diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 1143236874..b3b212cd5b 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,5 +1,5 @@ { - "baseBranches": ["develop", "develop-2.0.0"], + "baseBranches": ["develop", "develop-2.0.0", "develop-3.x.x"], "dependencyDashboard": true, "$schema": "https://docs.renovatebot.com/renovate-schema.json", 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..050ca8cd7f 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: @@ -29,14 +30,14 @@ jobs: script: | const pr = context.payload.pull_request; const body = pr.body || ''; - + // List of users to skip description validation // This should be automations where we don't care that much about the description format const skipUsersPrefixes = [ 'unity-renovate', 'svc-' ]; - + // If PR author is in the skip list, exit early const author = pr.user.login; console.log(`PR author: ${author}`); @@ -49,7 +50,7 @@ jobs: const requiredSections = [ { 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.' + description: 'PR description must include a "## Backports" section. Please add this section and provide information about this PR backport to develop, develop-2.0.0 or develop-3.x.x branch respectively or explain why backport is not needed.' }, { header: '## Testing & QA', diff --git a/.github/workflows/pr-supervisor.yaml b/.github/workflows/pr-supervisor.yaml index ba8da21e93..0583d1b101 100644 --- a/.github/workflows/pr-supervisor.yaml +++ b/.github/workflows/pr-supervisor.yaml @@ -2,7 +2,7 @@ # 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. +# This job will be required in branch protection rules for develop, develop-2.0.0, develop-3.x.x, 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. 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 @@ -26,32 +27,32 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v6 - + - name: Wait and Verify Yamato Job Status env: GH_TOKEN: ${{ secrets.GH_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | set -e - - + + MAX_ATTEMPTS=$((12*60)) INTERVAL=60 - + sleep $INTERVAL 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") ]') - + 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 - + if [[ "$failed" -gt 0 ]]; then echo "A check has failed! Failing fast." exit 1 @@ -61,6 +62,6 @@ jobs: echo "All non-supervisor checks are completed!" exit 0 fi - + sleep $INTERVAL - done \ No newline at end of file + done 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/.yamato/_triggers.yml b/.yamato/_triggers.yml index 8cdf8445ce..6f2da59265 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.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 @@ -58,6 +58,7 @@ pr_minimal_required_checks: (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,13 +76,13 @@ 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) + # Run package EditMode and Playmode package tests on trunk and an older supported editor (6000.3) - .yamato/package-tests.yml#package_test_-_ngo_{{ pinnedTrunk }}_mac - - .yamato/package-tests.yml#package_test_-_ngo_6000.0_win + - .yamato/package-tests.yml#package_test_-_ngo_6000.3_win - # Run testproject EditMode and Playmode project tests on trunk and an older supported editor (6000.0) + # Run testproject EditMode and Playmode project tests on trunk and an older supported editor (6000.3) - .yamato/project-tests.yml#test_testproject_win_{{ pinnedTrunk }} - - .yamato/project-tests.yml#test_testproject_mac_6000.0 + - .yamato/project-tests.yml#test_testproject_mac_6000.3 # 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 @@ -94,6 +95,7 @@ pr_code_changes_checks: (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 [ diff --git a/.yamato/project.metafile b/.yamato/project.metafile index 871ff18710..a0aff72c8f 100644 --- a/.yamato/project.metafile +++ b/.yamato/project.metafile @@ -176,14 +176,13 @@ validation_editors: default: - 6000.3 all: - - 6000.0 - 6000.3 - 6000.4 - 6000.5 - trunk - a4ce83e807ca9aff8394d1cc07341168dc49df03 minimal: - - 6000.0 + - 6000.3 pinnedTrunk: a4ce83e807ca9aff8394d1cc07341168dc49df03 diff --git a/Examples/CharacterControllerMovingBodies/Assets/Scripts/ExtendedNetworkManager.cs b/Examples/CharacterControllerMovingBodies/Assets/Scripts/ExtendedNetworkManager.cs index 2c291bbe89..d2d9b29083 100644 --- a/Examples/CharacterControllerMovingBodies/Assets/Scripts/ExtendedNetworkManager.cs +++ b/Examples/CharacterControllerMovingBodies/Assets/Scripts/ExtendedNetworkManager.cs @@ -10,7 +10,7 @@ using SessionState = Unity.Services.Multiplayer.SessionState; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/CharacterControllerMovingBodies/Assets/Scripts/MoverScriptNoRigidbody.cs b/Examples/CharacterControllerMovingBodies/Assets/Scripts/MoverScriptNoRigidbody.cs index 13423f4629..c938e1587b 100644 --- a/Examples/CharacterControllerMovingBodies/Assets/Scripts/MoverScriptNoRigidbody.cs +++ b/Examples/CharacterControllerMovingBodies/Assets/Scripts/MoverScriptNoRigidbody.cs @@ -2,7 +2,7 @@ using Unity.Netcode.Components; using Unity.Netcode; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/CharacterControllerMovingBodies/Assets/Scripts/PlayerBallMotion.cs b/Examples/CharacterControllerMovingBodies/Assets/Scripts/PlayerBallMotion.cs index 7e525d6c33..9696d62f56 100644 --- a/Examples/CharacterControllerMovingBodies/Assets/Scripts/PlayerBallMotion.cs +++ b/Examples/CharacterControllerMovingBodies/Assets/Scripts/PlayerBallMotion.cs @@ -5,7 +5,7 @@ #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// @@ -17,7 +17,7 @@ public class PlayerBallMotionEditor : NetworkTransformEditor { private SerializedProperty m_RotationAxis; private SerializedProperty m_RotationSpeed; - + public override void OnEnable() { diff --git a/Examples/CharacterControllerMovingBodies/Assets/Scripts/RotatingBodyLogic.cs b/Examples/CharacterControllerMovingBodies/Assets/Scripts/RotatingBodyLogic.cs index eaa32a77d6..84977b59a4 100644 --- a/Examples/CharacterControllerMovingBodies/Assets/Scripts/RotatingBodyLogic.cs +++ b/Examples/CharacterControllerMovingBodies/Assets/Scripts/RotatingBodyLogic.cs @@ -3,7 +3,7 @@ using Unity.Netcode.Components; using UnityEngine; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/CharacterControllerMovingBodies/Packages/manifest.json b/Examples/CharacterControllerMovingBodies/Packages/manifest.json index 0a8e3c4a4b..707ad3934f 100644 --- a/Examples/CharacterControllerMovingBodies/Packages/manifest.json +++ b/Examples/CharacterControllerMovingBodies/Packages/manifest.json @@ -10,7 +10,7 @@ "com.unity.ide.rider": "3.0.38", "com.unity.ide.visualstudio": "2.0.25", "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.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-3.x.x", "com.unity.purchasing": "4.12.2", "com.unity.services.multiplayer": "1.2.0", "com.unity.test-framework": "1.6.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/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs index 6da9441570..6893bf3790 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/MoverScriptNoRigidbody.cs @@ -7,7 +7,7 @@ #region MoverScriptNoRigidbody Custom Editor #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs index 172d819c27..2edccff2e6 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/NetworkManagerBootstrapper.cs @@ -21,7 +21,7 @@ #region NetworkManagerBootstrapperEditor #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/PlayerBallMotion.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/PlayerBallMotion.cs index 7e525d6c33..9696d62f56 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/PlayerBallMotion.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/PlayerBallMotion.cs @@ -5,7 +5,7 @@ #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// @@ -17,7 +17,7 @@ public class PlayerBallMotionEditor : NetworkTransformEditor { private SerializedProperty m_RotationAxis; private SerializedProperty m_RotationSpeed; - + public override void OnEnable() { diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/RotatingBodyLogic.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/RotatingBodyLogic.cs index eaa32a77d6..84977b59a4 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/RotatingBodyLogic.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/RotatingBodyLogic.cs @@ -3,7 +3,7 @@ using Unity.Netcode.Components; using UnityEngine; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs index 256122618e..fbc0e71a62 100644 --- a/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs +++ b/Examples/OverridingScenesAndPrefabs/Assets/Scripts/SceneBootstrapLoader.cs @@ -6,7 +6,7 @@ using UnityEngine; using UnityEngine.SceneManagement; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// @@ -224,7 +224,7 @@ private void OnSessionOwnerPromoted(ulong sessionOwnerPromoted) if (sessionOwnerPromoted == m_NetworkManager.LocalClientId) { // When we set the client synchronization mode to additive, the session owner will include this setting - // setting when synchronizing a newly joining client and the client will use any already loaded scenes + // setting when synchronizing a newly joining client and the client will use any already loaded scenes // that the session owner determines should be synchronized. If a scene that is being synchronized is not // yet loaded, then the client will load that scene. m_NetworkManager.SceneManager.SetClientSynchronizationMode(LoadSceneMode.Additive); diff --git a/Examples/OverridingScenesAndPrefabs/Packages/manifest.json b/Examples/OverridingScenesAndPrefabs/Packages/manifest.json index 0a8e3c4a4b..707ad3934f 100644 --- a/Examples/OverridingScenesAndPrefabs/Packages/manifest.json +++ b/Examples/OverridingScenesAndPrefabs/Packages/manifest.json @@ -10,7 +10,7 @@ "com.unity.ide.rider": "3.0.38", "com.unity.ide.visualstudio": "2.0.25", "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.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-3.x.x", "com.unity.purchasing": "4.12.2", "com.unity.services.multiplayer": "1.2.0", "com.unity.test-framework": "1.6.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/PingTool/Assets/Scripts/ExtendedNetworkManager.cs b/Examples/PingTool/Assets/Scripts/ExtendedNetworkManager.cs index 2c291bbe89..d2d9b29083 100644 --- a/Examples/PingTool/Assets/Scripts/ExtendedNetworkManager.cs +++ b/Examples/PingTool/Assets/Scripts/ExtendedNetworkManager.cs @@ -10,7 +10,7 @@ using SessionState = Unity.Services.Multiplayer.SessionState; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// diff --git a/Examples/PingTool/Assets/Scripts/PlayerMotion.cs b/Examples/PingTool/Assets/Scripts/PlayerMotion.cs index f746521c15..d8166c319c 100644 --- a/Examples/PingTool/Assets/Scripts/PlayerMotion.cs +++ b/Examples/PingTool/Assets/Scripts/PlayerMotion.cs @@ -2,7 +2,7 @@ using UnityEngine; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// /// The custom editor for the component. diff --git a/Examples/PingTool/Packages/manifest.json b/Examples/PingTool/Packages/manifest.json index 0c5e1bb258..4795e5c0ec 100644 --- a/Examples/PingTool/Packages/manifest.json +++ b/Examples/PingTool/Packages/manifest.json @@ -12,7 +12,7 @@ "com.unity.multiplayer.center": "1.0.0", "com.unity.multiplayer.playmode": "1.6.1", "com.unity.multiplayer.tools": "2.2.6", - "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.netcode.gameobjects": "https://github.com/Unity-Technologies/com.unity.netcode.gameobjects.git?path=com.unity.netcode.gameobjects#develop-3.x.x", "com.unity.purchasing": "4.12.2", "com.unity.services.multiplayer": "1.2.0", "com.unity.test-framework": "1.6.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/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 9d1075d0b3..38c6f59a4a 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -13,6 +13,11 @@ Additional documentation and release notes are available at [Multiplayer Documen ### Changed +- All editor assembly definitions are renamed with `Unity.Netcode.GameObjects.x` variants + - `Unity.Netcode.Editor` → `Unity.Netcode.GameObjects.Editor` + - `Unity.Netcode.Editor.CodeGen` → `Unity.Netcode.GameObjects.Editor.CodeGen` + - `Unity.Netcode.Editor.PackageChecker` → `Unity.Netcode.GameObjects.Editor.PackageChecker` + - `Unity.Netcode.Editor.Tests` → `Unity.Netcode.GameObjects.Editor.Tests` ### Deprecated diff --git a/com.unity.netcode.gameobjects/Documentation~/learn/distributed-authority-quick-start.md b/com.unity.netcode.gameobjects/Documentation~/learn/distributed-authority-quick-start.md index 9b292a4771..897d7e30e2 100644 --- a/com.unity.netcode.gameobjects/Documentation~/learn/distributed-authority-quick-start.md +++ b/com.unity.netcode.gameobjects/Documentation~/learn/distributed-authority-quick-start.md @@ -164,7 +164,7 @@ public class ConnectionManager : MonoBehaviour using Unity.Netcode.Components; using UnityEngine; #if UNITY_EDITOR -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEditor; /// /// The custom editor for the component. diff --git a/com.unity.netcode.gameobjects/Editor/Analytics/AnalyticsHandler.cs b/com.unity.netcode.gameobjects/Editor/Analytics/AnalyticsHandler.cs index b366e225eb..6df5c2d822 100644 --- a/com.unity.netcode.gameobjects/Editor/Analytics/AnalyticsHandler.cs +++ b/com.unity.netcode.gameobjects/Editor/Analytics/AnalyticsHandler.cs @@ -2,7 +2,7 @@ using System; using UnityEngine.Analytics; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { internal class AnalyticsHandler : IAnalytic where T : IAnalytic.IData { diff --git a/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs b/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs index 0a18028c84..b1c4e69698 100644 --- a/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs +++ b/com.unity.netcode.gameobjects/Editor/Analytics/NetcodeAnalytics.cs @@ -4,7 +4,7 @@ using UnityEngine; using UnityEngine.Analytics; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// Used to collection network session configuration information diff --git a/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs b/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs index 9ba7e46142..cd1ca3b1de 100644 --- a/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs +++ b/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalytics.cs @@ -4,7 +4,7 @@ using UnityEngine; using UnityEngine.Analytics; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { [Serializable] internal struct NetworkManagerAnalytics : IAnalytic.IData, IEquatable diff --git a/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalyticsHandler.cs b/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalyticsHandler.cs index 7866df9621..18f9bec50f 100644 --- a/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalyticsHandler.cs +++ b/com.unity.netcode.gameobjects/Editor/Analytics/NetworkManagerAnalyticsHandler.cs @@ -1,7 +1,7 @@ #if UNITY_EDITOR using UnityEngine.Analytics; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { [AnalyticInfo("NGO_NetworkManager", "unity.netcode", 5, 100, 1000)] internal class NetworkManagerAnalyticsHandler : AnalyticsHandler diff --git a/com.unity.netcode.gameobjects/Editor/AssemblyInfo.cs b/com.unity.netcode.gameobjects/Editor/AssemblyInfo.cs index 0f4e7e2b1d..fce6c4572d 100644 --- a/com.unity.netcode.gameobjects/Editor/AssemblyInfo.cs +++ b/com.unity.netcode.gameobjects/Editor/AssemblyInfo.cs @@ -2,7 +2,7 @@ #if UNITY_INCLUDE_TESTS #if UNITY_EDITOR -[assembly: InternalsVisibleTo("Unity.Netcode.Editor.Tests")] +[assembly: InternalsVisibleTo("Unity.Netcode.GameObjects.Editor.Tests")] [assembly: InternalsVisibleTo("TestProject.Runtime.Tests")] #endif // UNITY_EDITOR #endif // UNITY_INCLUDE_TESTS diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs index 8d29e112f0..2b3b7d99f1 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs @@ -12,7 +12,7 @@ using UnityEngine; using Object = System.Object; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal static class CodeGenHelpers { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkMessageILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkMessageILPP.cs index d74b737bde..03bea544bb 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkMessageILPP.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkMessageILPP.cs @@ -11,7 +11,7 @@ using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostProcessor; using MethodAttributes = Mono.Cecil.MethodAttributes; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal sealed class INetworkMessageILPP : ILPPInterface { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkSerializableILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkSerializableILPP.cs index abfc9a26ae..c4123d5b88 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkSerializableILPP.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/INetworkSerializableILPP.cs @@ -8,7 +8,7 @@ using Unity.CompilationPipeline.Common.ILPostProcessing; using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostProcessor; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal sealed class INetworkSerializableILPP : ILPPInterface { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs index 04a72d7c9e..b1852baf44 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs @@ -16,7 +16,7 @@ using MethodAttributes = Mono.Cecil.MethodAttributes; using ParameterAttributes = Mono.Cecil.ParameterAttributes; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal sealed class NetworkBehaviourILPP : ILPPInterface { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs index 4adbbfd8ed..369fb04097 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorAssemblyResolver.cs @@ -6,7 +6,7 @@ using Mono.Cecil; using Unity.CompilationPipeline.Common.ILPostProcessing; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal class PostProcessorAssemblyResolver : IAssemblyResolver { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs index f96ba3396c..7c904750f5 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporter.cs @@ -2,7 +2,7 @@ using System.Reflection; using Mono.Cecil; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal class PostProcessorReflectionImporter : DefaultReflectionImporter { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs index 81f80f04ed..1f7e41c3c8 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/PostProcessorReflectionImporterProvider.cs @@ -1,6 +1,6 @@ using Mono.Cecil; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal class PostProcessorReflectionImporterProvider : IReflectionImporterProvider { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs b/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs index 57295be52e..941e492c13 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/RuntimeAccessModifiersILPP.cs @@ -7,7 +7,7 @@ using Unity.CompilationPipeline.Common.ILPostProcessing; using ILPPInterface = Unity.CompilationPipeline.Common.ILPostProcessing.ILPostProcessor; -namespace Unity.Netcode.Editor.CodeGen +namespace Unity.Netcode.GameObjects.Editor.CodeGen { internal sealed class RuntimeAccessModifiersILPP : ILPPInterface { diff --git a/com.unity.netcode.gameobjects/Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef b/com.unity.netcode.gameobjects/Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef index 1accd5e5d7..1b93c60458 100644 --- a/com.unity.netcode.gameobjects/Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef +++ b/com.unity.netcode.gameobjects/Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef @@ -1,6 +1,6 @@ { - "name": "Unity.Netcode.Editor.CodeGen", - "rootNamespace": "Unity.Netcode.Editor.CodeGen", + "name": "Unity.Netcode.GameObjects.Editor.CodeGen", + "rootNamespace": "Unity.Netcode.GameObjects.Editor.CodeGen", "references": [ "Unity.Netcode.Runtime", "Unity.Collections" @@ -32,4 +32,4 @@ } ], "noEngineReferences": false -} \ No newline at end of file +} diff --git a/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsProjectSettings.cs b/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsProjectSettings.cs index 48ddd77fde..05f83876bd 100644 --- a/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsProjectSettings.cs +++ b/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsProjectSettings.cs @@ -1,7 +1,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor.Configuration +namespace Unity.Netcode.GameObjects.Editor.Configuration { /// /// A of type . diff --git a/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsSettings.cs b/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsSettings.cs index 70dfc02021..6a43d62e7e 100644 --- a/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsSettings.cs +++ b/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeForGameObjectsSettings.cs @@ -1,6 +1,6 @@ using UnityEditor; -namespace Unity.Netcode.Editor.Configuration +namespace Unity.Netcode.GameObjects.Editor.Configuration { internal class NetcodeForGameObjectsEditorSettings { diff --git a/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeSettingsProvider.cs b/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeSettingsProvider.cs index 22ed67e48c..a8b521117c 100644 --- a/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeSettingsProvider.cs +++ b/com.unity.netcode.gameobjects/Editor/Configuration/NetcodeSettingsProvider.cs @@ -5,7 +5,7 @@ using Directory = UnityEngine.Windows.Directory; using File = UnityEngine.Windows.File; -namespace Unity.Netcode.Editor.Configuration +namespace Unity.Netcode.GameObjects.Editor.Configuration { internal static class NetcodeSettingsProvider { diff --git a/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabProcessor.cs b/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabProcessor.cs index f74530e60f..cab11b3be1 100644 --- a/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabProcessor.cs +++ b/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabProcessor.cs @@ -2,7 +2,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor.Configuration +namespace Unity.Netcode.GameObjects.Editor.Configuration { /// /// Updates the default instance when prefabs are updated (created, moved, deleted) in the project. diff --git a/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabsEditor.cs b/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabsEditor.cs index 68113ca32f..6b1128c829 100644 --- a/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabsEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/Configuration/NetworkPrefabsEditor.cs @@ -2,7 +2,7 @@ using UnityEditorInternal; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// The custom editor for the . diff --git a/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs b/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs index 2311da1477..98193cc631 100644 --- a/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/HiddenScriptEditor.cs @@ -5,7 +5,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// Internal use. Hides the script field for the given component. diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources.meta b/com.unity.netcode.gameobjects/Editor/Icons.meta similarity index 77% rename from testproject/Legacy/MultiprocessRuntime/readme-ressources.meta rename to com.unity.netcode.gameobjects/Editor/Icons.meta index 00a2ce978f..47f083a506 100644 --- a/testproject/Legacy/MultiprocessRuntime/readme-ressources.meta +++ b/com.unity.netcode.gameobjects/Editor/Icons.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5d13190bb106b4188934d5576df7e777 +guid: 09ac49ca8d1df6347814a8a4760eb02c folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/com.unity.netcode.gameobjects/Editor/Icons/NOBridgeIcon.png b/com.unity.netcode.gameobjects/Editor/Icons/NOBridgeIcon.png new file mode 100644 index 0000000000..c94cfb2e9b Binary files /dev/null and b/com.unity.netcode.gameobjects/Editor/Icons/NOBridgeIcon.png differ diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Building-Player.jpg.meta b/com.unity.netcode.gameobjects/Editor/Icons/NOBridgeIcon.png.meta similarity index 51% rename from testproject/Legacy/MultiprocessRuntime/readme-ressources/Building-Player.jpg.meta rename to com.unity.netcode.gameobjects/Editor/Icons/NOBridgeIcon.png.meta index e675f9e356..2a11d94057 100644 --- a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Building-Player.jpg.meta +++ b/com.unity.netcode.gameobjects/Editor/Icons/NOBridgeIcon.png.meta @@ -1,9 +1,9 @@ fileFormatVersion: 2 -guid: 4d67ff4fda6ec4805b2fd16af441aa47 +guid: 04d779b185ebc8d488b5d25eeb21c611 TextureImporter: internalIDToNameTable: [] externalObjects: {} - serializedVersion: 11 + serializedVersion: 13 mipmaps: mipMapMode: 0 enableMipMap: 1 @@ -20,10 +20,12 @@ TextureImporter: externalNormalMap: 0 heightScale: 0.25 normalMapFilter: 0 + flipGreenChannel: 0 isReadable: 0 streamingMipmaps: 0 streamingMipmapsPriority: 0 vTOnly: 0 + ignoreMipmapLimit: 0 grayScaleToAlpha: 0 generateCubemap: 6 cubemapConvolution: 0 @@ -50,7 +52,7 @@ TextureImporter: spriteBorder: {x: 0, y: 0, z: 0, w: 0} spriteGenerateFallbackPhysicsShape: 1 alphaUsage: 1 - alphaIsTransparency: 0 + alphaIsTransparency: 1 spriteTessellationDetail: -1 textureType: 0 textureShape: 1 @@ -62,10 +64,12 @@ TextureImporter: textureFormatSet: 0 ignorePngGamma: 0 applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 platformSettings: - - serializedVersion: 3 + - serializedVersion: 4 buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 + maxTextureSize: 64 resizeAlgorithm: 0 textureFormat: -1 textureCompression: 1 @@ -73,12 +77,66 @@ TextureImporter: crunchedCompression: 0 allowsAlphaSplitting: 0 overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 8192 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: iOS + maxTextureSize: 8192 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Android + maxTextureSize: 8192 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 8192 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 androidETC2FallbackOverride: 0 forceMaximumCompressionQuality_BC6H_BC7: 0 spriteSheet: serializedVersion: 2 sprites: [] outline: [] + customData: physicsShape: [] bones: [] spriteID: @@ -88,9 +146,11 @@ TextureImporter: edges: [] weights: [] secondaryTextures: [] - spritePackingTag: + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 userData: assetBundleName: assetBundleVariant: diff --git a/com.unity.netcode.gameobjects/Editor/NetcodeEditorBase.cs b/com.unity.netcode.gameobjects/Editor/NetcodeEditorBase.cs index b61a77e6b6..fb10ebd25a 100644 --- a/com.unity.netcode.gameobjects/Editor/NetcodeEditorBase.cs +++ b/com.unity.netcode.gameobjects/Editor/NetcodeEditorBase.cs @@ -2,7 +2,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// The base Netcode Editor helper class to display derived based components
diff --git a/com.unity.netcode.gameobjects/Editor/NetworkAnimatorParameterEntryDrawer.cs b/com.unity.netcode.gameobjects/Editor/NetworkAnimatorParameterEntryDrawer.cs index 9060b8993c..7fbf7789dd 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkAnimatorParameterEntryDrawer.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkAnimatorParameterEntryDrawer.cs @@ -4,7 +4,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { [CustomPropertyDrawer(typeof(NetworkAnimator.AnimatorParametersListContainer))] internal class NetworkAnimatorParameterEntryDrawer : PropertyDrawer diff --git a/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs index 1312ff69e6..01e7425a6d 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkBehaviourEditor.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; using System.Reflection; -using Unity.Netcode.Editor.Configuration; +using Unity.Netcode.GameObjects.Editor.Configuration; using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// The for @@ -326,14 +326,8 @@ private void OnEnable() /// /// 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", true)] + public static Transform GetRootParentTransform(Transform transform) => transform.root; /// /// Used to determine if a GameObject has one or more NetworkBehaviours but @@ -358,7 +352,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/NetworkManagerEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs index a4e339f558..a140415e87 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkManagerEditor.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Unity.Netcode.Editor.Configuration; +using Unity.Netcode.GameObjects.Editor.Configuration; using Unity.Netcode.Logging; using UnityEditor; using UnityEngine; @@ -10,7 +10,7 @@ using UnityEngine.Assemblies; #endif -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// This handles the translation between the and diff --git a/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs b/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs index 5c7e554baf..abf238c45a 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkManagerHelper.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; using System.Linq; -using Unity.Netcode.Editor.Configuration; +using Unity.Netcode.GameObjects.Editor.Configuration; using Unity.Netcode.Logging; using UnityEditor; using UnityEngine; using UnityEngine.SceneManagement; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { #if UNITY_EDITOR /// diff --git a/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs index 04e0d1f698..924e519f27 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs @@ -5,7 +5,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// The for @@ -32,6 +32,9 @@ private void Initialize() m_Initialized = true; m_NetworkObject = (NetworkObject)target; +#if UNIFIED_NETCODE + m_NetworkObject.UnifiedValidation(); +#endif } /// diff --git a/com.unity.netcode.gameobjects/Editor/NetworkRigidbodyBaseEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkRigidbodyBaseEditor.cs index 40c15fc4fc..46bb7c4f6d 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkRigidbodyBaseEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkRigidbodyBaseEditor.cs @@ -2,7 +2,7 @@ using Unity.Netcode.Components; using UnityEditor; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { [CustomEditor(typeof(NetworkRigidbodyBase), true)] [CanEditMultipleObjects] diff --git a/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs b/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs index 31f3314bea..06823d94e2 100644 --- a/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs +++ b/com.unity.netcode.gameobjects/Editor/NetworkTransformEditor.cs @@ -2,7 +2,7 @@ using UnityEditor; using UnityEngine; -namespace Unity.Netcode.Editor +namespace Unity.Netcode.GameObjects.Editor { /// /// The for diff --git a/com.unity.netcode.gameobjects/Editor/PackageChecker/UTPAdapterChecker.cs b/com.unity.netcode.gameobjects/Editor/PackageChecker/UTPAdapterChecker.cs index 0d109a0115..8f6ffd67a6 100644 --- a/com.unity.netcode.gameobjects/Editor/PackageChecker/UTPAdapterChecker.cs +++ b/com.unity.netcode.gameobjects/Editor/PackageChecker/UTPAdapterChecker.cs @@ -5,7 +5,7 @@ using UnityEditor.PackageManager; using UnityEditor.PackageManager.Requests; -namespace Unity.Netcode.Editor.PackageChecker +namespace Unity.Netcode.GameObjects.Editor.PackageChecker { [InitializeOnLoad] internal class UTPAdapterChecker diff --git a/com.unity.netcode.gameobjects/Editor/PackageChecker/Unity.Netcode.PackageChecker.Editor.asmdef b/com.unity.netcode.gameobjects/Editor/PackageChecker/Unity.Netcode.PackageChecker.Editor.asmdef index 9599c27b6c..b4a04f0564 100644 --- a/com.unity.netcode.gameobjects/Editor/PackageChecker/Unity.Netcode.PackageChecker.Editor.asmdef +++ b/com.unity.netcode.gameobjects/Editor/PackageChecker/Unity.Netcode.PackageChecker.Editor.asmdef @@ -1,6 +1,6 @@ { - "name": "Unity.Netcode.PackageChecker.Editor", - "rootNamespace": "Unity.Netcode.Editor.PackageChecker", + "name": "Unity.Netcode.GameObjects.PackageChecker.Editor", + "rootNamespace": "Unity.Netcode.GameObjects.Editor.PackageChecker", "references": [], "includePlatforms": [ "Editor" @@ -19,4 +19,4 @@ } ], "noEngineReferences": false -} \ No newline at end of file +} diff --git a/com.unity.netcode.gameobjects/Editor/Unity.Netcode.Editor.asmdef b/com.unity.netcode.gameobjects/Editor/Unity.Netcode.Editor.asmdef index 926f85b604..e4d210bd4d 100644 --- a/com.unity.netcode.gameobjects/Editor/Unity.Netcode.Editor.asmdef +++ b/com.unity.netcode.gameobjects/Editor/Unity.Netcode.Editor.asmdef @@ -1,13 +1,14 @@ { - "name": "Unity.Netcode.Editor", - "rootNamespace": "Unity.Netcode.Editor", + "name": "Unity.Netcode.GameObjects.Editor", + "rootNamespace": "Unity.Netcode.GameObjects.Editor", "references": [ "Unity.Netcode.Runtime", "Unity.Netcode.Components", "Unity.Services.Relay", "Unity.Networking.Transport", "Unity.Services.Core", - "Unity.Services.Authentication" + "Unity.Services.Authentication", + "Unity.NetCode" ], "includePlatforms": [ "Editor" @@ -43,6 +44,16 @@ "name": "com.unity.services.multiplayer", "expression": "0.2.0", "define": "MULTIPLAYER_SERVICES_SDK_INSTALLED" + }, + { + "name": "com.unity.netcode", + "expression": "1.10.1", + "define": "UNIFIED_NETCODE" + }, + { + "name": "com.unity.multiplayer.playmode", + "expression": "0.1.0", + "define": "UNITY_MULTIPLAYER_PLAYMODE" } ], "noEngineReferences": false diff --git a/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs b/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs index 59d36853a3..221ae1431f 100644 --- a/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs +++ b/com.unity.netcode.gameobjects/Runtime/AssemblyInfo.cs @@ -1,8 +1,8 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Unity.Netcode.Components")] #if UNITY_EDITOR -[assembly: InternalsVisibleTo("Unity.Netcode.Editor")] -[assembly: InternalsVisibleTo("Unity.Netcode.Editor.CodeGen")] +[assembly: InternalsVisibleTo("Unity.Netcode.GameObjects.Editor")] +[assembly: InternalsVisibleTo("Unity.Netcode.GameObjects.Editor.CodeGen")] #endif // UNITY_EDITOR #if COM_UNITY_NETCODE_ADAPTER_UTP @@ -14,14 +14,14 @@ [assembly: InternalsVisibleTo("Unity.Netcode.TestHelpers.Runtime")] [assembly: InternalsVisibleTo("TestProject.Runtime.Tests")] #if UNITY_EDITOR -[assembly: InternalsVisibleTo("Unity.Netcode.Editor.Tests")] +[assembly: InternalsVisibleTo("Unity.Netcode.GameObjects.Editor.Tests")] [assembly: InternalsVisibleTo("TestProject.Editor.Tests")] #endif // UNITY_EDITOR #if MULTIPLAYER_TOOLS [assembly: InternalsVisibleTo("Unity.Multiplayer.Tools.GameObjects.Tests")] [assembly: InternalsVisibleTo("TestProject.ToolsIntegration.RuntimeTests")] -[assembly: InternalsVisibleTo("TestProject.Netcode.GameObjejct.Runtime.Tests")] +[assembly: InternalsVisibleTo("TestProject.Netcode.GameObject.Runtime.Tests")] #endif // MULTIPLAYER_TOOLS #endif // UNITY_INCLUDE_TESTS // Should always be visible when multiplayer tools package is installed. diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs new file mode 100644 index 0000000000..fcd585d9a9 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs @@ -0,0 +1,72 @@ +#if UNIFIED_NETCODE +using Unity.NetCode; +#if UNITY_EDITOR +using UnityEditor; +#endif +using UnityEngine; + +namespace Unity.Netcode +{ + /// + /// TODO-UNIFIED: Needs further peer review and exploring alternate ways of handling this. + /// This is a component that is added to the root of all N4E-spawned hybrid prefab instances. It is used to link + /// the N4E-spawned hybrid prefab instances to the incoming + /// specific to the N4E-spawned hybrid prefab instance that has the matching . + /// + public partial class NetworkObjectBridge : GhostBehaviour + { +#if UNITY_EDITOR + [HideInInspector] + [SerializeField] + private bool m_Sorted = false; + private void OnValidate() + { + // TODO-UNIFIED: GhostAdapter must be above all GhostBehaviours in order to assure the GhostAdapter is initialized before any GhostBehaviour. + // This auto-sorting is required because the GhostBehaviours rely on the GhostAdapter.Awake being invoked before any GhostBehaviour.Awake. + if (!m_Sorted && !EditorApplication.isPlaying) + { + while (UnityEditorInternal.ComponentUtility.MoveComponentUp(this)) + { + // Keep moving until it can't go higher + } + var ghostAdapter = gameObject.GetComponent(); + // Now move the GhostAdapter to the top so it is above NetworkObjectBridge + while (ghostAdapter != null && UnityEditorInternal.ComponentUtility.MoveComponentUp(ghostAdapter)) + { + // Keep moving until it can't go higher + } + + m_Sorted = true; + } + } +#endif + + /// + /// This is used to link data to + /// N4E-spawned hybrid prefab instances. + /// + internal GhostField NetworkObjectId = new GhostField(); + public void SetNetworkObjectId(ulong networkObjectId) + { + NetworkObjectId.PresetValue(networkObjectId); + NetworkObjectId.Value = networkObjectId; + } + + /// + /// Currently, NGO provides the parenting event handling via . + /// Once can provide a form of event notification that + /// the value has changed, we can then invert this flow such that the change in the parent value + /// drives the event. + /// + /// We use NGO scale, delivered via ParentSyncMessage, that is applied to this + /// instance's entity's PostTransformMatrix. + internal void HybridParentUpdate(Vector3 scale) + { + var current = Ghost.GetPositionAndRotation(); + //Debug.Log($"---- Current LT: {current.Position} | {current.Rotation.eulerAngles}"); + //Debug.Log($"---- New LT: {transform.localPosition} | {transform.localRotation}"); + Ghost.ApplyPostTransformMatrixScale(scale); + } + } +} +#endif diff --git a/testproject/Legacy/MultiprocessRuntime/BaseMultiprocessTests.cs.meta b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs.meta similarity index 61% rename from testproject/Legacy/MultiprocessRuntime/BaseMultiprocessTests.cs.meta rename to com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs.meta index 6b52bd9e90..0e4dd44b97 100644 --- a/testproject/Legacy/MultiprocessRuntime/BaseMultiprocessTests.cs.meta +++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/NetworkObjectBridge.cs.meta @@ -1,11 +1,11 @@ fileFormatVersion: 2 -guid: f77e60aa394b9419784b6c46618fb553 +guid: 510c5bb08d2f5724e85aa4fb66a8a4ff MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: 04d779b185ebc8d488b5d25eeb21c611, type: 3} userData: assetBundleName: assetBundleVariant: diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs new file mode 100644 index 0000000000..f1a8d7dc3c --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs @@ -0,0 +1,95 @@ +#if UNIFIED_NETCODE +using System; +using Unity.Entities; +using Unity.NetCode; +using UnityEngine; + +namespace Unity.Netcode +{ + /// + /// TODO-UNIFIED: Needs furthery review and proper error messaging using the new logging context. + /// Handles the bootstrap process for both client and server in unified mode. This is used to create the world and set it on the + /// NetworkManager during initialization. + /// + internal class UnifiedBootstrap : ClientServerBootstrap + { + public static UnifiedBootstrap Instance { get; private set; } + public static Action OnInitialized; + public static ushort Port = 7979; + public static NetworkManager CurrentNetworkManagerForInitialization; + + public static World LastCreatedWorld { get; private set; } + + private static int s_WorldCounter = 0; + + public override bool Initialize(string defaultWorldName) + { + var networkManager = CurrentNetworkManagerForInitialization; + if (networkManager == NetworkManager.Singleton) + { + Instance = this; + } + + AutoConnectPort = Port; + if (base.Initialize(defaultWorldName)) + { + Debug.LogError($"[{nameof(UnifiedBootstrap)}] Auto-bootstrap is enabled!!! This will break the POC!"); + return true; + } + + if (networkManager != null) + { + Debug.Log($"Starting a world for {(networkManager.IsServer ? "Host" : "Client")}"); + s_WorldCounter++; + LastCreatedWorld = networkManager.IsServer ? CreateSingleWorldHost($"HostSingleWorld-{s_WorldCounter}") + : CreateClientWorld($"ClientWorld-{s_WorldCounter}"); + + if (LastCreatedWorld == null) + { + s_WorldCounter--; + Debug.LogError($"[{nameof(UnifiedBootstrap)}] World is null!"); + return false; + } + + if (!LastCreatedWorld.IsCreated) + { + s_WorldCounter--; + Debug.LogError($"[{nameof(UnifiedBootstrap)}] World was not created!"); + return false; + } + + if (networkManager.LogLevel <= LogLevel.Developer) + { + NetworkLog.LogInfo($"[{nameof(UnifiedBootstrap)}] Created world: {LastCreatedWorld.Name} / {LastCreatedWorld.SequenceNumber}"); + } + + networkManager.NetcodeWorld = (NetcodeWorld)LastCreatedWorld; +#if UNIFIED_NGO_REGISTERS_PREFABS + if (networkManager.NetworkConfig.Prefabs.HasPendingGhostPrefabs) + { + if (networkManager.LogLevel <= LogLevel.Developer) + { + NetworkLog.LogInfo($"[{nameof(UnifiedBootstrap)}] Registering hybrid prefabs..."); + } + networkManager.NetworkConfig.Prefabs.RegisterGhostPrefabs(networkManager); + } +#endif + } + else + { + LastCreatedWorld = CreateLocalWorld("LocalWorld"); + } + + OnInitialized?.Invoke(); + + return true; + } + + ~UnifiedBootstrap() + { + LastCreatedWorld = null; + Instance = null; + } + } +} +#endif diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs.meta b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs.meta new file mode 100644 index 0000000000..a9a3d5ee88 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedBootstrap.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0671ce785ad022344a6721d1be9559ad \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs new file mode 100644 index 0000000000..e9b66ba877 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs @@ -0,0 +1,129 @@ +#if UNIFIED_NETCODE +using System.Collections.Generic; +using Unity.Collections; +using Unity.Entities; +using Unity.NetCode; +using UnityEngine; + +namespace Unity.Netcode.Components +{ + + public struct NetcodeConnection + { + internal World World; + internal Entity Entity; + public int NetworkId; + + public bool IsServer => World.IsServer(); + public void GoInGame() + { + World.EntityManager.AddComponentData(Entity, default(NetworkStreamInGame)); + } + public void SendMessage(T message) where T : unmanaged, IRpcCommand + { + var req = World.EntityManager.CreateEntity(); + World.EntityManager.AddComponentData(req, new SendRpcCommandRequest { TargetConnection = Entity }); + World.EntityManager.AddComponentData(req, message); + } + } + + internal partial class UnifiedUpdateConnections : SystemBase + { + private List m_TempConnections = new List(); + + private Dictionary m_NewConnections = new Dictionary(); + + protected override void OnUpdate() + { + var isServer = World.IsServer(); + var commandBuffer = new EntityCommandBuffer(Allocator.Temp); + foreach (var networkManager in Object.FindObjectsByType()) + { + foreach (var (networkId, connectionState, entity) in SystemAPI.Query().WithNone().WithEntityAccess()) + { + commandBuffer.RemoveComponent(entity); + m_TempConnections.Add(new NetcodeConnection + { + World = World, + Entity = entity, + NetworkId = networkId.Value + }); + } + + foreach (var con in m_TempConnections) + { + NetworkManager.OnNetCodeDisconnect?.Invoke(con); + } + + m_TempConnections.Clear(); + + // TODO: We should figure out how to associate the N4E NetworkId with the NGO ClientId + foreach (var (networkId, entity) in SystemAPI.Query().WithAll() + .WithNone().WithEntityAccess()) + { + if (!m_NewConnections.ContainsKey(networkId.Value)) + { + var newConnection = new NetcodeConnection + { World = World, Entity = entity, NetworkId = networkId.Value }; + m_NewConnections.Add(networkId.Value, newConnection); + } + } + + // If we have any pending connections + if (m_NewConnections.Count > 0) + { + foreach (var entry in m_NewConnections) + { + // Server: always connect + // Client: wait until we have synchronized before announcing we are ready to receive snapshots + if (networkManager.IsServer || (!networkManager.IsServer && networkManager.IsConnectedClient)) + { + // Set the connection in-game + commandBuffer.AddComponent(entry.Value.Entity); + commandBuffer.AddComponent(entry.Value.Entity, default(ConnectionState)); + NetworkManager.OnNetCodeConnect?.Invoke(entry.Value); + m_TempConnections.Add(entry.Value); + } + } + + // Remove any connections that have "gone in-game". + foreach (var connection in m_TempConnections) + { + m_NewConnections.Remove(connection.NetworkId); + } + } + + m_TempConnections.Clear(); + + // If the local NetworkManager is shutting down or no longer connected, then + // make sure we have disconnected all known connections. + if (networkManager.ShutdownInProgress || !networkManager.IsListening) + { + foreach (var (networkId, entity) in SystemAPI.Query().WithEntityAccess()) + { + commandBuffer.RemoveComponent(entity); + NetworkManager.OnNetCodeDisconnect?.Invoke(new NetcodeConnection + { World = World, Entity = entity, NetworkId = networkId.Value }); + } + } + } + commandBuffer.Playback(EntityManager); + } + + /// + /// Always disconnect all known connections when being destroyed. + /// + protected override void OnDestroy() + { + var commandBuffer = new EntityCommandBuffer(Allocator.Temp); + foreach (var (networkId, entity) in SystemAPI.Query().WithEntityAccess()) + { + commandBuffer.RemoveComponent(entity); + NetworkManager.OnNetCodeDisconnect?.Invoke(new NetcodeConnection { World = World, Entity = entity, NetworkId = networkId.Value }); + } + commandBuffer.Playback(EntityManager); + base.OnDestroy(); + } + } +} +#endif diff --git a/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs.meta b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs.meta new file mode 100644 index 0000000000..01feb655c4 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Components/Helpers/UnifiedUpdateConnections.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d5f2f5fd179c39f43b68ec502cdec9c4 diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs index 0d0de9afa8..ff0636c5b4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidBodyBase.cs @@ -20,6 +20,13 @@ public abstract class NetworkRigidbodyBase : NetworkBehaviour internal bool NetworkRigidbodyBaseExpanded; #endif + // TODO-UNIFIED: + // Provide an option to automatically remove the NetworkRigidbodyBase component at runtime if it is a hybrid prefab that is spawned since this + // component is primarily used for the Rigidbody interpolation and extrapolation features of NetworkTransform which are not relevant for a hybrid + // prefab that is spawned since it will be using N4E's built in interpolation and extrapolation features. This greatly improves performance on + // the client side. If using N4E prediction or distributed authority mode, then Rigibody and any component derived from this should always be used. + + /// /// When enabled, the associated will use the Rigidbody/Rigidbody2D to apply and synchronize changes in position, rotation, and /// allows for the use of Rigidbody interpolation/extrapolation. @@ -51,7 +58,6 @@ public abstract class NetworkRigidbodyBase : NetworkBehaviour private bool m_IsRigidbody2D = false; #endif - private NetworkManager m_LocalNetworkManager; // Used to cache the authority state of this Rigidbody during the last frame private bool m_IsAuthority; @@ -194,6 +200,11 @@ protected void Initialize(RigidbodyTypes rigidbodyType, NetworkTransform network #endif #if COM_UNITY_MODULES_PHYSICS && COM_UNITY_MODULES_PHYSICS2D +#if UNIFIED_NETCODE + // Used to keep track of the original kinematic state upon awake. + // (see OnDestroy below) + private bool m_OriginalKinematicState; +#endif /// /// Initializes the networked Rigidbody based on the /// passed in as a parameter. @@ -247,9 +258,31 @@ protected void Initialize(RigidbodyTypes rigidbodyType, NetworkTransform network if (AutoUpdateKinematicState) { +#if UNIFIED_NETCODE + // Keep track of the original kinematic state. (see OnDestroy) + m_OriginalKinematicState = IsKinematic(); +#endif SetIsKinematic(true); } } + +#if UNIFIED_NETCODE + public override void OnDestroy() + { + base.OnDestroy(); + // If the user has left this component on their prefab and this is a hybrid prefab, + // then we want to set the rigid body back to its original kinematic settings since + // we are automatically destroying these components at runtime when it is a hybrid + // prefab that is spawned. + if (NetworkObject && NetworkObject.HasGhost) + { + if (m_InternalRigidbody || m_InternalRigidbody2D) + { + SetIsKinematic(m_OriginalKinematicState); + } + } + } +#endif #endif internal Vector3 GetAdjustedPositionThreshold() { diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody.cs index 590fad77b7..ffd82ff5f4 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody.cs @@ -9,7 +9,10 @@ namespace Unity.Netcode.Components /// mode of the and disabling it on all peers but the authoritative one. /// [RequireComponent(typeof(NetworkTransform))] + // TODO-UNIFIED: We should not require this for unified and come up with a different way of handling the dependency +#if !UNIFIED_NETCODE [RequireComponent(typeof(Rigidbody))] +#endif [AddComponentMenu("Netcode/Network Rigidbody")] [HelpURL(HelpUrls.NetworkRigidbody)] public class NetworkRigidbody : NetworkRigidbodyBase diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody2D.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody2D.cs index dd84d52252..8912a2cff0 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody2D.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkRigidbody2D.cs @@ -9,7 +9,10 @@ namespace Unity.Netcode.Components /// mode of the rigidbody and disabling it on all peers but the authoritative one. /// [RequireComponent(typeof(NetworkTransform))] + // TODO-UNIFIED: We should not require this for unified and come up with a different way of handling the dependency +#if !UNIFIED_NETCODE [RequireComponent(typeof(Rigidbody2D))] +#endif [AddComponentMenu("Netcode/Network Rigidbody 2D")] [HelpURL(HelpUrls.NetworkRigidbody2D)] public class NetworkRigidbody2D : NetworkRigidbodyBase diff --git a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs index 3ca9093b34..4ae2b2f63f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs +++ b/com.unity.netcode.gameobjects/Runtime/Components/NetworkTransform.cs @@ -1793,6 +1793,17 @@ internal void RegisterRigidbody(NetworkRigidbodyBase networkRigidbody) m_UseRigidbodyForMotion = m_NetworkRigidbodyInternal.UseRigidBodyForMotion; } } + +#if UNIFIED_NETCODE + internal void UnregisterRigidbody() + { + if (m_NetworkRigidbodyInternal) + { + m_NetworkRigidbodyInternal = null; + m_UseRigidbodyForMotion = false; + } + } +#endif #endif #if DEBUG_NETWORKTRANSFORM || UNITY_INCLUDE_TESTS @@ -3634,6 +3645,15 @@ internal override void InternalOnNetworkPreSpawn(ref NetworkManager networkManag /// public override void OnNetworkSpawn() { +#if UNIFIED_NETCODE + // TODO-UNIFIED: + // Provide a notification to users that NetworkTransform component will be removed at runtime if it is a hybrid prefab that is spawned since + // it will be using N4E's built in interpolation and extrapolation features. + if (NetworkObject.HasGhost) + { + return; + } +#endif m_ParentedChildren.Clear(); Initialize(); @@ -3726,8 +3746,17 @@ private void ResetInterpolatedStateToCurrentAuthoritativeState() /// The internal initialization method to allow for internal API adjustments /// /// - private void InternalInitialization(bool isOwnershipChange = false) + internal virtual void InternalInitialization(bool isOwnershipChange = false) { +#if UNIFIED_NETCODE + // TODO-UNIFIED: + // Provide a notification to users that NetworkTransform component will be removed at runtime if it is a hybrid prefab that is spawned since + // it will be using N4E's built in interpolation and extrapolation features. + if (NetworkObject.HasGhost) + { + return; + } +#endif if (!IsSpawned) { return; diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs index c6f30d2835..25d75adf26 100644 --- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs @@ -57,6 +57,14 @@ public class NetworkPrefab /// public GameObject OverridingTargetPrefab; +#if UNIFIED_NETCODE + /// + /// Used to determine if this prefab needs to be registered + /// via the unified API. + /// + internal bool HasGhost { get; private set; } +#endif + /// /// Compares this NetworkPrefab with another to determine equality /// @@ -166,6 +174,11 @@ public bool Validate(int index = -1) return false; } +#if UNIFIED_NETCODE + // Mark this network prefab as having to be registered via the unified API + HasGhost = networkObject.HasGhost; +#endif + return true; } @@ -183,7 +196,6 @@ public bool Validate(int index = -1) return false; } - break; } case NetworkPrefabOverride.Prefab: diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs index 45d93ad9d7..97eabd16ab 100644 --- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs +++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs @@ -47,6 +47,11 @@ public class NetworkPrefabs [NonSerialized] private List m_Prefabs = new List(); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + [NonSerialized] + internal Dictionary PrefabTable = new Dictionary(); +#endif + [NonSerialized] private List m_RuntimeAddedPrefabs = new List(); @@ -57,12 +62,18 @@ 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. m_Prefabs.Add(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.TryAdd(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab); +#endif } } private void RemoveTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab) { m_Prefabs.Remove(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash); +#endif } /// @@ -95,6 +106,9 @@ public void Initialize(bool warnInvalid = true) { m_Prefabs.Clear(); NetworkPrefabsLists.RemoveAll(x => x == null); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.Clear(); +#endif foreach (var list in NetworkPrefabsLists) { list.OnAdd += AddTriggeredByNetworkPrefabList; @@ -127,10 +141,16 @@ public void Initialize(bool warnInvalid = true) if (AddPrefabRegistration(networkPrefab)) { m_Prefabs.Add(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.TryAdd(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab); +#endif } else { removeList?.Add(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash); +#endif } } @@ -139,10 +159,16 @@ public void Initialize(bool warnInvalid = true) if (AddPrefabRegistration(networkPrefab)) { m_Prefabs.Add(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.TryAdd(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab); +#endif } else { removeList?.Add(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.Remove(networkPrefab.SourcePrefabGlobalObjectIdHash); +#endif } } @@ -175,6 +201,9 @@ public bool Add(NetworkPrefab networkPrefab) { m_Prefabs.Add(networkPrefab); m_RuntimeAddedPrefabs.Add(networkPrefab); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.TryAdd(networkPrefab.SourcePrefabGlobalObjectIdHash, networkPrefab); +#endif return true; } @@ -202,6 +231,9 @@ public void Remove(NetworkPrefab prefab) m_RuntimeAddedPrefabs.Remove(prefab); OverrideToNetworkPrefab.Remove(prefab.TargetPrefabGlobalObjectIdHash); NetworkPrefabOverrideLinks.Remove(prefab.SourcePrefabGlobalObjectIdHash); +#if UNIFIED_NETCODE && UNIFIED_NGO_REGISTERS_PREFABS + PrefabTable.Remove(prefab.SourcePrefabGlobalObjectIdHash); +#endif } /// @@ -277,6 +309,55 @@ public bool Contains(NetworkPrefab prefab) return false; } +#if UNIFIED_NETCODE + internal bool HasGhostPrefabs { get; private set; } + +#if UNIFIED_NGO_REGISTERS_PREFABS + /// + /// TODO: Either keep or remove prior to freeze. + /// Leaving this here in case we have to control when things get registered. + /// + internal bool HasPendingGhostPrefabs { get; private set; } + private List m_PendingGhostRegistration = new List(); + /// + /// UNIFIED-POC
+ /// Hybrid NetworkObject-Ghost Prefab Registration
+ ///
+ /// + /// When is true, s + /// will mark themselves as having a ghost during . + /// After validation, if a network prefab's value is + /// set, then it is added to . + /// Within during the , + /// if is true then will be invoked. + /// This will repeat until the hosted single world instance is created. + /// + /// + internal void RegisterGhostPrefabs(NetworkManager networkManager) + { + if (!HasPendingGhostPrefabs) + { + Debug.LogWarning($"Should not be invoking!"); + return; + } + var isHost = networkManager.IsHost; + for (int i = m_PendingGhostRegistration.Count - 1; i >= 0; i--) + { + var networkPrefab = m_PendingGhostRegistration[i]; + + // Returns false if the single world is not available yet + if (NetCode.Netcode.RegisterPrefabSingleWorld(networkPrefab.Prefab, isHost, networkManager.NetcodeWorld)) + { + Debug.Log($"[{nameof(NetworkPrefabs)}][{nameof(RegisterGhostPrefabs)}] Registered hybrid spawned object: {networkPrefab.Prefab.name}"); + m_PendingGhostRegistration.RemoveAt(i); + } + } + HasPendingGhostPrefabs = m_PendingGhostRegistration.Count > 0; + } +#endif +#endif + + /// /// Configures for the given /// @@ -295,6 +376,18 @@ private bool AddPrefabRegistration(NetworkPrefab networkPrefab) uint source = networkPrefab.SourcePrefabGlobalObjectIdHash; uint target = networkPrefab.TargetPrefabGlobalObjectIdHash; +#if UNIFIED_NETCODE + if (networkPrefab.HasGhost) + { + HasGhostPrefabs = true; + +#if UNIFIED_NGO_REGISTERS_PREFABS + HasPendingGhostPrefabs = true; + m_PendingGhostRegistration.TryAdd(networkPrefab); +#endif + } +#endif + // Make sure the prefab isn't already registered. if (NetworkPrefabOverrideLinks.ContainsKey(source)) { diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs index 59f9e637b6..696bef2234 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs @@ -1,8 +1,10 @@ #pragma warning disable IDE0005 using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; using Unity.Collections; +#if MULTIPLAYER_TOOLS && (DEVELOPMENT_BUILD || UNITY_EDITOR || UNITY_MP_TOOLS_NET_STATS_MONITOR_ENABLED_IN_RELEASE) +using System.Runtime.CompilerServices; +#endif using UnityEngine; #pragma warning restore IDE0005 diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs index b9a2c15789..df32e1b7dd 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs @@ -1,10 +1,22 @@ using System; using System.Collections.Generic; -using Unity.Collections; using System.Linq; +using Unity.Collections; +#if UNIFIED_NETCODE +using Unity.Entities; +using Unity.NetCode; +#endif using Unity.Netcode.Components; using Unity.Netcode.Logging; using Unity.Netcode.Runtime; +// TODO-UNIFIED: When: +// - N4E is a dependency of Netcode for GameObjects. +// - TestProject has been updated to include N4E. +// - TestProject and Runtime tests have been updated to use UnifiedHost. +// Remove the conditional compilation and just use the namespace. +#if UNIFIED_NETCODE && OUT_OF_BAND_RPC +using Unity.Netcode.Unified; +#endif using UnityEngine; #if UNITY_EDITOR using UnityEditor; @@ -12,6 +24,8 @@ #endif using UnityEngine.SceneManagement; + + namespace Unity.Netcode { /// @@ -54,7 +68,7 @@ public class NetworkManager : MonoBehaviour, INetworkUpdateSystem #pragma warning restore IDE1006 // restore naming rule violation check -#if DEVELOPMENT_BUILD || UNITY_EDITOR +#if DEBUG || UNITY_EDITOR 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; @@ -462,9 +476,14 @@ public void NetworkUpdate(NetworkUpdateStage updateStage) // This should be invoked just prior to the MessageManager processes its outbound queue. SceneManager.CheckForAndSendNetworkObjectSceneChanged(); +#if UNIFIED_NETCODE + if (!NetworkConfig.Prefabs.HasGhostPrefabs) +#endif + { - // Process outbound messages - MessageManager.ProcessSendQueues(); + // Process outbound messages + MessageManager.ProcessSendQueues(); + } // Metrics update needs to be driven by NetworkConnectionManager's update to assure metrics are dispatched after the send queue is processed. MetricsManager.UpdateMetrics(); @@ -1009,11 +1028,13 @@ internal bool NetworkManagerCheckForParent(bool ignoreNetworkManagerCache = fals { #if UNITY_EDITOR var isParented = NetworkManagerHelper.NotifyUserOfNestedNetworkManager(this, ignoreNetworkManagerCache); + + #else - var isParented = transform.root != transform; + var isParented = transform.parent != null; if (isParented) { - throw new Exception(GenerateNestedNetworkManagerMessage(transform)); + Log.Error(new Context(LogLevel.Error, GenerateNestedNetworkManagerMessage(transform))); } #endif return isParented; @@ -1029,7 +1050,17 @@ internal static string GenerateNestedNetworkManagerMessage(Transform transform) /// private void OnTransformParentChanged() { +#if UNITY_EDITOR + // During editor playmode, we log the message as a dialog box + // and that script sets the parent back to root/null. NetworkManagerCheckForParent(); +#else + if (NetworkManagerCheckForParent()) + { + // During runtime, we log the message and set our parent back to root/null. + transform.parent = null; + } +#endif } /// @@ -1216,6 +1247,23 @@ internal void Initialize(bool server) // UnityTransport dependencies are then initialized RealTimeProvider = ComponentFactory.Create(this); + +#if UNIFIED_NETCODE && OUT_OF_BAND_RPC + // TODO-FixMe: + // We assign transport at this point to preceed the NetworkConnectionManager + // being initialized. However, HasGhostPrefabs might not be set at this point + // if the prefabs list was set after instantiating the NetworkManager. + // Integration tests do this, but user code could do this too. + // To-Investigate: + // Determine if this really impacts anything having prefabs initialze/register + // at this point versus last. + NetworkConfig.InitializePrefabs(); + if (NetworkConfig.Prefabs.HasGhostPrefabs) + { + NetworkConfig.NetworkTransport = gameObject.AddComponent(); + } +#endif + MetricsManager.Initialize(this); { @@ -1223,7 +1271,7 @@ internal void Initialize(bool server) MessageManager.Hook(new NetworkManagerHooks(this)); -#if DEVELOPMENT_BUILD || UNITY_EDITOR +#if DEBUG || UNITY_EDITOR if (NetworkConfig.NetworkProfilingMetrics) { MessageManager.Hook(new ProfilingHooks()); @@ -1262,8 +1310,9 @@ internal void Initialize(bool server) BehaviourUpdater = new NetworkBehaviourUpdater(); BehaviourUpdater.Initialize(this); - +#if !UNIFIED_NETCODE NetworkConfig.InitializePrefabs(); +#endif PrefabHandler.RegisterPlayerPrefab(); #if UNITY_EDITOR BeginNetworkSession(); @@ -1310,6 +1359,55 @@ private bool CanStart(StartType type) return true; } +#if UNIFIED_NETCODE + /// + /// The world instance assigned to this NetworkManager instance. + /// + public NetcodeWorld NetcodeWorld { get; internal set; } + internal void InitializeNetcodeWorld() + { + if (NetcodeWorld != null) + { + return; + } + + if (this == Singleton) + { + if (NetCode.Netcode.IsActive) + { + Log.Info(new Context(LogLevel.Normal, "Netcode is not active but has an instance at this point.")); + } + /// !! Important !! + /// Clear out any pre-existing configuration in the event this applicatioin instance has already been connected to a session. + NetCode.Netcode.Reset(); + } + + /// !! Initialize worlds here !! + /// Worlds are created here: + UnifiedBootstrap.CurrentNetworkManagerForInitialization = this; + DefaultWorldInitialization.Initialize("Default World", false); + } + + /// + /// Checks to make sure the NetcodeConfig is configured correctly for hybrid mode. Hybrid mode requires a single world to be used for the NetcodeConfig. + /// + /// True if the configuration is correct; otherwise, false. + private bool UnifiedIsConfiguredCorrectly() + { + if (NetCodeConfig.Global == null) + { + Log.Error(new Context(LogLevel.Error, "You must create a {nameof(NetCodeConfig)} and set it to a single world in order to run in hybrid mode!").AddTag("Unified")); + return false; + } + if (NetCodeConfig.Global.HostWorldModeSelection != NetCodeConfig.HostWorldMode.SingleWorld) + { + Log.Error(new Context(LogLevel.Error, "You must configure {nameof(NetCodeConfig)} to only use a single world in order to run in hybrid mode!").AddTag("Unified")); + return false; + } + return true; + } +#endif + /// /// Starts a server /// @@ -1341,6 +1439,28 @@ public bool StartServer() return false; } +#if UNIFIED_NETCODE + // TODO-UNIFIED: Review and align on this being a way to handle knowing if the world should be created. + if (NetworkConfig.Prefabs.HasGhostPrefabs) + { + if (!UnifiedIsConfiguredCorrectly()) + { + m_ShuttingDown = true; + ShutdownInternal(); + return false; + } + if (LogLevel <= LogLevel.Developer) + { + Log.Info(new Context(LogLevel.Developer, "Creating world: Default world")); + } + InitializeNetcodeWorld(); + } +#endif + return InternalStartServer(); + } + + internal bool InternalStartServer() + { try { IsListening = NetworkConfig.NetworkTransport.StartServer(); @@ -1366,7 +1486,6 @@ public bool StartServer() ShutdownInternal(); IsListening = false; } - return IsListening; } @@ -1399,6 +1518,25 @@ public bool StartClient() return false; } +#if UNIFIED_NETCODE + // TODO-UNIFIED: Review and align on this being a way to handle knowing if the world should be created. + if (NetworkConfig.Prefabs.HasGhostPrefabs) + { + if (!UnifiedIsConfiguredCorrectly()) + { + m_ShuttingDown = true; + ShutdownInternal(); + return false; + } + Log.Info(new Context(LogLevel.Developer, "Creating world: Default world")); + InitializeNetcodeWorld(); + } +#endif + return InternalStartClient(); + } + + internal bool InternalStartClient() + { try { IsListening = NetworkConfig.NetworkTransport.StartClient(); @@ -1423,6 +1561,7 @@ public bool StartClient() return IsListening; } + /// /// Starts a Host /// @@ -1453,6 +1592,25 @@ public bool StartHost() return false; } +#if UNIFIED_NETCODE + // TODO-UNIFIED: Review and align on this being a way to handle knowing if the world should be created. + if (NetworkConfig.Prefabs.HasGhostPrefabs) + { + if (!UnifiedIsConfiguredCorrectly()) + { + m_ShuttingDown = true; + ShutdownInternal(); + return false; + } + Log.Info(new Context(LogLevel.Developer, "Creating world: Default world")); + InitializeNetcodeWorld(); + } +#endif + return InternalStartHost(); + } + + internal bool InternalStartHost() + { try { IsListening = NetworkConfig.NetworkTransport.StartServer(); @@ -1661,6 +1819,25 @@ internal void ShutdownInternal() IsListening = false; m_ShuttingDown = false; + +#if UNIFIED_NETCODE + // TODO-UNIFIED: Review and align on this being a way to handle knowing if the world should be created. + if (NetworkConfig != null && NetworkConfig.Prefabs != null && NetworkConfig.Prefabs.HasGhostPrefabs) + { + try + { + // Dispose of all worlds + World.DisposeAllWorlds(); + // Clear the world assigned from previous session + NetcodeWorld = null; + } + catch (Exception ex) + { + Log.Exception(ex); + } + } +#endif + // Generate a local notification that the host client is disconnected if (IsHost) { @@ -1689,7 +1866,6 @@ internal void ShutdownInternal() NetworkTimeSystem?.Shutdown(); NetworkTickSystem = null; - if (localClient.IsClient) { // If we were a client, we want to know if we were a host @@ -1965,5 +2141,12 @@ internal static void OnOneTimeTearDown() } #endif +#if UNIFIED_NETCODE + // TODO-UNIFIED: We might not need all of this (i.e. UnifiedUpdateConnections might be handled differently in unified) + public delegate void OnConnectDelegate(NetcodeConnection connection); + public delegate void OnDisconnectDelegate(NetcodeConnection connection); + public static OnConnectDelegate OnNetCodeConnect; + public static OnDisconnectDelegate OnNetCodeDisconnect; +#endif } } diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs index d2f5aa5869..2286e50c65 100644 --- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs +++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs @@ -5,13 +5,13 @@ using System.Text; using Unity.Netcode.Components; using Unity.Netcode.Runtime; +#if UNIFIED_NETCODE +using Unity.NetCode; +#endif + #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; @@ -287,6 +287,10 @@ internal void OnValidate() // Always check for in-scene placed to assure any previous version scene assets with in-scene place NetworkObjects gets updated. CheckForInScenePlaced(); +#if UNIFIED_NETCODE + UnifiedValidation(); +#endif + // If the GlobalObjectIdHash value changed, then mark the asset dirty. if (GlobalObjectIdHash != oldValue) { @@ -348,6 +352,39 @@ private void CheckForInScenePlaced() } #endif // UNITY_EDITOR +#if UNIFIED_NETCODE + [HideInInspector] + [SerializeField] + internal GhostAdapter GhostAdapter; + + [HideInInspector] + [SerializeField] + internal bool HasGhost; + + [HideInInspector] + [SerializeField] + internal bool HadBridge; +#if UNITY_EDITOR + internal void UnifiedValidation() + { + NetworkObjectBridge = GetComponent(); + GhostAdapter = GetComponent(); + HasGhost = GhostAdapter != null; + if (HasGhost && NetworkObjectBridge == null) + { + NetworkObjectBridge = gameObject.AddComponent(); + HadBridge = true; + // Transform synchronization is handled by unified netcode + SynchronizeTransform = false; + } + else if (HadBridge && !HasGhost && !NetworkObjectBridge) + { + HadBridge = false; + SynchronizeTransform = true; + } + } +#endif +#endif /// /// Gets the NetworkManager that owns this NetworkObject instance /// @@ -1737,10 +1774,17 @@ private void OnDestroy() return; } + var spawnManager = NetworkManager.SpawnManager; + // Always attempt to remove from scene changed updates - networkManager.SpawnManager?.RemoveNetworkObjectFromSceneChangedUpdates(this); + spawnManager?.MarkNetworkObjectAsDestroying(this); +#if UNIFIED_NETCODE + // N4E controls this on the client, allow this if there is a ghost + if (IsSpawned && !HasGhost && !networkManager.ShutdownInProgress) +#else if (IsSpawned && !networkManager.ShutdownInProgress) +#endif { // 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). @@ -1768,11 +1812,11 @@ private void OnDestroy() } } - if (networkManager.SpawnManager != null && networkManager.SpawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject)) + if (spawnManager != null && spawnManager.SpawnedObjects.TryGetValue(NetworkObjectId, out var networkObject)) { if (this == networkObject) { - networkManager.SpawnManager.OnDespawnObject(networkObject, false); + spawnManager.OnDespawnObject(networkObject, false); } } } @@ -2026,6 +2070,12 @@ public void SpawnAsPlayerObject(ulong clientId, bool destroyWithScene = false) /// (true) the will be destroyed (false) the will persist after being despawned public void Despawn(bool destroy = true) { +#if UNIFIED_NETCODE + if (HasGhost && destroy == false) + { + throw new NotSupportedException("Despawn without destroy is not supported for hybrid objects."); + } +#endif if (!IsSpawned) { if (NetworkManager.LogLevel <= LogLevel.Error) @@ -2665,7 +2715,7 @@ internal void InvokeBehaviourNetworkSpawn() childBehaviour.InternalOnNetworkSpawn(); } - // After initialization, we can then invoke OnNetworkSpawn on each child NetworkBehaviour. + // After internally spawning, we can then invoke OnNetworkSpawn on each child NetworkBehaviour. foreach (var childBehaviour in ChildNetworkBehaviours.Values) { if (!childBehaviour.gameObject.activeInHierarchy) @@ -2740,6 +2790,14 @@ internal string GenerateDisabledNetworkBehaviourWarning(NetworkBehaviour network } internal Dictionary ChildNetworkBehaviours; + + /// + /// TODO-UNIFIED: + /// We should pre-calculate the index id's in the editor and save out two lists: + /// - All derived components in a pre-determined order. + /// - All of the identifiers aligned with the above list + /// Then construct the dictionar during awake. + /// internal bool InitializeChildNetworkBehaviours() { ChildNetworkBehaviours = new Dictionary(); @@ -2770,9 +2828,7 @@ internal bool InitializeChildNetworkBehaviours() networkTransform.IsNested = networkTransform.gameObject != gameObject; NetworkTransforms.Add(networkTransform); } - #if COM_UNITY_MODULES_PHYSICS || COM_UNITY_MODULES_PHYSICS2D - var rigidbodyBase = behaviour as NetworkRigidbodyBase; if (rigidbodyBase != null) { @@ -2780,7 +2836,51 @@ internal bool InitializeChildNetworkBehaviours() } #endif } +#if UNIFIED_NETCODE + // For now, cycle through all known NetworkTransform and NetworkRigidbodyBase derived components + // and destroy them all if this is a hybrid prefab instance. + // This allows a user to not have to make direct adjustments until trying out their NGO prefab + // as a hybrid spawned prefab (optional to completely remove, will eventually become obsolete and + // automatically removed later). + if (HasGhost && !NetworkManager.DistributedAuthorityMode) + { + if (NetworkRigidbodies != null) + { + for (int i = NetworkRigidbodies.Count - 1; i >= 0; i--) + { + // TODO-UNIFIED: This needs to be updated to make it "opt-in". + // Only clients remove the rigidbody for performance purposes when running a hybrid spawn client-server topology. + if (!NetworkManager.IsServer) + { + var rigidBody = NetworkRigidbodies[i].gameObject.GetComponent(); + if (rigidBody != null) + { + Destroy(rigidBody); + } + } + ChildNetworkBehaviours.Remove(NetworkRigidbodies[i].NetworkBehaviourId); + Destroy(NetworkRigidbodies[i]); + } + NetworkRigidbodies.Clear(); + } + // When hybrid spawning, the transform is synchronized by the GhostObject. + // As a convenience, we remove and destroy all NetworkTransforms. + // TODO-Parenting-Related-Area: We need to replicate this functionality in a GhostAdapter + // Possibly use a "Synchronize" property and display only on children of a root parent GhostAdapter. + if (NetworkTransforms != null) + { + NetworkManager.Log.Warning(new Logging.Context(LogLevel.Developer, $"[]{name} Hybrid spawned objects do not support {nameof(NetworkTransform)} and " + + $"are removed at runtime. If hybrid spawning is intended, then remove it from the network prefab to avoid allocating and de-allocating at runtime.")); + for (int i = NetworkTransforms.Count - 1; i >= 0; i--) + { + ChildNetworkBehaviours.Remove(NetworkTransforms[i].NetworkBehaviourId); + Destroy(NetworkTransforms[i]); + } + NetworkTransforms.Clear(); + } + } +#endif return true; } @@ -2914,18 +3014,21 @@ internal struct SerializedObject public ulong OwnerClientId; public ushort OwnershipFlags; - private const ushort k_IsPlayerObject = 0x001; - private const ushort k_HasParent = 0x002; - private const ushort k_IsSceneObject = 0x004; - private const ushort k_HasTransform = 0x008; - private const ushort k_IsLatestParentSet = 0x010; - private const ushort k_WorldPositionStays = 0x020; - private const ushort k_DestroyWithScene = 0x040; - private const ushort k_DontDestroyWithOwner = 0x080; - private const ushort k_HasOwnershipFlags = 0x100; - private const ushort k_SyncObservers = 0x200; - private const ushort k_SpawnWithObservers = 0x400; - private const ushort k_HasInstantiationData = 0x800; + private const ushort k_IsPlayerObject = 0x0001; + private const ushort k_HasParent = 0x0002; + private const ushort k_IsSceneObject = 0x0004; + private const ushort k_HasTransform = 0x0008; + private const ushort k_IsLatestParentSet = 0x0010; + private const ushort k_WorldPositionStays = 0x0020; + private const ushort k_DestroyWithScene = 0x0040; + private const ushort k_DontDestroyWithOwner = 0x0080; + private const ushort k_HasOwnershipFlags = 0x0100; + private const ushort k_SyncObservers = 0x0200; + private const ushort k_SpawnWithObservers = 0x0400; + private const ushort k_HasInstantiationData = 0x0800; +#if UNIFIED_NETCODE + private const ushort k_HasGhost = 0x1000; +#endif public bool IsPlayerObject; public bool HasParent; @@ -2946,6 +3049,9 @@ internal struct SerializedObject public bool SyncObservers; public bool SpawnWithObservers; public bool HasInstantiationData; +#if UNIFIED_NETCODE + public bool HasGhost; +#endif [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ushort GetBitsetRepresentation() @@ -2995,10 +3101,19 @@ internal ushort GetBitsetRepresentation() { bitset |= k_SpawnWithObservers; } + if (HasInstantiationData) { bitset |= k_HasInstantiationData; } + +#if UNIFIED_NETCODE + if (HasGhost) + { + bitset |= k_HasGhost; + } + +#endif return bitset; } @@ -3017,6 +3132,9 @@ internal void SetStateFromBitset(ushort bitset) SyncObservers = (bitset & k_SyncObservers) != 0; SpawnWithObservers = (bitset & k_SpawnWithObservers) != 0; HasInstantiationData = (bitset & k_HasInstantiationData) != 0; +#if UNIFIED_NETCODE + HasGhost = (bitset & k_HasGhost) != 0; +#endif } // When handling the initial synchronization of NetworkObjects, @@ -3282,7 +3400,10 @@ internal SerializedObject Serialize(ulong targetClientId = NetworkManager.Server Hash = CheckForGlobalObjectIdHashOverride(), OwnerObject = this, TargetClientId = targetClientId, - HasInstantiationData = InstantiationData != null && InstantiationData.Length > 0 + HasInstantiationData = InstantiationData != null && InstantiationData.Length > 0, +#if UNIFIED_NETCODE + HasGhost = HasGhost, +#endif }; // Handle Parenting @@ -3552,7 +3673,76 @@ private void Awake() { SetCachedParent(transform.parent); SceneOrigin = gameObject.scene; + + } + +#if UNIFIED_NETCODE + +#if DEBUG_ENABLE_DISABLE + private void OnEnable() + { + Debug.Log("Enabled!"); + } + + private void OnDisable() + { + Debug.Log("Disabled!"); + if (IsSpawned || HasGhost) + { + if (HasGhost && GhostAdapter.IsPrefab()) + { + return; + } + gameObject.SetActive(true); + } + + try + { + throw new Exception("Disabled trap!"); + } + catch (Exception ex) + { + Debug.LogWarning($"[{name}][{ex.Message}] Callstack:\n{ex.StackTrace}"); + } } +#endif + + private void Start() + { + InitGhost(); + } + [SerializeField] + [HideInInspector] + internal NetworkObjectBridge NetworkObjectBridge; + + private void InitGhost() + { + if (!NetworkManager.IsListening) + { + if (NetworkManager.LogLevel == LogLevel.Developer) + { + Debug.LogWarning($"[{nameof(NetworkObject)}] Did not register because there is no session in progress!"); + } + return; + } + + if (!HasGhost || !NetworkObjectBridge || GhostAdapter.IsPrefab()) + { + // Nothing to register + return; + } + + // All instances with Ghosts are automatically registered + if (NetworkManager.LogLevel == LogLevel.Developer) + { + Debug.Log($"[{nameof(NetworkObject)}] GhostBridge {name} detected and instantiated."); + } + if (GhostAdapter.WasInitialized && NetworkObjectBridge.NetworkObjectId.Value != 0) + { + NetworkManager.SpawnManager.GhostSpawnManager.RegisterGhostBridge(NetworkObjectBridge.NetworkObjectId.Value, this); + } + } +#endif /// /// Update diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/DeferredMessageManager.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/DeferredMessageManager.cs index f05d000fec..c68173e60d 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/DeferredMessageManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/DeferredMessageManager.cs @@ -125,6 +125,16 @@ protected virtual void PurgeTrigger(IDeferredNetworkMessageManager.TriggerType t triggerInfo.TriggerData.Dispose(); } + public bool HasAnyOfTrigger(IDeferredNetworkMessageManager.TriggerType trigger) + { + if (m_Triggers.TryGetValue(trigger, out var triggers)) + { + return triggers.Count != 0; + } + + return false; + } + public virtual void ProcessTriggers(IDeferredNetworkMessageManager.TriggerType trigger, ulong key) { if (m_Triggers.TryGetValue(trigger, out var triggers)) @@ -143,6 +153,11 @@ public virtual void ProcessTriggers(IDeferredNetworkMessageManager.TriggerType t triggerInfo.TriggerData.Dispose(); } } + + if (trigger != IDeferredNetworkMessageManager.TriggerType.OnOtherTriggerFinishedProcessing) + { + ProcessTriggers(IDeferredNetworkMessageManager.TriggerType.OnOtherTriggerFinishedProcessing, (ulong)trigger); + } } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/IDeferredNetworkMessageManager.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/IDeferredNetworkMessageManager.cs index 910021f606..569970b22f 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/IDeferredNetworkMessageManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/IDeferredNetworkMessageManager.cs @@ -8,6 +8,10 @@ internal enum TriggerType OnSpawn, OnAddPrefab, OnNextFrame, +#if UNIFIED_NETCODE + OnGhostSpawned, +#endif + OnOtherTriggerFinishedProcessing, } /// @@ -28,6 +32,8 @@ internal enum TriggerType public void ProcessTriggers(TriggerType trigger, ulong key); + public bool HasAnyOfTrigger(TriggerType trigger); + /// /// Cleans up any trigger that's existed for more than a second. /// These triggers were probably for situations where a request was received after a despawn rather than before a spawn. diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs index cf518a6216..6d7d28bf73 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/CreateObjectMessage.cs @@ -120,6 +120,25 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int ByteUnpacker.ReadValuePacked(reader, out NetworkObjectId); } +#if UNIFIED_NETCODE + // Leaving for debugging purposes + //if (networkManager.LogLevel == LogLevel.Developer) + //{ + // UnityEngine.Debug.Log($"Received {nameof(CreateObjectMessage)} for NetworkObjectId-{ObjectInfo.NetworkObjectId}."); + //} + + // For now, we will defer the create object message until the associated Ghost is spawned + if (ObjectInfo.HasGhost && !networkManager.SpawnManager.GhostSpawnManager.IsGhostPendingSpawn(ObjectInfo.NetworkObjectId)) + { + if (networkManager.LogLevel == LogLevel.Developer) + { + UnityEngine.Debug.Log($"[{nameof(NetworkObject)}-{ObjectInfo.NetworkObjectId}] Deferring {nameof(CreateObjectMessage)} to wait for Ghost."); + } + networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnGhostSpawned, ObjectInfo.NetworkObjectId, reader, ref context, k_Name); + return false; + } +#endif + if (!networkManager.NetworkConfig.ForceSamePrefabs && !networkManager.SpawnManager.HasPrefab(ObjectInfo)) { networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, ObjectInfo.Hash, reader, ref context, k_Name); diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs index 39daa80c39..8cd1fcd131 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ParentSyncMessage.cs @@ -118,29 +118,42 @@ public void Handle(ref NetworkContext context) // DANGO-TODO: Still determining if we should not apply this change (I am leaning towards not allowing it). } + networkObject.SetNetworkParenting(LatestParent, WorldPositionStays); networkObject.ApplyNetworkParenting(RemoveParent); - // This check is primarily for client-server network topologies when the motion model is owner authoritative: - // When SyncOwnerTransformWhenParented is enabled, then always apply the transform values. - // When SyncOwnerTransformWhenParented is disabled, then only synchronize the transform on non-owner instances. - if (networkObject.SyncOwnerTransformWhenParented || (!networkObject.SyncOwnerTransformWhenParented && !networkObject.IsOwner)) +#if UNIFIED_NETCODE + if (networkObject.HasGhost) { - // We set all of the transform values after parenting as they are - // the values of the server-side post-parenting transform values - if (!WorldPositionStays) - { - networkObject.transform.SetLocalPositionAndRotation(Position, Rotation); - } - else + // Handles the GhostAdapter side of things for parenting + networkObject.NetworkObjectBridge.HybridParentUpdate(Scale); + } + else +#endif + { + // This check is primarily for client-server network topologies when the motion model is owner authoritative: + // When SyncOwnerTransformWhenParented is enabled, then always apply the transform values. + // When SyncOwnerTransformWhenParented is disabled, then only synchronize the transform on non-owner instances. + if (networkObject.SyncOwnerTransformWhenParented || (!networkObject.SyncOwnerTransformWhenParented && !networkObject.IsOwner)) { - networkObject.transform.SetPositionAndRotation(Position, Rotation); + + // We set all of the transform values after parenting as they are + // the values of the server-side post-parenting transform values + if (!WorldPositionStays) + { + networkObject.transform.SetLocalPositionAndRotation(Position, Rotation); + } + else + { + networkObject.transform.SetPositionAndRotation(Position, Rotation); + } + networkObject.transform.localScale = Scale; } - networkObject.transform.localScale = Scale; } // If in distributed authority mode and we are running a DAHost and this is the DAHost, then forward the parent changed message to any remaining clients - if ((networkManager.DistributedAuthorityMode && !networkManager.CMBServiceConnection && networkManager.DAHost) || (networkObject.AllowOwnerToParent && context.SenderId == networkObject.OwnerClientId && networkManager.IsServer)) + if ((networkManager.DistributedAuthorityMode && !networkManager.CMBServiceConnection && networkManager.DAHost) + || (networkObject.AllowOwnerToParent && context.SenderId == networkObject.OwnerClientId && networkManager.IsServer)) { var size = 0; var message = this; diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/SceneEventMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/SceneEventMessage.cs index 25c53a2786..901b421cdb 100644 --- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/SceneEventMessage.cs +++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/SceneEventMessage.cs @@ -1,4 +1,3 @@ - namespace Unity.Netcode { // Todo: Would be lovely to get this one nicely formatted with all the data it sends in the struct @@ -9,6 +8,7 @@ internal struct SceneEventMessage : INetworkMessage public SceneEventData EventData; + private const string k_Name = "SceneEventMessage"; private FastBufferReader m_ReceivedData; @@ -19,6 +19,19 @@ public void Serialize(FastBufferWriter writer, int targetVersion) public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int receivedMessageVersion) { + var networkManager = (NetworkManager)context.SystemOwner; +#if UNIFIED_NETCODE + // Defer this message if the OnGhostSpawned trigger is still being processed. This is because the scene event message can be sent + // as part of the ghost spawning process and we want to make sure that all ghost spawning related messages are processed before we + // process this one. This is to avoid any potential issues with the order of message processing and to ensure that all ghost + // related messages are processed before we process this one. + if (networkManager.DeferredMessageManager.HasAnyOfTrigger(IDeferredNetworkMessageManager.TriggerType + .OnGhostSpawned)) + { + networkManager.DeferredMessageManager.DeferMessage(IDeferredNetworkMessageManager.TriggerType.OnOtherTriggerFinishedProcessing, (ulong)IDeferredNetworkMessageManager.TriggerType.OnGhostSpawned, reader, ref context, k_Name); + return false; + } +#endif m_ReceivedData = reader; return true; } diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs index 2fbdf1fbe9..641fed9b8e 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs @@ -2756,8 +2756,14 @@ internal void PopulateScenePlacedObjects(Scene sceneToFilterBy, bool clearSceneP var globalObjectIdHash = networkObjectInstance.GlobalObjectIdHash; var sceneHandle = networkObjectInstance.gameObject.scene.handle; // We check to make sure the NetworkManager instance is the same one to be "NetcodeIntegrationTestHelpers" compatible and filter the list on a per scene basis (for additive scenes) +#if UNIFIED_NETCODE + if (!networkObjectInstance.HasGhost && networkObjectInstance.IsSceneObject != false && (networkObjectInstance.NetworkManager == NetworkManager || + networkObjectInstance.NetworkManagerOwner == null) && sceneHandle == sceneToFilterBy.handle) +#else if (networkObjectInstance.IsSceneObject != false && (networkObjectInstance.NetworkManager == NetworkManager || networkObjectInstance.NetworkManagerOwner == null) && sceneHandle == sceneToFilterBy.handle) + +#endif { if (!ScenePlacedObjects.ContainsKey(globalObjectIdHash)) { diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs index 0fff313574..9ebd119033 100644 --- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs +++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs @@ -5,6 +5,7 @@ using Unity.Collections; using UnityEngine.SceneManagement; + namespace Unity.Netcode { /// @@ -1113,6 +1114,20 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) var serializedObject = new NetworkObject.SerializedObject(); serializedObject.Deserialize(InternalBuffer); +#if UNIFIED_NETCODE + // This handles the case where a NetworkObject is serialized with a ghost component but the ghost isn't actually included in + // the spawn message and won't be spawned by the client until later in the N4E synchronization process. In this case, we need + // to defer the deserialization of the NetworkObject until the ghost is spawned and we have an instance to deserialize this + // information during synchronization. + if (serializedObject.HasGhost) + { + if (networkManager.SpawnManager.GhostSpawnManager.ShouldDeferGhostSceneObject(serializedObject, InternalBuffer)) + { + continue; + } + } +#endif + // If the sceneObject is in-scene placed, then set the scene being synchronized if (serializedObject.IsSceneObject) { @@ -1120,9 +1135,9 @@ internal void SynchronizeSceneNetworkObjects(NetworkManager networkManager) } var spawnedNetworkObject = NetworkObject.Deserialize(serializedObject, InternalBuffer, networkManager); - var noStop = InternalBuffer.Position; if (EnableSerializationLogs) { + var noStop = InternalBuffer.Position; builder.AppendLine($"[Head: {noStart}][Tail: {noStop}][Size: {noStop - noStart}][{spawnedNetworkObject.name}][NID-{spawnedNetworkObject.NetworkObjectId}][Children: {spawnedNetworkObject.ChildNetworkBehaviours.Count}]"); LogArray(InternalBuffer.ToArray(), noStart, noStop, builder); } @@ -1294,7 +1309,6 @@ private void DeserializeObjectsMovedIntoNewScene(FastBufferReader reader) } } - /// /// While a client is synchronizing ObjectSceneChanged messages could be received. /// This defers any ObjectSceneChanged message processing to occur after the client diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/GhostSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/GhostSpawnManager.cs new file mode 100644 index 0000000000..4077179f33 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/GhostSpawnManager.cs @@ -0,0 +1,287 @@ +#if UNIFIED_NETCODE +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Unity.Collections; +using Unity.Netcode.Logging; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Netcode +{ + /// + /// Handles the management of ghost spawns during the synchronization process. This includes tracking pending NetworkObject spawns + /// that are waiting for their associated ghost to be spawned before they can be fully deserialized. + /// + internal class GhostSpawnManager + { + private readonly NetworkManager m_NetworkManager; + private readonly ContextualLogger m_Log; + + public GhostSpawnManager(NetworkManager networkManager) + { + m_NetworkManager = networkManager; + m_Log = new ContextualLogger((Object)networkManager, networkManager); + } + + private readonly Dictionary m_GhostsPendingSpawn = new(); + + // TODO: We might want to make this a mock interface but temporary solution to validate + // the need to assure we are registering with the right NetworkManager instance when testing (everything + // will use the singleton during Awake and Start when we need to register). + internal delegate void RegisterPendingGhostDelegateHandler(NetworkObject networkObject, ulong networkObjectId); + + internal static RegisterPendingGhostDelegateHandler RegisterPendingGhost; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void RuntimeInitializeOnLoad() => RegisterPendingGhost = null; + + internal void RegisterGhostBridge(ulong networkObjectId, NetworkObject networkObject) + { + m_Log.Info(new Context(LogLevel.Developer, $"Registering {nameof(NetworkObject)} for ghost bridge").AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + + // Set when running through integration tests in order to initially bypass the + // normal registration. This is because at this point in the instantiation process, + // NetworkObject's NetworkManager is pointing to the singleton which means all instances + // (even if intended to be for a specific client) will end up registering with whichever + // NetworkManager instance is being pointed to by the singleton. + if (RegisterPendingGhost != null) + { + RegisterPendingGhost(networkObject, networkObjectId); + } + else if (!m_NetworkManager.IsServer) + { + RegisterGhostPendingSpawn(networkObject, networkObjectId); + } + } + + internal void RegisterGhostPendingSpawn(NetworkObject networkObject, ulong networkObjectId) + { + m_Log.Info(new Context(LogLevel.Developer, $"Registering {nameof(NetworkObject)} for ghost spawn").AddTag(networkObject.name).AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + + if (!m_GhostsPendingSpawn.TryAdd(networkObjectId, networkObject)) + { + m_Log.Error(new Context(LogLevel.Normal, $"{nameof(NetworkObject)} has already been registered as a pending ghost!").AddTag(networkObject.name).AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + return; + } + + // TODO-REVIEW-BELOW: *** This is very likely no longer an issue with the new connection sequence *** + // TODO-UNIFIED: We need a better way to preserve any hybrid instances pending NGO spawn. + // Edge-Case scenario: During initial client synchronization (i.e. !m_NetworkManager.IsConnectedClient). + // + // Description: A client can receive snapshots before finishing the NGO synchronization process. + // This is when an edge case scenario can happen where the initial NGO synchronization information + // can include new scenes to load. If one of those scenes is configured to load in SingleMode, then + // any instantiated ghosts pending synchronization would be instantiated in whatever the currently + // active scene was when the client was processing the synchronization data. If the ghosts pending + // synchronization are in the currently active scene when the new scene is loaded in SingleMode, then + // they would be destroyed. + // + // Current Fix: + // If the client is not yet synchronized, then any ghost pending spawn get migrated into the DDOL. + // + // Further review: + // We need to make sure that we are migrating NetworkObjects into their assigned scene (if scene + // management is enabled). Currently, we assume all instances were in the DDOL and just migrate + // them into the currently active scene upon spawn. + if (!m_NetworkManager.IsConnectedClient && !m_GhostsPendingSynchronization.ContainsKey(networkObjectId)) + { + Object.DontDestroyOnLoad(networkObject.gameObject); + } + else // There is matching spawn data for this pending Ghost, process the pending spawn for this hybrid instance. + { + m_NetworkManager.DeferredMessageManager.ProcessTriggers(IDeferredNetworkMessageManager.TriggerType.OnGhostSpawned, networkObjectId); + if (m_GhostsPendingSynchronization.ContainsKey(networkObjectId)) + { + ProcessGhostPendingSynchronization(networkObjectId); + } + } + } + + internal bool TryGetGhostNetworkObjectForSpawn(NetworkObject.SerializedObject serializedObject, [NotNullWhen(true)] out NetworkObject networkObject) + { + var networkObjectId = serializedObject.NetworkObjectId; + + // TODO-UNIFIED: Get this working somehow (or if not possible prevent this from happening prior to getting to this point) + if (serializedObject.HasInstantiationData) + { + m_Log.Error(new Context(LogLevel.Error, $"{nameof(NetworkObject)} Pre-spawn instantiation data does not work in this version!").AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + } + if (!m_GhostsPendingSpawn.Remove(networkObjectId, out networkObject) || networkObject == null) + { + m_Log.Error(new Context(LogLevel.Error, $"Attempting to spawn {nameof(NetworkObject)} with no instance to spawn!").AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + return false; + } + + // TODO-UNIFIED: We need a better way to preserve any hybrid instances pending NGO spawn. + // NOTE: We might be able to use the NetworkSceneHandle to get the associated local scene handle to which we can use to get the targeted scene. + UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(networkObject.gameObject, UnityEngine.SceneManagement.SceneManager.GetActiveScene()); + return true; + } + + private bool m_GhostsArePendingSynchronization; + private readonly Dictionary m_GhostsPendingSynchronization = new(); + internal void RegisterGhostPendingSynchronization(PendingGhostSpawnEntry pendingGhostSpawnEntry) + { + var networkObjectId = pendingGhostSpawnEntry.SerializedObject.NetworkObjectId; + m_Log.Info(new Context(LogLevel.Developer, $"Registering {nameof(NetworkObject.SerializedObject)} for pending synchronization").AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + + m_GhostsPendingSynchronization.TryAdd(networkObjectId, pendingGhostSpawnEntry); + m_GhostsArePendingSynchronization = true; + } + + internal NetworkObject ProcessGhostPendingSynchronization(ulong networkObjectId, bool removeUponSpawn = true) + { + var ghostPendingSync = m_GhostsPendingSynchronization[networkObjectId]; + var serializedObject = ghostPendingSync.SerializedObject; + var reader = ghostPendingSync.Buffer; + if (removeUponSpawn) + { + m_GhostsPendingSynchronization.Remove(networkObjectId); + } + + if (serializedObject.IsSceneObject) + { + m_NetworkManager.SceneManager.SetTheSceneBeingSynchronized(serializedObject.NetworkSceneHandle); + } + var networkObject = NetworkObject.Deserialize(serializedObject, reader, m_NetworkManager); + + // TODO-UNIFIED: How do we handle the "all in-scene placed objects are spawned notification"? + //if (serializedObject.IsSceneObject) + //{ + // networkObject.InternalInSceneNetworkObjectsSpawned(); + //} + + // If removing, determine if we have any pending ghosts remaining and dispose of this ghost's pending synchronization buffer. + // If not removing, then we will keep the buffer around until we do remove it (either via spawn or timeout). + if (removeUponSpawn) + { + m_GhostsArePendingSynchronization = m_GhostsPendingSynchronization.Count > 0; + ghostPendingSync.Dispose(); + } + return networkObject; + } + + + private readonly HashSet m_GhostSynchronizationPendingRemoval = new(); + + internal void ProcessAllGhostsPendingSynchronization() + { + var spawnTimeout = m_NetworkManager.NetworkConfig.SpawnTimeout; + if (!m_GhostsArePendingSynchronization) + { + return; + } + foreach (var ghost in m_GhostsPendingSynchronization) + { + var networkObjectId = ghost.Value.SerializedObject.NetworkObjectId; + if (m_GhostsPendingSpawn.ContainsKey(networkObjectId)) + { + // Process it, but don't remove it as we handle that a little later + ProcessGhostPendingSynchronization(ghost.Value.SerializedObject.NetworkObjectId, false); + m_GhostSynchronizationPendingRemoval.Add(networkObjectId); + } + else + if ((ghost.Value.RegistrationTime + spawnTimeout) < Time.realtimeSinceStartup) + { + m_Log.Info(new Context(LogLevel.Developer, $"Registering {nameof(NetworkObject.SerializedObject)} for pending synchronization").AddInfo(nameof(NetworkObject.NetworkObjectId), networkObjectId)); + + // Timed out entries are removed too + m_GhostSynchronizationPendingRemoval.Add(ghost.Key); + } + } + + foreach (var networkObjectId in m_GhostSynchronizationPendingRemoval) + { + var entry = m_GhostsPendingSynchronization[networkObjectId]; + m_GhostsPendingSynchronization.Remove(networkObjectId); + entry.Buffer.Dispose(); + } + m_GhostSynchronizationPendingRemoval.Clear(); + m_GhostsArePendingSynchronization = m_GhostsPendingSynchronization.Count > 0; + } + + internal void MarkNetworkObjectAsDestroying(ulong networkObjectId) + { + m_GhostsPendingSpawn.Remove(networkObjectId); + m_GhostsPendingSynchronization.Remove(networkObjectId); + } + + internal bool IsGhostPendingSpawn(ulong networkObjectId) + { + return m_GhostsPendingSpawn.ContainsKey(networkObjectId); + } + + /// + /// Used in scene managment synchronization. + /// Verifies if this should defer its spawn until the associated GhostObject is created. + /// + /// The object to check + /// 's to save the buffer with data for the deferred spawn. + /// True if the serialized object should should wait for the associated ghost object; false otherwise + internal bool ShouldDeferGhostSceneObject(NetworkObject.SerializedObject serializedObject, FastBufferReader internalBuffer) + { + if (!m_GhostsPendingSpawn.TryGetValue(serializedObject.NetworkObjectId, out var existingObject)) + { + m_Log.Info(new Context(LogLevel.Developer, $"Deferring creation of InScenePlaced {nameof(NetworkObject)} to wait for Ghost.").AddTag("SynchronizeSceneNetworkObjects").AddInfo(nameof(NetworkObject.NetworkObjectId), serializedObject.NetworkObjectId)); + + var newEntry = new PendingGhostSpawnEntry() + { + RegistrationTime = Time.realtimeSinceStartup, + SerializedObject = serializedObject, + Buffer = new FastBufferReader(internalBuffer, Allocator.Persistent, serializedObject.SynchronizationDataSize, internalBuffer.Position) + }; + + RegisterGhostPendingSynchronization(newEntry); + internalBuffer.Seek(internalBuffer.Position + serializedObject.SynchronizationDataSize); + return true; + } + + if (existingObject == null) + { + m_Log.Info(new Context(LogLevel.Developer, $"Dropping creation of InScenePlaced {nameof(NetworkObject)} as it has an entry but no longer exists!").AddTag("SynchronizeSceneNetworkObjects").AddInfo(nameof(NetworkObject.NetworkObjectId), serializedObject.NetworkObjectId)); + + // If it no longer exists, then just remove the entry and skip it. + internalBuffer.Seek(internalBuffer.Position + serializedObject.SynchronizationDataSize); + m_GhostsPendingSpawn.Remove(serializedObject.NetworkObjectId); + return true; + } + + return false; + } + + /// + /// Finalizer that ensures proper cleanup of manager resources + /// + ~GhostSpawnManager() + { + Shutdown(); + } + + internal void Shutdown() + { + m_GhostsPendingSpawn.Clear(); + m_GhostsPendingSynchronization.Clear(); + } + } + + /// + /// Used to store pending ghost spawns that are waiting for their associated (N4E) ghost to be spawned before they can be fully deserialized and + /// spawned during the scene synchronization process. This is necessary because in unified mode we allow for NetworkObjects with ghost components + /// to be synchronized during the scene synchronization process but we can't guarantee the order of messages that the client receives so we + /// need to defer the deserialization of any NetworkObject that has a ghost component until we have received the message that the ghost has + /// been spawned and we have an instance to deserialize this information into. + /// + internal struct PendingGhostSpawnEntry : IDisposable + { + public float RegistrationTime; + public FastBufferReader Buffer; + public NetworkObject.SerializedObject SerializedObject; + + public void Dispose() + { + Buffer.Dispose(); + } + } +} +#endif diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/GhostSpawnManager.cs.meta b/com.unity.netcode.gameobjects/Runtime/Spawning/GhostSpawnManager.cs.meta new file mode 100644 index 0000000000..0d6ca6acb6 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/GhostSpawnManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f9f76edcf67a469bb7cd094e59343ce9 +timeCreated: 1780070241 \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs index c8aab939f4..34cf77d959 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +#if UNIFIED_NETCODE +using Unity.NetCode; +#endif using UnityEngine; namespace Unity.Netcode @@ -418,6 +421,19 @@ public void AddNetworkPrefab(GameObject prefab) { m_NetworkManager.DeferredMessageManager.ProcessTriggers(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, networkObject.GlobalObjectIdHash); } + +#if UNIFIED_NETCODE + if (m_NetworkManager.IsListening) + { + var ghost = prefab.GetComponent(); + if (ghost) + { + m_NetworkManager.InitializeNetcodeWorld(); + NetCode.Netcode.RegisterPrefabSingleWorld(prefab, m_NetworkManager.IsHost, + m_NetworkManager.NetcodeWorld); + } + } +#endif } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs index 52e891f8e1..766ae67857 100644 --- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs @@ -352,6 +352,10 @@ public NetworkObject[] GetClientOwnedObjects(ulong clientId) /// public NetworkManager NetworkManager { get; } +#if UNIFIED_NETCODE + internal GhostSpawnManager GhostSpawnManager { get; } +#endif + internal readonly Queue ReleasedNetworkObjectIds = new Queue(); private ulong m_NetworkObjectIdCounter; @@ -966,6 +970,17 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SerializedObject s var parentNetworkId = serializedObject.HasParent ? serializedObject.ParentObjectId : default; var worldPositionStays = (!serializedObject.HasParent) || serializedObject.WorldPositionStays; +#if UNIFIED_NETCODE + if (serializedObject.HasGhost) + { + if (!GhostSpawnManager.TryGetGhostNetworkObjectForSpawn(serializedObject, out networkObject)) + { + // Don't need to log because the inner function will log + return null; + } + } + else +#endif // If scene management is disabled or the NetworkObject was dynamically spawned if (!NetworkManager.NetworkConfig.EnableSceneManagement || !serializedObject.IsSceneObject) { @@ -991,7 +1006,6 @@ internal NetworkObject CreateLocalNetworkObject(NetworkObject.SerializedObject s networkObject.gameObject.SetActive(true); } } - if (networkObject == null) { return null; @@ -1189,6 +1203,16 @@ internal bool AuthorityLocalSpawn([NotNull] NetworkObject networkObject, ulong n return false; } +#if UNIFIED_NETCODE + // If this is a hybrid prefab, the spawn authority is responsible for assigning the network object id to the network object bridge so that it + // can be used to link the N4E ghost to the NetworkObject. This is needed because in the hybrid prefab case, the ghost can be spawned before + // the NetworkObject is fully spawned. + if (networkObject.HasGhost) + { + networkObject.NetworkObjectBridge.SetNetworkObjectId(networkObject.NetworkObjectId); + } +#endif + // When done spawning invoke post spawn networkObject.InvokeBehaviourNetworkPostSpawn(); @@ -1678,6 +1702,15 @@ internal void DestroySceneObjects() } } + internal void MarkNetworkObjectAsDestroying(NetworkObject networkObject) + { + // Always attempt to remove from scene changed updates + RemoveNetworkObjectFromSceneChangedUpdates(networkObject); +#if UNIFIED_NETCODE + GhostSpawnManager.MarkNetworkObjectAsDestroying(networkObject.NetworkObjectId); +#endif + } + internal void ServerSpawnSceneObjectsOnStartSweep() { var networkObjects = FindObjects.ByType(orderByIdentifier: true); @@ -1914,7 +1947,14 @@ internal void OnDespawnObject([NotNull] NetworkObject networkObject, bool destro { RemovePlayerObject(networkObject, destroyGameObject); } - +#if UNIFIED_NETCODE + // Unified netcode handles destroying the instance of the object on the non-authority side when the object has a ghost representation. + if (destroyGameObject && networkObject.HasGhost && !NetworkManager.IsServer) + { + // exit early + return; + } +#endif var gobj = networkObject.gameObject; if (destroyGameObject && gobj != null) { @@ -2045,6 +2085,9 @@ internal void HandleNetworkObjectShow(bool forceSend = false) internal NetworkSpawnManager(NetworkManager networkManager) { NetworkManager = networkManager; +#if UNIFIED_NETCODE + GhostSpawnManager = new GhostSpawnManager(networkManager); +#endif } /// diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/Unified.meta b/com.unity.netcode.gameobjects/Runtime/Transports/Unified.meta new file mode 100644 index 0000000000..b4340f3a18 --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Transports/Unified.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5ce5c8d0dc8948aab8482e617eccabcc +timeCreated: 1772129529 \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs b/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs new file mode 100644 index 0000000000..bdaebdc3ca --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs @@ -0,0 +1,476 @@ +#if UNIFIED_NETCODE && OUT_OF_BAND_RPC +using System; +using System.Collections.Generic; +using Unity.Burst; +using Unity.Burst.Intrinsics; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Entities; +using Unity.NetCode; +using Unity.Netcode.Transports.UTP; +using UnityEngine; + +namespace Unity.Netcode.Unified +{ + [BurstCompile] + internal unsafe struct FixedBytes1280 + { + public fixed byte Buffer[1280]; + public int Length; + + // Returns a direct pointer to the data in the buffer. + // Implemented as a static with an in-parameter to avoid the buffer being copied while keeping its memory allocation fixed/non-heap + // Note that the buffer MUST outlive the returned pointer, as it is an alias. + public static byte* GetUnsafePtr(in FixedBytes1280 data) + { + fixed (byte* buffer = data.Buffer) + { + return buffer; + } + } + + // Returns a native array that is an alias of the existing data without copying it + // Implemented as a static with an in-parameter to avoid the buffer being copied while keeping its memory allocation fixed/non-heap + // Note that the buffer MUST outlive the returned array, as it is an alias. + public static NativeArray ToNativeArray(in FixedBytes1280 data) + { + var array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(GetUnsafePtr(data), data.Length, Allocator.None); +#if ENABLE_UNITY_COLLECTIONS_CHECKS + var safety = CollectionHelper.CreateSafetyHandle(Allocator.None); + NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, safety); +#endif + return array; + } + } + + internal struct TransportRpcData : IBufferElementData + { + public FixedBytes1280 Buffer; + } + + [BurstCompile] + internal struct TransportRpc : IOutOfBandRpcCommand, IRpcCommandSerializer + { + public TransportRpcData Value; + + public unsafe void Serialize(ref DataStreamWriter writer, in RpcSerializerState state, in TransportRpc data) + { + writer.WriteInt(data.Value.Buffer.Length); + var span = new Span(FixedBytes1280.GetUnsafePtr(data.Value.Buffer), data.Value.Buffer.Length); + writer.WriteBytes(span); + } + + public unsafe void Deserialize(ref DataStreamReader reader, in RpcDeserializerState state, ref TransportRpc data) + { + var length = reader.ReadInt(); + data.Value.Buffer = new FixedBytes1280 + { + Length = length + }; + + var span = new Span(FixedBytes1280.GetUnsafePtr(data.Value.Buffer), length); + reader.ReadBytes(span); + } + + [BurstCompile(DisableDirectCall = true)] + private static void InvokeExecute(ref RpcExecutor.Parameters parameters) + { + var element = new TransportRpc(); + element.Deserialize(ref parameters.Reader, parameters.DeserializerState, ref element); + parameters.CommandBuffer.AppendToBuffer(parameters.JobIndex, parameters.Connection, element.Value); + } + + private static readonly PortableFunctionPointer k_InvokeExecuteFunctionPointer = new PortableFunctionPointer(InvokeExecute); + + public PortableFunctionPointer CompileExecute() + { + return k_InvokeExecuteFunctionPointer; + } + } + + [UpdateInGroup(typeof(RpcCommandRequestSystemGroup))] + [CreateAfter(typeof(RpcSystem))] + [BurstCompile] + internal partial struct TransportRpcCommandRequestSystem : ISystem + { + private RpcCommandRequest m_Request; + + [BurstCompile] + internal struct SendRpc : IJobChunk + { + public RpcCommandRequest.SendRpcData Data; + + public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask) + { + Data.Execute(chunk, unfilteredChunkIndex); + } + } + + public void OnCreate(ref SystemState state) + { + m_Request.OnCreate(ref state); + } + + [BurstCompile] + public void OnUpdate(ref SystemState state) + { + var sendJob = new SendRpc { Data = m_Request.InitJobData(ref state) }; + state.Dependency = sendJob.Schedule(m_Request.Query, state.Dependency); + } + } + + [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation | WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)] + [UpdateInGroup(typeof(SimulationSystemGroup), OrderLast = true)] + [UpdateBefore(typeof(RpcSystem))] + internal partial class UnifiedNetcodeUpdateSystem : SystemBase + { + public void OnCreate(ref SystemState state) + { + state.RequireForUpdate(); + state.RequireForUpdate(); + } + + public UnifiedNetcodeTransport Transport; + public NetworkManager NetworkManager; + + public List DisconnectQueue = new List(); + + public void Disconnect(Connection connection) + { + DisconnectQueue.Add(connection); + } + + public void SendRpc(TransportRpc rpc, Entity connectionEntity) + { + var rpcQueue = SystemAPI.GetSingleton().GetRpcQueue(); + if (!EntityManager.HasComponent(connectionEntity)) + { + // Disconnected, can't send. + return; + } + var ghostInstance = GetComponentLookup(); + var rpcDataStreamBuffer = EntityManager.GetBuffer(connectionEntity); + rpcQueue.Schedule(rpcDataStreamBuffer, ghostInstance, rpc); + } + + protected override void OnUpdate() + { + NetworkManager.MessageManager.ProcessSendQueues(); + + using var commandBuffer = new EntityCommandBuffer(Allocator.Temp); + foreach(var (networkId, _, entity) in SystemAPI.Query, RefRO>().WithEntityAccess()) + { + var connectionId = networkId.ValueRO.Value; + DynamicBuffer rpcs = EntityManager.GetBuffer(entity); + foreach (var rpc in rpcs) + { + var buffer = rpc.Buffer; + try + { + Transport.DispatchMessage(connectionId, buffer); + } + catch(Exception e) + { + Debug.LogException(e); + } + } + rpcs.Clear(); + } + + foreach (var connection in DisconnectQueue) + { + commandBuffer.AddComponent(connection.ConnectionEntity); + } + DisconnectQueue.Clear(); + + commandBuffer.Playback(EntityManager); + + } + } + + internal class UnifiedNetcodeTransport : NetworkTransport + { + private const int k_MaxPacketSize = 1280; + + private int m_ServerClientId = -1; + public override ulong ServerClientId => (ulong)m_ServerClientId; + + private NetworkManager m_NetworkManager; + + private IRealTimeProvider m_RealTimeProvider; + + private class ConnectionInfo + { + public BatchedSendQueue SendQueue; + public BatchedReceiveQueue ReceiveQueue; + public Connection Connection; + public Dictionary DeferredMessages; + } + + private Dictionary m_Connections; + + internal void DispatchMessage(int connectionId, in FixedBytes1280 buffer) + { + var connectionInfo = m_Connections[connectionId]; + + using var arr = FixedBytes1280.ToNativeArray(buffer); + var reader = new DataStreamReader(arr); + if (connectionInfo.ReceiveQueue == null) + { + connectionInfo.ReceiveQueue = new BatchedReceiveQueue(reader); + } + else + { + connectionInfo.ReceiveQueue.PushReader(reader); + } + + var message = connectionInfo.ReceiveQueue.PopMessage(); + while (message.Count != 0) + { + InvokeOnTransportEvent(NetworkEvent.Data, (ulong)connectionId, message, + m_RealTimeProvider.RealTimeSinceStartup); + message = connectionInfo.ReceiveQueue.PopMessage(); + } + } + + public override unsafe void Send(ulong clientId, ArraySegment payload, NetworkDelivery networkDelivery) + { + if (!m_Connections.TryGetValue((int)clientId, out ConnectionInfo connectionInfo)) + { + return; + } + + connectionInfo.SendQueue.PushMessage(payload); + + while (!connectionInfo.SendQueue.IsEmpty) + { + var rpc = new TransportRpc(); + + var writer = new DataStreamWriter(FixedBytes1280.GetUnsafePtr(rpc.Value.Buffer), k_MaxPacketSize); + + var amount = connectionInfo.SendQueue.FillWriterWithBytes(ref writer, k_MaxPacketSize); + rpc.Value.Buffer.Length = amount; + + var updateSystem = m_NetworkManager.NetcodeWorld.GetExistingSystemManaged(); + updateSystem.SendRpc(rpc, connectionInfo.Connection.ConnectionEntity); + + connectionInfo.SendQueue.Consume(amount); + } + } + + public override NetworkEvent PollEvent(out ulong clientId, out ArraySegment payload, out float receiveTime) + { + clientId = 0; + payload = default; + receiveTime = 0; + return NetworkEvent.Nothing; + } + + private void OnClientConnectedToServer(Connection connection, NetCodeConnectionEvent connectionEvent) + { + m_Connections[connectionEvent.Id.Value] = new ConnectionInfo + { + ReceiveQueue = null, + SendQueue = new BatchedSendQueue(BatchedSendQueue.MaximumMaximumCapacity), + Connection = connection + }; + m_ServerClientId = connectionEvent.Id.Value; + InvokeOnTransportEvent(NetworkEvent.Connect, (ulong)connectionEvent.Id.Value, default, m_RealTimeProvider.RealTimeSinceStartup); + var updateSystem = m_NetworkManager.NetcodeWorld.GetExistingSystemManaged(); + updateSystem.EntityManager.AddBuffer(connection.ConnectionEntity); + } + + private void OnServerNewClientConnection(Connection connection, NetCodeConnectionEvent connectionEvent) + { + m_Connections[connectionEvent.Id.Value] = new ConnectionInfo + { + ReceiveQueue = null, + SendQueue = new BatchedSendQueue(BatchedSendQueue.MaximumMaximumCapacity), + Connection = connection + }; ; + InvokeOnTransportEvent(NetworkEvent.Connect, (ulong)connectionEvent.Id.Value, default, m_RealTimeProvider.RealTimeSinceStartup); + var updateSystem = m_NetworkManager.NetcodeWorld.GetExistingSystemManaged(); + updateSystem.EntityManager.AddBuffer(connection.ConnectionEntity); + } + + private const string k_InvalidRpcMessage = "An invalid RPC was received"; + private const string k_HandshakeTimeoutMessage = "The connection was closed because the handshake timed out."; + private const string k_ApprovalFailureMessage = "The connection was closed because the connection was not approved by the server."; + private const string k_ApprovalTimeoutMessage = "The connection was closed because the connection approval process timed out."; + + private string GetDisconnectMessageFromNetworkStreamDisconnectReason(NetworkStreamDisconnectReason reason) + { + switch (reason) + { + case NetworkStreamDisconnectReason.ConnectionClose: + return UnityTransportNotificationHandler.DisconnectedMessage; + case NetworkStreamDisconnectReason.Timeout: + return UnityTransportNotificationHandler.TimeoutMessage; + case NetworkStreamDisconnectReason.MaxConnectionAttempts: + return UnityTransportNotificationHandler.MaxConnectionAttemptsMessage; + case NetworkStreamDisconnectReason.ClosedByRemote: + return UnityTransportNotificationHandler.ClosedRemoteConnectionMessage; + case NetworkStreamDisconnectReason.BadProtocolVersion: + return UnityTransportNotificationHandler.ProtocolErrorMessage; + case NetworkStreamDisconnectReason.InvalidRpc: + return k_InvalidRpcMessage; + case NetworkStreamDisconnectReason.AuthenticationFailure: + return UnityTransportNotificationHandler.AuthenticationFailureMessage; + case NetworkStreamDisconnectReason.ProtocolError: + return UnityTransportNotificationHandler.ProtocolErrorMessage; + case NetworkStreamDisconnectReason.HandshakeTimeout: + return k_HandshakeTimeoutMessage; + case NetworkStreamDisconnectReason.ApprovalFailure: + return k_ApprovalFailureMessage; + case NetworkStreamDisconnectReason.ApprovalTimeout: + return k_ApprovalTimeoutMessage; + } + return "Unknown reason"; + } + + private DisconnectEvents GetDisconnectEventFromNetworkStreamDisconnectReason(NetworkStreamDisconnectReason reason) + { + switch (reason) + { + case NetworkStreamDisconnectReason.ConnectionClose: + return DisconnectEvents.Disconnected; + case NetworkStreamDisconnectReason.Timeout: + return DisconnectEvents.ProtocolTimeout; + case NetworkStreamDisconnectReason.MaxConnectionAttempts: + return DisconnectEvents.MaxConnectionAttempts; + case NetworkStreamDisconnectReason.ClosedByRemote: + return DisconnectEvents.ClosedByRemote; + case NetworkStreamDisconnectReason.BadProtocolVersion: + return DisconnectEvents.ProtocolError; + case NetworkStreamDisconnectReason.InvalidRpc: + return DisconnectEvents.ProtocolError; + case NetworkStreamDisconnectReason.AuthenticationFailure: + return DisconnectEvents.AuthenticationFailure; + case NetworkStreamDisconnectReason.ProtocolError: + return DisconnectEvents.ProtocolError; + case NetworkStreamDisconnectReason.HandshakeTimeout: + return DisconnectEvents.ProtocolError; + case NetworkStreamDisconnectReason.ApprovalFailure: + return DisconnectEvents.AuthenticationFailure; + case NetworkStreamDisconnectReason.ApprovalTimeout: + return DisconnectEvents.ProtocolTimeout; + } + return DisconnectEvents.Disconnected; + } + + private void OnClientDisconnectFromServer(Connection connection, NetCodeConnectionEvent connectionEvent) + { + SetDisconnectEvent( + GetDisconnectEventFromNetworkStreamDisconnectReason(connectionEvent.DisconnectReason), + GetDisconnectMessageFromNetworkStreamDisconnectReason(connectionEvent.DisconnectReason) + ); + InvokeOnTransportEvent(NetworkEvent.Disconnect, (ulong)connectionEvent.Id.Value, default, m_RealTimeProvider.RealTimeSinceStartup); + } + + private void OnServerClientDisconnected(Connection connection, NetCodeConnectionEvent connectionEvent) + { + InvokeOnTransportEvent(NetworkEvent.Disconnect, (ulong)connectionEvent.Id.Value, default, m_RealTimeProvider.RealTimeSinceStartup); + } + + private void OnClientConnectionEvent(Connection connection, NetCodeConnectionEvent connectionEvent) + { + switch (connectionEvent.State) + { + case ConnectionState.State.Connected: + OnClientConnectedToServer(connection, connectionEvent); + break; + case ConnectionState.State.Disconnected: + OnClientDisconnectFromServer(connection, connectionEvent); + break; + } + } + + private void OnServerConnectionEvent(Connection connection, NetCodeConnectionEvent connectionEvent) + { + switch (connectionEvent.State) + { + case ConnectionState.State.Connected: + OnServerNewClientConnection(connection, connectionEvent); + break; + case ConnectionState.State.Disconnected: + OnServerClientDisconnected(connection, connectionEvent); + break; + } + } + + public override bool StartClient() + { + m_NetworkManager.NetcodeWorld.OnConnectionEvent += OnClientConnectionEvent; + var updateSystem = m_NetworkManager.NetcodeWorld.GetExistingSystemManaged(); + updateSystem.Transport = this; + updateSystem.NetworkManager = m_NetworkManager; + return true; + } + + public override bool StartServer() + { + foreach (var connection in m_NetworkManager.NetcodeWorld.AllConnections) + { + OnServerNewClientConnection(connection, default); + } + + m_NetworkManager.NetcodeWorld.OnConnectionEvent += OnServerConnectionEvent; + var updateSystem = m_NetworkManager.NetcodeWorld.GetExistingSystemManaged(); + updateSystem.Transport = this; + updateSystem.NetworkManager = m_NetworkManager; + return true; + } + + public override void DisconnectRemoteClient(ulong clientId) + { + m_NetworkManager.NetcodeWorld.DisconnectAClient(m_Connections[(int)clientId].Connection); + m_Connections.Remove((int)clientId); + } + + public override void DisconnectLocalClient() + { + // Remove the connection 1st (the world might not be available) + m_Connections.Remove((int)ServerClientId); + + // TODO-FIX-REVIEW-ME: + // This was causing errors to occur upon shutdown during an integration test. + // The cases being trapped for below yield no errors, but there might be some + // form of other underlying issue here: + + if (m_NetworkManager.NetcodeWorld == null || !m_NetworkManager.NetcodeWorld.IsCreated) + { + return; + } + + if (m_NetworkManager.IsServer || m_NetworkManager.NetcodeWorld.IsHost()) + { + if (m_NetworkManager.LogLevel <= LogLevel.Developer) + { + Debug.LogWarning("Host is attempting to shutdown the local client which is not required with a single world host."); + } + return; + } + m_NetworkManager.NetcodeWorld.RequestDisconnectFromServer(); + + } + + public override ulong GetCurrentRtt(ulong clientId) + { + var (transportId, _) = m_NetworkManager.ConnectionManager.ClientIdToTransportId(clientId); + return (ulong)m_Connections[(int)transportId].Connection.RTT; + } + + public override void Initialize(NetworkManager networkManager = null) + { + m_Connections = new Dictionary(); + m_RealTimeProvider = networkManager.RealTimeProvider; + m_NetworkManager = networkManager; + } + + public override void Shutdown() + { + + } + } +} +#endif diff --git a/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs.meta b/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs.meta new file mode 100644 index 0000000000..ace36beccc --- /dev/null +++ b/com.unity.netcode.gameobjects/Runtime/Transports/Unified/UnifiedNetcodeTransport.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9980b4e2027240ceb731e395dc270359 +timeCreated: 1772129541 \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Runtime/Unity.Netcode.Runtime.asmdef b/com.unity.netcode.gameobjects/Runtime/Unity.Netcode.Runtime.asmdef index 3d0e9a58bf..98a2cd6a29 100644 --- a/com.unity.netcode.gameobjects/Runtime/Unity.Netcode.Runtime.asmdef +++ b/com.unity.netcode.gameobjects/Runtime/Unity.Netcode.Runtime.asmdef @@ -13,7 +13,9 @@ "Unity.Networking.Transport", "Unity.Collections", "Unity.Burst", - "Unity.Mathematics" + "Unity.Mathematics", + "Unity.NetCode", + "Unity.Entities" ], "includePlatforms": [], "excludePlatforms": [], @@ -88,6 +90,16 @@ "expression": "6000.5.0a1", "define": "SCENE_MANAGEMENT_SCENE_HANDLE_MUST_USE_ULONG" }, + { + "name": "com.unity.netcode", + "expression": "1.10.1", + "define": "UNIFIED_NETCODE" + }, + { + "name": "com.unity.multiplayer.playmode", + "expression": "0.1.0", + "define": "UNITY_MULTIPLAYER_PLAYMODE" + }, { "name": "Unity", "expression": "[6000.4.0b5,6000.5.0a1)", diff --git a/com.unity.netcode.gameobjects/Tests/Editor/ArithmeticTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/ArithmeticTests.cs index 2791e4ac84..f3f60669ed 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/ArithmeticTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/ArithmeticTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class ArithmeticTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Build/BuildTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Build/BuildTests.cs index 7ee23412bf..2715f33d93 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Build/BuildTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Build/BuildTests.cs @@ -5,7 +5,7 @@ using UnityEditor.Build.Reporting; using UnityEngine; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BuildTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/DisconnectMessageTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/DisconnectMessageTests.cs index e30ceccb1f..d7724be9c4 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/DisconnectMessageTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/DisconnectMessageTests.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using Unity.Collections; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class DisconnectMessageTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/InterpolatorTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/InterpolatorTests.cs index 666183abe6..520633a961 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/InterpolatorTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/InterpolatorTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class InterpolatorTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/DisconnectOnSendTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/DisconnectOnSendTests.cs index a33e7ac6f4..37a711a29c 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/DisconnectOnSendTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/DisconnectOnSendTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using NUnit.Framework; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class DisconnectOnSendTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs index a584ea61e6..aee1f2096d 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs @@ -8,7 +8,7 @@ using UnityEngine; using UnityEngine.TestTools; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class MessageCorruptionTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageReceivingTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageReceivingTests.cs index d77bf4ea72..5a879f1c20 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageReceivingTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageReceivingTests.cs @@ -5,7 +5,7 @@ using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class MessageReceivingTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs index 66898947e6..025b3d54e4 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageRegistrationTests.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using NUnit.Framework; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class MessageRegistrationTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageSendingTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageSendingTests.cs index ae2a1e955e..85049eec56 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageSendingTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageSendingTests.cs @@ -8,7 +8,7 @@ using UnityEngine.TestTools; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class MessageSendingTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageVersioningTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageVersioningTests.cs index 222c08b24b..623fff9227 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageVersioningTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageVersioningTests.cs @@ -3,7 +3,7 @@ using NUnit.Framework; using NUnit.Framework.Internal; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class MessageVersioningTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/NopMessageSender.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/NopMessageSender.cs index 3f5a35b3a3..a22d4c7375 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/NopMessageSender.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/NopMessageSender.cs @@ -1,4 +1,4 @@ -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NopMessageSender : INetworkMessageSender { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/NetworkBehaviourEditorTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/NetworkBehaviourEditorTests.cs index ca7d121ea5..ebf3c43b20 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/NetworkBehaviourEditorTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/NetworkBehaviourEditorTests.cs @@ -4,7 +4,7 @@ using UnityEngine.TestTools; using Object = UnityEngine.Object; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NetworkBehaviourEditorTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/NetworkManagerConfigurationTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/NetworkManagerConfigurationTests.cs index ea4a4b155b..52cdcdbf96 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/NetworkManagerConfigurationTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/NetworkManagerConfigurationTests.cs @@ -1,14 +1,14 @@ using System.Collections.Generic; using System.Text.RegularExpressions; using NUnit.Framework; -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using Unity.Netcode.Transports.UTP; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.TestTools; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NetworkManagerConfigurationTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/NetworkObjectTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/NetworkObjectTests.cs index e4f127564a..fd3bae3cb8 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/NetworkObjectTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/NetworkObjectTests.cs @@ -1,10 +1,10 @@ using System.Text.RegularExpressions; using NUnit.Framework; -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using UnityEngine; using UnityEngine.TestTools; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NetworkObjectTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/NetworkPrefabProcessorTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/NetworkPrefabProcessorTests.cs index f50e502633..0cd1ae134f 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/NetworkPrefabProcessorTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/NetworkPrefabProcessorTests.cs @@ -1,9 +1,9 @@ using NUnit.Framework; -using Unity.Netcode.Editor.Configuration; +using Unity.Netcode.GameObjects.Editor.Configuration; using UnityEditor; using UnityEngine; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NetworkPrefabProcessorTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/NetworkVar/NetworkVarTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/NetworkVar/NetworkVarTests.cs index 77ad69dd62..a411b994b0 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/NetworkVar/NetworkVarTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/NetworkVar/NetworkVarTests.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using UnityEngine; -namespace Unity.Netcode.EditorTests.NetworkVar +namespace Unity.Netcode.GameObjects.EditorTests.NetworkVar { internal class NetworkVarTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs index b6234001c8..f89c6ab3d3 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BaseFastBufferReaderWriterTest.cs @@ -4,7 +4,7 @@ using UnityEngine; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal abstract class BaseFastBufferReaderWriterTest { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitCounterTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitCounterTests.cs index 9200d6b987..10a32a25b5 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitCounterTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitCounterTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BitCounterTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitReaderTests.cs index de83183880..5dbf8f7f39 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitReaderTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using Unity.Collections; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BitReaderTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs index b4a84ff710..dfc3f5caf4 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BitWriterTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using Unity.Collections; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BitWriterTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BufferSerializerTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BufferSerializerTests.cs index b6684ff0e0..7ee8cf5e8f 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BufferSerializerTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BufferSerializerTests.cs @@ -3,7 +3,7 @@ using Unity.Collections; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BufferSerializerTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs index 1bd197997f..30881efff0 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/BytePackerTests.cs @@ -6,7 +6,7 @@ using UnityEngine; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BytePackerTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs index 85aabbb52e..3c955f39aa 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferReaderTests.cs @@ -5,7 +5,7 @@ using UnityEngine; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class FastBufferReaderTests : BaseFastBufferReaderWriterTest { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs index 32e580c66f..f52307d462 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/FastBufferWriterTests.cs @@ -6,7 +6,7 @@ using UnityEngine; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class FastBufferWriterTests : BaseFastBufferReaderWriterTest { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/NetworkSceneHandleTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/NetworkSceneHandleTests.cs index 8be50e5530..cdda8aa5e0 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/NetworkSceneHandleTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/NetworkSceneHandleTests.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using Unity.Collections; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NetworkSceneHandleTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/UserBitReaderAndBitWriterTests_NCCBUG175.cs b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/UserBitReaderAndBitWriterTests_NCCBUG175.cs index f279f4de05..5565a166f6 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Serialization/UserBitReaderAndBitWriterTests_NCCBUG175.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Serialization/UserBitReaderAndBitWriterTests_NCCBUG175.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using Unity.Collections; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class UserBitReaderAndBitWriterTests_NCCBUG175 { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs index fc7cb01d69..7b435523ea 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Timing/ClientNetworkTimeSystemTests.cs @@ -2,7 +2,7 @@ using NUnit.Framework; using UnityEngine; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { /// /// Tests for running a as a client. diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Timing/NetworkTimeTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Timing/NetworkTimeTests.cs index 2a137bde2b..93403ef555 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Timing/NetworkTimeTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Timing/NetworkTimeTests.cs @@ -5,7 +5,7 @@ using UnityEngine; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class NetworkTimeTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs index 8d5edba0a4..4c6560aea5 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Timing/ServerNetworkTimeSystemTests.cs @@ -1,7 +1,7 @@ using NUnit.Framework; using UnityEngine; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class ServerNetworkTimeSystemTests { @@ -31,5 +31,3 @@ public void LocalTimeEqualServerTimeTest() } } - - diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Timing/TimingTestHelper.cs b/com.unity.netcode.gameobjects/Tests/Editor/Timing/TimingTestHelper.cs index e1dee9b3a7..ffa62cc265 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Timing/TimingTestHelper.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Timing/TimingTestHelper.cs @@ -2,7 +2,7 @@ using UnityEngine; using Random = System.Random; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { /// /// Helper functions for timing related tests. Allows to get a set of time steps and simulate time advancing without the need of a full playmode test. @@ -60,4 +60,3 @@ public static void ApplySteps(NetworkTimeSystem timeSystem, NetworkTickSystem ti } } } - diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedReceiveQueueTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedReceiveQueueTests.cs index 97671f906f..26a9ca94cb 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedReceiveQueueTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedReceiveQueueTests.cs @@ -3,7 +3,7 @@ using Unity.Collections; using Unity.Netcode.Transports.UTP; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BatchedReceiveQueueTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedSendQueueTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedSendQueueTests.cs index f27bef95d3..81d65b92f9 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedSendQueueTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Transports/BatchedSendQueueTests.cs @@ -3,7 +3,7 @@ using Unity.Collections; using Unity.Netcode.Transports.UTP; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class BatchedSendQueueTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs index 34f785074a..22e075eec1 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/Transports/UnityTransportTests.cs @@ -4,7 +4,7 @@ using UnityEngine; using UnityEngine.TestTools; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class UnityTransportTests { diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Unity.Netcode.Editor.Tests.asmdef b/com.unity.netcode.gameobjects/Tests/Editor/Unity.Netcode.Editor.Tests.asmdef index 06002bf7d2..a9a05da02b 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/Unity.Netcode.Editor.Tests.asmdef +++ b/com.unity.netcode.gameobjects/Tests/Editor/Unity.Netcode.Editor.Tests.asmdef @@ -1,10 +1,10 @@ { - "name": "Unity.Netcode.Editor.Tests", - "rootNamespace": "Unity.Netcode.EditorTests", + "name": "Unity.Netcode.GameObjects.Editor.Tests", + "rootNamespace": "Unity.Netcode.GameObjects.EditorTests", "references": [ "Unity.Collections", "Unity.Netcode.Runtime", - "Unity.Netcode.Editor", + "Unity.Netcode.GameObjects.Editor", "Unity.Multiplayer.MetricTypes", "Unity.Multiplayer.NetStats", "Unity.Multiplayer.Tools.MetricTypes", @@ -45,10 +45,10 @@ "define": "SCENE_MANAGEMENT_SCENE_HANDLE_NO_INT_CONVERSION" }, { - "name": "Unity", - "expression": "6000.5.0a1", - "define": "SCENE_MANAGEMENT_SCENE_HANDLE_MUST_USE_ULONG" + "name": "Unity", + "expression": "6000.5.0a1", + "define": "SCENE_MANAGEMENT_SCENE_HANDLE_MUST_USE_ULONG" } ], "noEngineReferences": false -} \ No newline at end of file +} diff --git a/com.unity.netcode.gameobjects/Tests/Editor/XXHashTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/XXHashTests.cs index 30fbb52aff..076f2e2325 100644 --- a/com.unity.netcode.gameobjects/Tests/Editor/XXHashTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Editor/XXHashTests.cs @@ -1,6 +1,6 @@ using NUnit.Framework; -namespace Unity.Netcode.EditorTests +namespace Unity.Netcode.GameObjects.EditorTests { internal class XXHashTests { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs new file mode 100644 index 0000000000..b5fd31ae71 --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs @@ -0,0 +1,91 @@ +#if UNIFIED_NETCODE +using System.Collections; +using NUnit.Framework; +using Unity.Netcode.Components; +using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine; +using UnityEngine.TestTools; + + +namespace Unity.Netcode.RuntimeTests +{ + /// + /// Test class that deliberately removes some functionality from NetworkTransform that is conditionally disabled + /// by the presence of ghost objects in the base class. This is to help be certain that the network transform + /// is not doing the work, but that the work is being done by N4E's snapshots. + /// + internal class DoNothingNetworkTransform : NetworkTransform + { + public override void OnNetworkSpawn() + { + // Deliberately left empty + } + + internal override void InternalInitialization(bool isOwnershipChange = false) + { + // Deliberately left empty + } + } + + [TestFixture(HostOrServer.UnifiedHost)] + internal class UnifiedNetworkTransformTest : IntegrationTestWithApproximation + { + protected override int NumberOfClients => 2; + + private GameObject m_Prefab; + private NetworkObject m_Instance; + + public UnifiedNetworkTransformTest(HostOrServer hostOrServer) : base(hostOrServer) + { + } + + protected override bool OnSetVerboseDebug() + { + return false; + } + + protected override IEnumerator OnSetup() + { + // Creates the hybrid prefab + m_Prefab = CreateNetworkObjectPrefab("HybridPrefab"); + m_Prefab.AddComponent(); + return base.OnSetup(); + } + + [UnityTest] + public IEnumerator BasicMovementTest() + { + var authority = GetAuthorityNetworkManager(); + m_Instance = SpawnObject(m_Prefab, m_ServerNetworkManager).GetComponent(); + + // Wait 5 seconds so we will dump any deferred messages if it failed on clients + // when checking to see if it spawned or not on the clients next. + // Enable this to debug deferred + //yield return new WaitForSeconds(5); + + yield return WaitForSpawnedOnAllOrTimeOut(m_Instance); + AssertOnTimeout($"Failed to spawn {m_Instance.name} on all clients!"); + + VerboseDebug("All clients spawned instance!"); + + var originalPos = authority.LocalClient.PlayerObject.transform.position; + var newPos = originalPos + new Vector3(1, 1, 1); + + m_Instance.transform.position = newPos; + + foreach (var client in m_ClientNetworkManagers) + { + Assert.IsTrue(Approximately(originalPos, s_GlobalNetworkObjects[client.LocalClientId][m_Instance.NetworkObjectId].transform.position)); + } + + yield return new WaitForSeconds(1); + + foreach (var client in m_ClientNetworkManagers) + { + Assert.IsTrue(Approximately(newPos, s_GlobalNetworkObjects[client.LocalClientId][m_Instance.NetworkObjectId].transform.position)); + } + VerboseDebug("Test Passed!"); + } + } +} +#endif diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs.meta b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs.meta new file mode 100644 index 0000000000..10d990cfa3 --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkTransform/UnifiedNetworkTransformTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0f26fa7bd5474b3f9947e0813374b50f +timeCreated: 1775078549 \ No newline at end of file diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkUpdateLoopTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkUpdateLoopTests.cs index ecaf3ec792..7f4dba5f16 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkUpdateLoopTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkUpdateLoopTests.cs @@ -1,6 +1,6 @@ using System; using System.Collections; -using System.Linq; +using System.Collections.Generic; using NUnit.Framework; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; @@ -41,9 +41,10 @@ public void RegisterCustomLoopInTheMiddle() PlayerLoop.SetPlayerLoop(curPlayerLoop); NetworkUpdateLoop.UnregisterLoopSystems(); - + var subSystemArray = PlayerLoop.GetCurrentPlayerLoop().subSystemList[0].subSystemList; + var lastType = subSystemArray[subSystemArray.Length - 1].type; // our custom `PlayerLoopSystem` with the type of `NetworkUpdateLoopTests` should still exist - Assert.AreEqual(typeof(NetworkUpdateLoopTests), PlayerLoop.GetCurrentPlayerLoop().subSystemList[0].subSystemList.Last().type); + Assert.AreEqual(typeof(NetworkUpdateLoopTests), lastType); } // replace the current PlayerLoop with the cached PlayerLoop after the test PlayerLoop.SetPlayerLoop(cachedPlayerLoop); @@ -94,7 +95,14 @@ public void UpdateStageSystems() for (int i = 0; i < currentPlayerLoop.subSystemList.Length; i++) { var playerLoopSystem = currentPlayerLoop.subSystemList[i]; - var subsystems = playerLoopSystem.subSystemList.ToList(); + // New behaviour (6000.6.x) + // Some PlayerLoopSystems can evidently now have no sub-system lists. + if (playerLoopSystem.subSystemList == null) + { + // Ignore any PlayerLoopSystem with no sub-system lists. + continue; + } + var subsystems = new List(playerLoopSystem.subSystemList); if (playerLoopSystem.type == typeof(Initialization)) { diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkListTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkListTests.cs index 5f3be93f57..daceeee8b9 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkListTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkVariable/NetworkListTests.cs @@ -15,6 +15,10 @@ namespace Unity.Netcode.RuntimeTests [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Server)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] + [TestFixture(HostOrServer.UnifiedServer)] +#endif internal class NetworkListTests : NetcodeIntegrationTest { protected override int NumberOfClients => 3; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs index a6f4a83275..86ab22beaf 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTest.cs @@ -6,6 +6,9 @@ using System.Runtime.CompilerServices; using System.Text; using NUnit.Framework; +#if UNIFIED_NETCODE +using Unity.NetCode; +#endif using Unity.Netcode.RuntimeTests; using Unity.Netcode.Transports.UTP; using UnityEngine; @@ -223,7 +226,17 @@ public enum HostOrServer /// /// Denotes that distributed authority is being used. /// - DAHost + DAHost, +#if UNIFIED_NETCODE + /// + /// Use N4E-backed hybrid spawning in server mode + /// + UnifiedServer, + /// + /// Use N4E-backed hybrid spawning in host mode + /// + UnifiedHost +#endif } /// @@ -626,6 +639,12 @@ private void InternalOnOneTimeSetup() /// protected virtual IEnumerator OnSetup() { +#if UNIFIED_NETCODE + if (m_AllPrefabsAsHybrid) + { + GhostSpawnManager.RegisterPendingGhost = RegisterPendingGhost; + } +#endif yield return null; } @@ -639,6 +658,12 @@ protected virtual IEnumerator OnSetup() /// protected virtual void OnInlineSetup() { +#if UNIFIED_NETCODE + if (m_AllPrefabsAsHybrid) + { + GhostSpawnManager.RegisterPendingGhost = RegisterPendingGhost; + } +#endif } /// @@ -705,6 +730,24 @@ public IEnumerator SetUp() VerboseDebug($"Exiting {nameof(SetUp)}"); } +#if UNIFIED_NETCODE + private void RegisterPendingGhost(NetworkObject networkObject, ulong networkObjectId) + { + var ghost = networkObject.GetComponent(); + Assert.IsNotNull(ghost, $"[RegisterPendingGhost][NetworkObject-{networkObjectId}] Has no {nameof(GhostAdapter)}!"); + foreach (var networkManager in m_NetworkManagers) + { + // If the world matches, then register the instance with this NetworkManager's spawn manager. + if (networkManager.NetcodeWorld == ghost.World) + { + networkManager.SpawnManager.GhostSpawnManager.RegisterGhostPendingSpawn(networkObject, networkObjectId); + return; + } + } + Debug.LogError($"Did not find a world for NetworkObject-{networkObjectId}!!"); + } +#endif + /// /// Override this to add components or adjustments to the default player prefab /// @@ -824,7 +867,20 @@ protected void CreateServerAndClients(int numberOfClients) { manager.NetworkConfig.PlayerPrefab = m_PlayerPrefab; SetDistributedAuthorityProperties(manager); +#if UNIFIED_NETCODE + foreach (var pendingPrefab in m_PendingPrefabs) + { + var prefab = new NetworkPrefab() + { + Prefab = pendingPrefab + }; + manager.NetworkConfig.Prefabs.Add(prefab); + } +#endif } +#if UNIFIED_NETCODE + m_PendingPrefabs.Clear(); +#endif // Provides opportunity to allow child derived classes to // modify the NetworkManager's configuration before starting. @@ -1613,6 +1669,21 @@ protected IEnumerator CoroutineShutdownAndCleanUp() DestroyNetworkManagers(); } + /// + /// When using hybrid spawning, this handles clean up. + /// + protected void UnifiedCleanup() + { +#if UNIFIED_NETCODE + if (m_AllPrefabsAsHybrid) + { + m_PendingPrefabs.Clear(); + GhostSpawnManager.RegisterPendingGhost = null; + CleanupPrefabReferences(); + } +#endif + } + /// /// Note: For mode /// this is called before ShutdownAndCleanUp. @@ -1620,6 +1691,7 @@ protected IEnumerator CoroutineShutdownAndCleanUp() /// protected virtual IEnumerator OnTearDown() { + UnifiedCleanup(); yield return null; } @@ -1628,6 +1700,7 @@ protected virtual IEnumerator OnTearDown() /// protected virtual void OnInlineTearDown() { + UnifiedCleanup(); } /// @@ -1763,6 +1836,24 @@ protected void DestroySceneNetworkObjects() if (CanDestroyNetworkObject(networkObject)) { +#if UNIFIED_NETCODE + // Handle removing the prefab reference and destroying it + // and then destroying the ghostAdapter prior to destroying + // a hybrid prefab. + var ghostAdapter = networkObject.GetComponent(); + if (ghostAdapter != null) + { + if (ghostAdapter.prefabReference != null) + { + var prefabReference = ghostAdapter.prefabReference; + prefabReference.Prefab = null; + ghostAdapter.prefabReference = null; + Object.Destroy(prefabReference); + } + Object.Destroy(networkObject.gameObject); + continue; + } +#endif // Destroy the GameObject that holds the NetworkObject component Object.DestroyImmediate(networkObject.gameObject); } @@ -2189,6 +2280,10 @@ internal void WaitForMessagesReceivedWithTimeTravel(List messagesInOrder, Assert.True(WaitForConditionOrTimeOutWithTimeTravel(hooks), $"[Messages Not Recieved] {hooks.GetHooksStillWaiting()}"); } +#if UNIFIED_NETCODE + protected bool m_AllPrefabsAsHybrid = false; +#endif + /// /// Creates a basic NetworkObject test prefab, assigns it to a new /// NetworkPrefab entry, and then adds it to the server and client(s) @@ -2198,6 +2293,12 @@ internal void WaitForMessagesReceivedWithTimeTravel(List messagesInOrder, /// The assigned to the new NetworkPrefab entry protected GameObject CreateNetworkObjectPrefab(string baseName) { +#if UNIFIED_NETCODE + if (m_AllPrefabsAsHybrid) + { + return CreateHybridPrefab(baseName, true); + } +#endif var prefabCreateAssertError = $"You can only invoke this method during {nameof(OnServerAndClientsCreated)} " + $"but before {nameof(OnStartedServerAndClients)}!"; var authorityNetworkManager = GetAuthorityNetworkManager(); @@ -2210,6 +2311,100 @@ protected GameObject CreateNetworkObjectPrefab(string baseName) return prefabObject; } +#if UNIFIED_NETCODE + // Pending prefabs declared before NetworkManagers instantiated + private List m_PendingPrefabs = new List(); + protected void CleanupPrefabReferences() + { + foreach (var reference in Object.FindObjectsByType()) + { + Object.Destroy(reference); + } + } + protected GameObject CreateHybridPrefab(string baseName, bool moveToDDOL = true) + { + // Prevent from trying to register/spawn when creating this hybrid prefab + var gameObject = new GameObject + { + name = baseName + }; + + // Order of operations in how these execute is actually important. + // GhostObject should execute 1st. + // NetworkObjectBridge 2nd. + // NetworkObject 3rd. + // NetworkBehaviours will execute in the order they are arranged unless otherwise specified. + + // When adding a Hybrid/Ghost prefab: + // - We disabled the GameObject prior to adding the GhostPrefabReference (so IsPrefab() == true). + // - Add the GhostAdapter and GhostPrefabReference + // - Then set it back to active. + gameObject.SetActive(false); + var adapter = gameObject.AddComponent(); + // Mark the reference as post processing to avoid registering this instance automatically. + GhostPrefabReference.s_IsPostProcessing = true; + adapter.prefabReference = ScriptableObject.CreateInstance(); + adapter.prefabReference.name = "GhostPrefabReference"; + adapter.prefabReference.Prefab = gameObject; + + GhostPrefabReference.s_IsPostProcessing = false; + + // TODO: This might be part of the CreateHybridPrefab parameters + // For now, just use normal interpolation until we get integration + // tests running. + // Once we have validated prediction works and have a working manual + // test, we can circle back to this (possibly make that a sub-task + // with the dependency to prediction manual test). + adapter.SupportedGhostModes = GhostModeMask.Interpolated; + + // Once done with setting up the GhostAdapter, we can set it back to active in the hierarchy + gameObject.SetActive(true); + + // GhostBehaviours that are part of a prefab will not invoke Ghost.InternalAcquireEntityReference + // Add the bridge + var bridge = gameObject.AddComponent(); + + // Now add NGO components + var no = gameObject.AddComponent(); + + // NetworkObject Ghost specific settings + no.HasGhost = true; + no.GhostAdapter = adapter; + no.HadBridge = true; + no.NetworkObjectBridge = bridge; + + // Disable transform synchronization for NetworkObject serialization + // since that is handled by the GhostAdapter. + no.SynchronizeTransform = false; + + // Turn it into a test prefab + NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(no); + if (moveToDDOL) + { + Object.DontDestroyOnLoad(gameObject); + } + var authorityNetworkManager = GetAuthorityNetworkManager(); + if (authorityNetworkManager == null) + { + m_PendingPrefabs.Add(gameObject); + } + else + { + authorityNetworkManager.AddNetworkPrefab(gameObject); + foreach (var clientNetworkManager in m_ClientNetworkManagers) + { + if (clientNetworkManager == authorityNetworkManager) + { + continue; + } + clientNetworkManager.AddNetworkPrefab(gameObject); + } + } + return gameObject; + } +#endif + + /// /// Overloaded method /// @@ -2255,6 +2450,14 @@ internal void SpawnInstanceWithOwnership(NetworkObject networkObjectToSpawn, Net } else { +#if UNIFIED_NETCODE + // TODO-FixMe: NetCode.Netcode.Instance is a singleton and might cause issues + // assigning this. + if (networkObjectToSpawn.HasGhost) + { + NetCode.Netcode.Instance.m_ActiveWorld = m_ServerNetworkManager.NetcodeWorld; + } +#endif networkObjectToSpawn.NetworkManagerOwner = m_ServerNetworkManager; // Required to assure the server does the spawning if (spawnAuthority == m_ServerNetworkManager) { @@ -2417,8 +2620,12 @@ private void InitializeTestConfiguration(NetworkTopologyTypes networkTopologyTyp // Note: For m_DistributedAuthority to be true, the m_NetworkTopologyType must be set to NetworkTopologyTypes.DistributedAuthority hostOrServer = m_DistributedAuthority ? HostOrServer.DAHost : HostOrServer.Host; } +#if UNIFIED_NETCODE + m_UseHost = hostOrServer == HostOrServer.Host || hostOrServer == HostOrServer.DAHost || hostOrServer == HostOrServer.UnifiedHost; + m_AllPrefabsAsHybrid = (hostOrServer == HostOrServer.UnifiedServer || hostOrServer == HostOrServer.UnifiedHost); +#else m_UseHost = hostOrServer == HostOrServer.Host || hostOrServer == HostOrServer.DAHost; - +#endif // If we are using a distributed authority network topology and the environment variable // to use the CMBService is set, then perform the m_UseCmbService check. if (m_DistributedAuthority && GetServiceEnvironmentVariable()) diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs index 32a0f734d7..6e031c6866 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/NetcodeIntegrationTestHelpers.cs @@ -745,18 +745,17 @@ public static GameObject CreateNetworkObjectPrefab(string baseName, NetworkManag Assert.IsFalse(authorityNetworkManager.IsListening, prefabCreateAssertError); var gameObject = CreateNetworkObject(baseName); - var networkPrefab = new NetworkPrefab() { Prefab = gameObject }; // We could refactor this test framework to share a NetworkPrefabList instance, but at this point it's // probably more trouble than it's worth to verify these lists stay in sync across all tests... - authorityNetworkManager.NetworkConfig.Prefabs.Add(networkPrefab); + authorityNetworkManager.AddNetworkPrefab(gameObject); foreach (var clientNetworkManager in clients) { if (clientNetworkManager == authorityNetworkManager) { continue; } - clientNetworkManager.NetworkConfig.Prefabs.Add(new NetworkPrefab() { Prefab = gameObject }); + clientNetworkManager.AddNetworkPrefab(gameObject); } return gameObject; } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Unity.Netcode.Runtime.Tests.asmdef b/com.unity.netcode.gameobjects/Tests/Runtime/Unity.Netcode.Runtime.Tests.asmdef index cde139b07f..86b6bae95f 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Unity.Netcode.Runtime.Tests.asmdef +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Unity.Netcode.Runtime.Tests.asmdef @@ -13,7 +13,9 @@ "Unity.Netcode.TestHelpers.Runtime", "Unity.Mathematics", "UnityEngine.TestRunner", - "UnityEditor.TestRunner" + "UnityEditor.TestRunner", + "Unity.NetCode", + "Unity.Entities" ], "includePlatforms": [], "excludePlatforms": [], @@ -47,6 +49,11 @@ "name": "Unity", "expression": "6000.1.0a1", "define": "HOSTNAME_RESOLUTION_AVAILABLE" + }, + { + "name": "com.unity.netcode", + "expression": "1.10.1", + "define": "UNIFIED_NETCODE" } ], "noEngineReferences": false diff --git a/com.unity.netcode.gameobjects/package.json b/com.unity.netcode.gameobjects/package.json index 04492deaa0..a37383e00d 100644 --- a/com.unity.netcode.gameobjects/package.json +++ b/com.unity.netcode.gameobjects/package.json @@ -2,7 +2,7 @@ "name": "com.unity.netcode.gameobjects", "displayName": "Netcode for GameObjects", "description": "Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.", - "version": "2.11.3", + "version": "3.0.0", "unity": "6000.0", "dependencies": { "com.unity.nuget.mono-cecil": "1.11.4", diff --git a/pvpExceptions.json b/pvpExceptions.json index 83e996338b..e92be2a8a5 100644 --- a/pvpExceptions.json +++ b/pvpExceptions.json @@ -5,9 +5,18 @@ "CHANGELOG.md: line 9: Unreleased section is not allowed for public release" ] }, + "PVP-130-2": { + "errors": [ + "Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef: assembly name does not match filename: Unity.Netcode.GameObjects.Editor.CodeGen", + "Editor/PackageChecker/Unity.Netcode.PackageChecker.Editor.asmdef: assembly name does not match filename: Unity.Netcode.GameObjects.PackageChecker.Editor", + "Editor/Unity.Netcode.Editor.asmdef: assembly name does not match filename: Unity.Netcode.GameObjects.Editor", + "Tests/Editor/Unity.Netcode.Editor.Tests.asmdef: assembly name does not match filename: Unity.Netcode.GameObjects.Editor.Tests" + ] + }, "PVP-132-2": { "errors": [ - "Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef: name of editor assembly should end with '.Editor'" + "Editor/CodeGen/Unity.Netcode.Editor.CodeGen.asmdef: name of editor assembly should end with '.Editor'", + "Editor/PackageChecker/Unity.Netcode.PackageChecker.Editor.asmdef: name of editor assembly should end with '.Editor'" ] } } diff --git a/testproject/Assets/NetCodeConfig.asset b/testproject/Assets/NetCodeConfig.asset new file mode 100644 index 0000000000..f6b1280970 --- /dev/null +++ b/testproject/Assets/NetCodeConfig.asset @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: abd30ee0214cf6a45b2d76765a4615b1, type: 3} + m_Name: NetCodeConfig + m_EditorClassIdentifier: Unity.NetCode::Unity.NetCode.NetCodeConfig + IsGlobalConfig: 1 + EnableClientServerBootstrap: 0 + HostWorldModeSelection: 1 + ClientServerTickRate: + SimulationTickRate: 30 + PredictedFixedStepSimulationTickRatio: 1 + NetworkTickRate: 0 + MaxSimulationStepsPerFrame: 1 + MaxSimulationStepBatchSize: 4 + TargetFrameRateMode: 0 + m_SendSnapshotsForCatchUpTicks: 0 + SnapshotAckMaskCapacity: 4096 + m_ClampPartialTicksThreshold: 5 + HandshakeApprovalTimeoutMS: 5000 + ClientTickRate: + InterpolationTimeNetTicks: 2 + InterpolationTimeMS: 0 + MaxExtrapolationTimeSimTicks: 20 + ForcedInputLatencyTicks: 0 + MaxPredictAheadTimeMS: 500 + NumAdditionalClientPredictedGhostLifetimeTicks: 0 + DefaultClassificationAllowableTickPeriod: 5 + TargetCommandSlack: 2 + NumAdditionalCommandsToSend: 2 + MaxPredictionStepBatchSizeRepeatedTick: 0 + MaxPredictionStepBatchSizeFirstTimeTick: 0 + PredictionLoopUpdateMode: 0 + InterpolationDelayJitterScale: 1.25 + InterpolationDelayMaxDeltaTicksFraction: 0.1 + InterpolationDelayCorrectionFraction: 0.1 + InterpolationTimeScaleMin: 0.85 + InterpolationTimeScaleMax: 1.1 + CommandAgeCorrectionFraction: 0.1 + PredictionTimeScaleMin: 0.9 + PredictionTimeScaleMax: 1.1 + GhostSendSystemData: + DefaultSnapshotPacketSize: 0 + PercentReservedForDespawnMessages: 0.33 + MinSendImportance: 0 + MinDistanceScaledSendImportance: 0 + MaxIterateChunks: 0 + MaxSendChunks: 0 + MaxSendEntities: 0 + m_ForceSingleBaseline: 0 + m_ForcePreSerialize: 0 + m_KeepSnapshotHistoryOnStructuralChange: 1 + m_EnablePerComponentProfiling: 0 + CleanupConnectionStatePerTick: 1 + m_FirstSendImportanceMultiplier: 1 + m_IrrelevantImportanceDownScale: 1 + m_TempStreamSize: 8192 + m_UseCustomSerializer: 0 + ConnectTimeoutMS: 1000 + MaxConnectAttempts: 60 + DisconnectTimeoutMS: 30000 + HeartbeatTimeoutMS: 500 + ReconnectionTimeoutMS: 2000 + ClientSendQueueCapacity: 64 + ClientReceiveQueueCapacity: 64 + ServerSendQueueCapacity: 512 + ServerReceiveQueueCapacity: 512 + MaxMessageSize: 1400 diff --git a/testproject/Legacy/MultiprocessRuntime/readme.md.meta b/testproject/Assets/NetCodeConfig.asset.meta similarity index 52% rename from testproject/Legacy/MultiprocessRuntime/readme.md.meta rename to testproject/Assets/NetCodeConfig.asset.meta index 5ef9bc8c31..222ccfadf4 100644 --- a/testproject/Legacy/MultiprocessRuntime/readme.md.meta +++ b/testproject/Assets/NetCodeConfig.asset.meta @@ -1,7 +1,8 @@ fileFormatVersion: 2 -guid: 39b2fcb99dff6414e8f41b93f4c92b88 -TextScriptImporter: +guid: c547acbddd81d32a0ba5e62ddfc4f4e3 +NativeFormatImporter: externalObjects: {} + mainObjectFileID: 11400000 userData: assetBundleName: assetBundleVariant: diff --git a/testproject/Assets/Scripts/testproject.asmdef b/testproject/Assets/Scripts/testproject.asmdef index 942bddd1f0..34b7976d61 100644 --- a/testproject/Assets/Scripts/testproject.asmdef +++ b/testproject/Assets/Scripts/testproject.asmdef @@ -3,7 +3,7 @@ "rootNamespace": "", "references": [ "Unity.Netcode.Runtime", - "Unity.Netcode.Editor", + "Unity.Netcode.GameObjects.Editor", "Unity.Netcode.Components", "Unity.Netcode.Adapter.UTP", "Unity.Services.Authentication", diff --git a/testproject/Assets/Tests/Editor/TestProject.Editor.Tests.asmdef b/testproject/Assets/Tests/Editor/TestProject.Editor.Tests.asmdef index 51aa4685de..28f8ebe4c2 100644 --- a/testproject/Assets/Tests/Editor/TestProject.Editor.Tests.asmdef +++ b/testproject/Assets/Tests/Editor/TestProject.Editor.Tests.asmdef @@ -3,7 +3,7 @@ "rootNamespace": "TestProject.EditorTests", "references": [ "Unity.Netcode.Runtime", - "Unity.Netcode.Editor", + "Unity.Netcode.GameObjects.Editor", "UnityEngine.TestRunner", "UnityEditor.TestRunner" ], @@ -22,4 +22,4 @@ ], "versionDefines": [], "noEngineReferences": false -} \ No newline at end of file +} diff --git a/testproject/Assets/Tests/Manual/DontDestroyOnLoad/ObjectToNotDestroyBehaviour.cs b/testproject/Assets/Tests/Manual/DontDestroyOnLoad/ObjectToNotDestroyBehaviour.cs index 0ab1566882..4cb30cb930 100644 --- a/testproject/Assets/Tests/Manual/DontDestroyOnLoad/ObjectToNotDestroyBehaviour.cs +++ b/testproject/Assets/Tests/Manual/DontDestroyOnLoad/ObjectToNotDestroyBehaviour.cs @@ -9,9 +9,12 @@ namespace TestProject.ManualTests /// public class ObjectToNotDestroyBehaviour : NetworkBehaviour { + public static bool VerboseDebug; + private bool m_ContinueSendingPing; private uint m_PingCounter; + public uint CurrentPing { get @@ -20,12 +23,19 @@ public uint CurrentPing } } - /// - /// When enabled, we move ourself to the DontDestroyOnLoad scene - /// - private void OnEnable() + private void Log(string msg) + { + if (VerboseDebug) + { + Debug.Log(msg); + } + } + + // Migrate into DDOL during pre-spawn + protected override void OnNetworkPreSpawn(ref NetworkManager networkManager) { DontDestroyOnLoad(this); + base.OnNetworkPreSpawn(ref networkManager); } /// @@ -38,11 +48,11 @@ private void PingUpdateClientRpc(uint pingNumber) { if (IsHost) { - Debug.Log($"Sent ping number ({pingNumber})."); + Log($"Sent ping number ({pingNumber})."); } else if (IsClient) { - Debug.Log($"Receiving ping number ({pingNumber}) from server"); + Log($"Receiving ping number ({pingNumber}) from server"); m_PingCounter = pingNumber; } } diff --git a/testproject/Assets/Tests/Manual/NestedNetworkTransforms/ChildMover.cs b/testproject/Assets/Tests/Manual/NestedNetworkTransforms/ChildMover.cs index f731d6fe95..efaceb4a38 100644 --- a/testproject/Assets/Tests/Manual/NestedNetworkTransforms/ChildMover.cs +++ b/testproject/Assets/Tests/Manual/NestedNetworkTransforms/ChildMover.cs @@ -45,20 +45,11 @@ public void PlayerIsMoving(float movementDirection) } } - private Transform GetRootParentTransform(Transform transform) - { - if (transform.parent != null) - { - return GetRootParentTransform(transform.parent); - } - return transform; - } - protected override void OnNetworkPostSpawn() { if (CanCommitToTransform) { - m_RootParentTransform = GetRootParentTransform(transform); + m_RootParentTransform = transform.root; if (RandomizeScale) { transform.localScale = transform.localScale * Random.Range(0.5f, 1.5f); diff --git a/testproject/Assets/Tests/Runtime/AddressablesTests.cs b/testproject/Assets/Tests/Runtime/AddressablesTests.cs index 4c9151c0f3..fb492b9540 100644 --- a/testproject/Assets/Tests/Runtime/AddressablesTests.cs +++ b/testproject/Assets/Tests/Runtime/AddressablesTests.cs @@ -15,6 +15,10 @@ namespace TestProject.RuntimeTests [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] + [TestFixture(HostOrServer.UnifiedServer)] +#endif public class AddressablesTests : NetcodeIntegrationTest { protected override int NumberOfClients => 2; diff --git a/testproject/Assets/Tests/Runtime/AnalyticsTests.cs b/testproject/Assets/Tests/Runtime/AnalyticsTests.cs index a841333900..975a01ab7b 100644 --- a/testproject/Assets/Tests/Runtime/AnalyticsTests.cs +++ b/testproject/Assets/Tests/Runtime/AnalyticsTests.cs @@ -2,7 +2,7 @@ using System.Collections; using NUnit.Framework; using Unity.Netcode; -using Unity.Netcode.Editor; +using Unity.Netcode.GameObjects.Editor; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine.TestTools; @@ -22,7 +22,7 @@ internal class AnalyticsTests : NetcodeIntegrationTest protected override IEnumerator OnSetup() { NetcodeAnalytics.EnableIntegrationTestAnalytics = true; - m_NetcodeAnalytics = Unity.Netcode.Editor.NetworkManagerHelper.Singleton.NetcodeAnalytics; + m_NetcodeAnalytics = Unity.Netcode.GameObjects.Editor.NetworkManagerHelper.Singleton.NetcodeAnalytics; yield return base.OnSetup(); } diff --git a/testproject/Assets/Tests/Runtime/DontDestroyOnLoadTests.cs b/testproject/Assets/Tests/Runtime/DontDestroyOnLoadTests.cs index 105265b08f..2d841049ca 100644 --- a/testproject/Assets/Tests/Runtime/DontDestroyOnLoadTests.cs +++ b/testproject/Assets/Tests/Runtime/DontDestroyOnLoadTests.cs @@ -11,6 +11,9 @@ namespace TestProject.RuntimeTests { [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.DAHost)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] +#endif public class DontDestroyOnLoadTests : NetcodeIntegrationTest { private const int k_ClientsToConnect = 4; diff --git a/testproject/Assets/Tests/Runtime/NetworkBehaviourSessionSynchronized.cs b/testproject/Assets/Tests/Runtime/NetworkBehaviourSessionSynchronized.cs index 771a90b9b8..0582211d0f 100644 --- a/testproject/Assets/Tests/Runtime/NetworkBehaviourSessionSynchronized.cs +++ b/testproject/Assets/Tests/Runtime/NetworkBehaviourSessionSynchronized.cs @@ -9,6 +9,9 @@ namespace TestProject.RuntimeTests { [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.DAHost)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] +#endif public class NetworkBehaviourSessionSynchronized : NetcodeIntegrationTest { private const string k_SceneToLoad = "SessionSynchronize"; diff --git a/testproject/Assets/Tests/Runtime/NetworkObjectDestroyWithSceneTests.cs b/testproject/Assets/Tests/Runtime/NetworkObjectDestroyWithSceneTests.cs index ad5fe5e1b0..57a2660601 100644 --- a/testproject/Assets/Tests/Runtime/NetworkObjectDestroyWithSceneTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkObjectDestroyWithSceneTests.cs @@ -10,6 +10,9 @@ namespace TestProject.RuntimeTests { [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] +#endif internal class NetworkObjectDestroyWithSceneTests : NetcodeIntegrationTest { private const string k_SceneToLoad = "EmptyScene"; @@ -98,7 +101,7 @@ public IEnumerator DestroyWithScene() // Depending on network topology, spawn the object with the appropriate owner. var owner = m_DistributedAuthority ? m_NotSessionOwner : m_SessionOwner; - m_SpawnedInstance = SpawnObject(m_TestPrefab.gameObject, m_NotSessionOwner, true).GetComponent(); + m_SpawnedInstance = SpawnObject(m_TestPrefab.gameObject, owner, true).GetComponent(); var instanceName = m_SpawnedInstance.name; yield return WaitForConditionOrTimeOut(() => ObjectSpawnedOnAllNetworkManagers(true)); diff --git a/testproject/Assets/Tests/Runtime/NetworkObjectSpawning.cs b/testproject/Assets/Tests/Runtime/NetworkObjectSpawning.cs index 6ed56b04ed..1b1f0e8c32 100644 --- a/testproject/Assets/Tests/Runtime/NetworkObjectSpawning.cs +++ b/testproject/Assets/Tests/Runtime/NetworkObjectSpawning.cs @@ -9,8 +9,11 @@ namespace TestProject.RuntimeTests { - [TestFixture(NetworkTopologyTypes.ClientServer)] - [TestFixture(NetworkTopologyTypes.DistributedAuthority)] + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.UnifiedHost)] +#endif + [TestFixture(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost)] internal class NetworkObjectSpawning : NetcodeIntegrationTest { private const string k_SceneToLoad = "NetworkObjectSpawnerTest"; @@ -27,7 +30,7 @@ protected override bool UseCMBService() return false; } - public NetworkObjectSpawning(NetworkTopologyTypes networkTopology) : base(networkTopology) { } + public NetworkObjectSpawning(NetworkTopologyTypes networkTopology, HostOrServer hostOrServer) : base(networkTopology, hostOrServer) { } protected override IEnumerator OnSetup() diff --git a/testproject/Assets/Tests/Runtime/NetworkSceneManager/SceneEventDataTests.cs b/testproject/Assets/Tests/Runtime/NetworkSceneManager/SceneEventDataTests.cs index a37a3244d2..f1bdc67c66 100644 --- a/testproject/Assets/Tests/Runtime/NetworkSceneManager/SceneEventDataTests.cs +++ b/testproject/Assets/Tests/Runtime/NetworkSceneManager/SceneEventDataTests.cs @@ -38,12 +38,10 @@ public IEnumerator FastReaderAllocationTest() var networkManager = networkManagerGameObject.AddComponent(); var unityTransport = networkManagerGameObject.AddComponent(); - var prefabs = ScriptableObject.CreateInstance(); - prefabs.Add(new NetworkPrefab()); networkManager.NetworkConfig = new NetworkConfig() { ConnectionApproval = false, - Prefabs = new NetworkPrefabs { NetworkPrefabsLists = new List { prefabs } }, + Prefabs = new NetworkPrefabs { NetworkPrefabsLists = new List { } }, NetworkTransport = unityTransport }; diff --git a/testproject/Assets/Tests/Runtime/OnNetworkSpawnExceptionTests.cs b/testproject/Assets/Tests/Runtime/OnNetworkSpawnExceptionTests.cs index ea81ac8409..224460e8c8 100644 --- a/testproject/Assets/Tests/Runtime/OnNetworkSpawnExceptionTests.cs +++ b/testproject/Assets/Tests/Runtime/OnNetworkSpawnExceptionTests.cs @@ -2,11 +2,12 @@ using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; +using NUnit.Framework; using Unity.Netcode; using Unity.Netcode.TestHelpers.Runtime; using UnityEngine; -using UnityEngine.Assertions; using UnityEngine.TestTools; +using Assert = UnityEngine.Assertions.Assert; using Random = UnityEngine.Random; namespace TestProject.RuntimeTests @@ -82,6 +83,10 @@ public override void OnNetworkDespawn() } } + [TestFixture(HostOrServer.Server)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedServer)] +#endif public class OnNetworkSpawnExceptionTests : NetcodeIntegrationTest { protected override int NumberOfClients => 1; @@ -101,6 +106,11 @@ protected override bool UseCMBService() return false; } + public OnNetworkSpawnExceptionTests(HostOrServer hostOrServer) : base(hostOrServer) + { + + } + [UnityTest] public IEnumerator WhenOnNetworkSpawnThrowsException_FutureOnNetworkSpawnsAreNotPrevented() { @@ -238,7 +248,6 @@ public IEnumerator WhenOnNetworkDespawnThrowsException_FutureOnNetworkDespawnsAr protected override IEnumerator OnSetup() { - m_UseHost = false; OnNetworkSpawnThrowsExceptionComponent.NumClientSpawns = 0; OnNetworkSpawnThrowsExceptionComponent.NumServerSpawns = 0; OnNetworkSpawnNoExceptionComponent.NumClientSpawns = 0; diff --git a/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs b/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs index d0f7e294cb..9fb4c7a603 100644 --- a/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs +++ b/testproject/Assets/Tests/Runtime/PrefabExtendedTests.cs @@ -13,8 +13,12 @@ namespace TestProject.RuntimeTests { // DAMODE-TODO: When scene management is working in distributed authority mode we need to update this test - [TestFixture(SceneManagementTypes.SceneManagementEnabled)] - [TestFixture(SceneManagementTypes.SceneManagementDisabled)] + [TestFixture(SceneManagementTypes.SceneManagementEnabled, HostOrServer.Host)] + [TestFixture(SceneManagementTypes.SceneManagementDisabled, HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(SceneManagementTypes.SceneManagementEnabled, HostOrServer.UnifiedHost)] + [TestFixture(SceneManagementTypes.SceneManagementDisabled, HostOrServer.UnifiedHost)] +#endif public class PrefabExtendedTests : NetcodeIntegrationTest { private const string k_PrefabTestScene = "PrefabTestScene"; @@ -42,7 +46,7 @@ protected override bool UseCMBService() return false; } - public PrefabExtendedTests(SceneManagementTypes sceneManagementType) + public PrefabExtendedTests(SceneManagementTypes sceneManagementType, HostOrServer hostOrServer) : base(hostOrServer) { m_SceneManagementEnabled = sceneManagementType == SceneManagementTypes.SceneManagementEnabled; } diff --git a/testproject/Assets/Tests/Runtime/RespawnInSceneObjectsAfterShutdown.cs b/testproject/Assets/Tests/Runtime/RespawnInSceneObjectsAfterShutdown.cs index 7dbdc2635f..857c14ee6f 100644 --- a/testproject/Assets/Tests/Runtime/RespawnInSceneObjectsAfterShutdown.cs +++ b/testproject/Assets/Tests/Runtime/RespawnInSceneObjectsAfterShutdown.cs @@ -8,8 +8,11 @@ namespace TestProject.RuntimeTests { - [TestFixture(NetworkTopologyTypes.DistributedAuthority)] - [TestFixture(NetworkTopologyTypes.ClientServer)] + [TestFixture(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost)] + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.UnifiedHost)] +#endif public class RespawnInSceneObjectsAfterShutdown : NetcodeIntegrationTest { public const string SceneToLoad = "InSceneNetworkObject"; @@ -23,7 +26,7 @@ protected override bool UseCMBService() return false; } - public RespawnInSceneObjectsAfterShutdown(NetworkTopologyTypes networkTopologyType) : base(networkTopologyType) { } + public RespawnInSceneObjectsAfterShutdown(NetworkTopologyTypes networkTopologyType, HostOrServer hostOrServer) : base(networkTopologyType, hostOrServer) { } protected override void OnOneTimeSetup() { diff --git a/testproject/Assets/Tests/Runtime/RpcObserverTests.cs b/testproject/Assets/Tests/Runtime/RpcObserverTests.cs index b71c7e03dd..3ce2642a6c 100644 --- a/testproject/Assets/Tests/Runtime/RpcObserverTests.cs +++ b/testproject/Assets/Tests/Runtime/RpcObserverTests.cs @@ -18,6 +18,10 @@ namespace TestProject.RuntimeTests [TestFixture(HostOrServer.DAHost)] [TestFixture(HostOrServer.Host)] [TestFixture(HostOrServer.Server)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] + [TestFixture(HostOrServer.UnifiedServer)] +#endif public class RpcObserverTests : NetcodeIntegrationTest { protected override int NumberOfClients => 9; @@ -155,6 +159,12 @@ private IEnumerator RunRpcObserverTest(List nonObservers) [UnityTest] public IEnumerator DespawnRespawnObserverTest() { +#if UNIFIED_NETCODE + if (m_AllPrefabsAsHybrid) + { + Assert.Ignore("Hybrid spawning does not support despawn-without-destroy."); + } +#endif var nonObservers = new List(); m_ServerRpcObserverObject.ResetTest(); // Wait for all clients to report they have spawned an instance of our test prefab diff --git a/testproject/Assets/Tests/Runtime/RpcTestsAutomated.cs b/testproject/Assets/Tests/Runtime/RpcTestsAutomated.cs index 228bfbfdd5..d37a3379ad 100644 --- a/testproject/Assets/Tests/Runtime/RpcTestsAutomated.cs +++ b/testproject/Assets/Tests/Runtime/RpcTestsAutomated.cs @@ -10,6 +10,10 @@ namespace TestProject.RuntimeTests { + [TestFixture(HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] +#endif public class RpcTestsAutomated : NetcodeIntegrationTest { private bool m_TimedOut; @@ -23,6 +27,11 @@ protected override bool UseCMBService() return false; } + public RpcTestsAutomated(HostOrServer hostOrServer) : base(hostOrServer) + { + + } + protected override NetworkManagerInstatiationMode OnSetIntegrationTestMode() { return NetworkManagerInstatiationMode.DoNotCreate; diff --git a/testproject/Assets/Tests/Runtime/RpcUserSerializableTypesTest.cs b/testproject/Assets/Tests/Runtime/RpcUserSerializableTypesTest.cs index ae10ea60c9..5a92112f32 100644 --- a/testproject/Assets/Tests/Runtime/RpcUserSerializableTypesTest.cs +++ b/testproject/Assets/Tests/Runtime/RpcUserSerializableTypesTest.cs @@ -49,8 +49,11 @@ public void NetworkSerialize(BufferSerializer } - [TestFixture(NetworkTopologyTypes.DistributedAuthority)] - [TestFixture(NetworkTopologyTypes.ClientServer)] + [TestFixture(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost)] + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.UnifiedHost)] +#endif public class RpcUserSerializableTypesTest : NetcodeIntegrationTest { private UserSerializableClass m_UserSerializableClass; @@ -88,7 +91,7 @@ protected override bool UseCMBService() return false; } - public RpcUserSerializableTypesTest(NetworkTopologyTypes networkTopologyType) : base(networkTopologyType) { } + public RpcUserSerializableTypesTest(NetworkTopologyTypes networkTopologyType, HostOrServer hostOrServer) : base(networkTopologyType, hostOrServer) { } protected override NetworkManagerInstatiationMode OnSetIntegrationTestMode() { diff --git a/testproject/Assets/Tests/Runtime/SceneObjectsNotDestroyedOnShutdownTest.cs b/testproject/Assets/Tests/Runtime/SceneObjectsNotDestroyedOnShutdownTest.cs index f82b7ed400..3fcc9feae6 100644 --- a/testproject/Assets/Tests/Runtime/SceneObjectsNotDestroyedOnShutdownTest.cs +++ b/testproject/Assets/Tests/Runtime/SceneObjectsNotDestroyedOnShutdownTest.cs @@ -9,8 +9,11 @@ namespace TestProject.RuntimeTests { - [TestFixture(NetworkTopologyTypes.ClientServer)] - [TestFixture(NetworkTopologyTypes.DistributedAuthority)] + [TestFixture(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost)] + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.UnifiedHost)] +#endif public class SceneObjectsNotDestroyedOnShutdownTest : NetcodeIntegrationTest { protected override int NumberOfClients => 0; @@ -20,7 +23,7 @@ public class SceneObjectsNotDestroyedOnShutdownTest : NetcodeIntegrationTest private Scene m_TestScene; private WaitForSeconds m_DefaultWaitForTick = new(1.0f / 30); - public SceneObjectsNotDestroyedOnShutdownTest(NetworkTopologyTypes topology) : base(topology) { } + public SceneObjectsNotDestroyedOnShutdownTest(NetworkTopologyTypes topology, HostOrServer hostOrServer) : base(topology, hostOrServer) { } [UnityTest] public IEnumerator SceneObjectsNotDestroyedOnShutdown() diff --git a/testproject/Assets/Tests/Runtime/SenderIdTests.cs b/testproject/Assets/Tests/Runtime/SenderIdTests.cs index 92ebf2f4a1..768a51ae53 100644 --- a/testproject/Assets/Tests/Runtime/SenderIdTests.cs +++ b/testproject/Assets/Tests/Runtime/SenderIdTests.cs @@ -10,6 +10,10 @@ namespace TestProject.RuntimeTests { + [TestFixture(HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(HostOrServer.UnifiedHost)] +#endif public class SenderIdTests : NetcodeIntegrationTest { protected override int NumberOfClients => 2; @@ -17,6 +21,8 @@ public class SenderIdTests : NetcodeIntegrationTest private NetworkManager FirstClient => m_ClientNetworkManagers[0]; private NetworkManager SecondClient => m_ClientNetworkManagers[1]; + public SenderIdTests(HostOrServer hostOrServer) : base(hostOrServer) { } + [UnityTest] public IEnumerator WhenSendingMessageFromServerToClient_SenderIdIsCorrect() { diff --git a/testproject/Assets/Tests/Runtime/ServerDisconnectsClientTest.cs b/testproject/Assets/Tests/Runtime/ServerDisconnectsClientTest.cs index c16cceda66..cd730b2099 100644 --- a/testproject/Assets/Tests/Runtime/ServerDisconnectsClientTest.cs +++ b/testproject/Assets/Tests/Runtime/ServerDisconnectsClientTest.cs @@ -9,8 +9,11 @@ namespace TestProject.RuntimeTests { - [TestFixture(NetworkTopologyTypes.DistributedAuthority)] - [TestFixture(NetworkTopologyTypes.ClientServer)] + [TestFixture(NetworkTopologyTypes.DistributedAuthority, HostOrServer.DAHost)] + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.Host)] +#if UNIFIED_NETCODE + [TestFixture(NetworkTopologyTypes.ClientServer, HostOrServer.UnifiedHost)] +#endif public class ServerDisconnectsClientTest : NetcodeIntegrationTest { protected override int NumberOfClients => 1; @@ -21,7 +24,7 @@ protected override bool UseCMBService() return false; } - public ServerDisconnectsClientTest(NetworkTopologyTypes networkTopologyType) : base(networkTopologyType) { } + public ServerDisconnectsClientTest(NetworkTopologyTypes networkTopologyType, HostOrServer hostOrServer) : base(networkTopologyType, hostOrServer) { } protected override void OnCreatePlayerPrefab() { diff --git a/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef b/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef index d94d369852..51b61982a5 100644 --- a/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef +++ b/testproject/Assets/Tests/Runtime/TestProject.Runtime.Tests.asmdef @@ -4,7 +4,7 @@ "references": [ "Unity.Netcode.Runtime", "Unity.Netcode.RuntimeTests", - "Unity.Netcode.Editor", + "Unity.Netcode.GameObjects.Editor", "TestProject.ManualTests", "TestProject", "Unity.Addressables", @@ -33,7 +33,12 @@ "name": "com.unity.addressables", "expression": "", "define": "TESTPROJECT_USE_ADDRESSABLES" + }, + { + "name": "com.unity.netcode", + "expression": "1.10.1", + "define": "UNIFIED_NETCODE" } ], "noEngineReferences": false -} \ No newline at end of file +} diff --git a/testproject/Legacy/MultiprocessRuntime/BaseMultiprocessTests.cs b/testproject/Legacy/MultiprocessRuntime/BaseMultiprocessTests.cs deleted file mode 100644 index 8e853a0b19..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/BaseMultiprocessTests.cs +++ /dev/null @@ -1,225 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using NUnit.Framework; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.TestTools; -using Object = UnityEngine.Object; -using Unity.Netcode.Transports.UTP; - - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class MultiprocessTestsAttribute : CategoryAttribute - { - public const string MultiprocessCategoryName = "Multiprocess"; - public MultiprocessTestsAttribute() : base(MultiprocessCategoryName) { } - } - - [MultiprocessTests] - public abstract class BaseMultiprocessTests - { - protected string[] platformList { get; set; } - - protected int GetWorkerCount() - { - platformList = MultiprocessOrchestration.GetRemotePlatformList(); - return platformList == null ? WorkerCount : platformList.Length; - } - protected bool m_LaunchRemotely; - private bool m_HasSceneLoaded = false; - // TODO: Remove UTR check once we have Multiprocess tests fully working - protected bool IgnoreMultiprocessTests => MultiprocessOrchestration.ShouldIgnoreUTRTests(); - - protected virtual bool IsPerformanceTest => false; - - /// - /// Implement this to specify the amount of workers to spawn from your main test runner - /// Note: If using remote workers, the woorker count will come from the environment variable - /// - protected abstract int WorkerCount { get; } - - private const string k_FirstPartOfTestRunnerSceneName = "InitTestScene"; - - // Since we want to additively load our BuildMultiprocessTestPlayer.MainSceneName - // We want to keep a reference to the - private Scene m_OriginalActiveScene; - - [OneTimeSetUp] - public virtual void SetupTestSuite() - { - MultiprocessLogger.Log("Running SetupTestSuite - OneTimeSetup"); - MultiprocessOrchestration.IsPerformanceTest = IsPerformanceTest; - if (IgnoreMultiprocessTests) - { - Assert.Ignore("Ignoring tests under UTR. For testing, include the \"-bypassIgnoreUTR\" command line parameter."); - } - - if (IsPerformanceTest) - { - Assert.Ignore("Performance tests should be run from remote test execution on device (this can be ran using the \"run selected tests (your platform)\" button"); - } - MultiprocessLogger.Log($"Currently active scene {SceneManager.GetActiveScene().name}"); - var currentlyActiveScene = SceneManager.GetActiveScene(); - - // Just adding a sanity check here to help with debugging in the event that SetupTestSuite is - // being invoked and the TestRunner scene has not been set to the active scene yet. - // This could mean that TeardownSuite wasn't called or SceneManager is not finished unloading - // or could not unload the BuildMultiprocessTestPlayer.MainSceneName. - if (!currentlyActiveScene.name.StartsWith(k_FirstPartOfTestRunnerSceneName)) - { - MultiprocessLogger.LogError( - $"Expected the currently active scene to begin with ({k_FirstPartOfTestRunnerSceneName}) but" + - $" currently active scene is {currentlyActiveScene.name}"); - } - m_OriginalActiveScene = currentlyActiveScene; - - SceneManager.sceneLoaded += OnSceneLoaded; - SceneManager.LoadScene(BuildMultiprocessTestPlayer.MainSceneName, LoadSceneMode.Additive); - } - - private void OnSceneLoaded(Scene scene, LoadSceneMode mode) - { - SceneManager.sceneLoaded -= OnSceneLoaded; - if (scene.name == BuildMultiprocessTestPlayer.MainSceneName) - { - SceneManager.SetActiveScene(scene); - } - - var transport = NetworkManager.Singleton.NetworkConfig.NetworkTransport; - switch (transport) - { - case UnityTransport unityTransport: - unityTransport.ConnectionData.ServerListenAddress = "0.0.0.0"; - MultiprocessLogger.Log($"Setting unityTransport.ConnectionData.Port {unityTransport.ConnectionData.ServerListenAddress}"); - break; - default: - MultiprocessLogger.LogError($"The transport {transport} has no case"); - break; - } - - MultiprocessLogger.Log("Starting Host"); - NetworkManager.Singleton.StartHost(); - - // Use scene verification to make sure we don't try to get clients to synchronize the TestRunner scene - NetworkManager.Singleton.SceneManager.VerifySceneBeforeLoading = VerifySceneIsValidForClientsToLoad; - - m_HasSceneLoaded = true; - } - - /// - /// We want to exclude the TestRunner scene on the host-server side so it won't try to tell clients to - /// synchronize to this scene when they connect (host-server side only for multiprocess) - /// - /// true - scene is fine to synchronize/inform clients to load and false - scene should not be loaded by clients - private bool VerifySceneIsValidForClientsToLoad(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode) - { - if (sceneName.StartsWith(k_FirstPartOfTestRunnerSceneName)) - { - return false; - } - return true; - } - - [UnitySetUp] - public virtual IEnumerator Setup() - { - yield return new WaitUntil(() => NetworkManager.Singleton != null); - yield return new WaitUntil(() => NetworkManager.Singleton.IsServer); - yield return new WaitUntil(() => NetworkManager.Singleton.IsListening); - yield return new WaitUntil(() => m_HasSceneLoaded == true); - var startTime = Time.time; - m_LaunchRemotely = MultiprocessOrchestration.IsRemoteOperationEnabled(); - - MultiprocessLogger.Log($"Active Worker Count is {MultiprocessOrchestration.ActiveWorkerCount()}" + - $" and connected client count is {NetworkManager.Singleton.ConnectedClients.Count} " + - $" and WorkerCount is {GetWorkerCount()} " + - $" and LaunchRemotely is {m_LaunchRemotely}"); - if (MultiprocessOrchestration.ActiveWorkerCount() + 1 < NetworkManager.Singleton.ConnectedClients.Count) - { - MultiprocessLogger.Log("Is this a bad state?"); - } - - // Moved this out of OnSceneLoaded as OnSceneLoaded is a callback from the SceneManager and just wanted to avoid creating - // processes from within the same callstack/context as the SceneManager. This will instantiate up to the WorkerCount and - // then any subsequent calls to Setup if there are already workers it will skip this step - if (!m_LaunchRemotely) - { - if (NetworkManager.Singleton.ConnectedClients.Count - 1 < WorkerCount) - { - var numProcessesToCreate = WorkerCount - (NetworkManager.Singleton.ConnectedClients.Count - 1); - for (int i = 1; i <= numProcessesToCreate; i++) - { - MultiprocessLogger.Log($"Spawning testplayer {i} since connected client count is {NetworkManager.Singleton.ConnectedClients.Count} is less than {WorkerCount} and Number of spawned external players is {MultiprocessOrchestration.ActiveWorkerCount()} "); - string logPath = MultiprocessOrchestration.StartWorkerNode(); // will automatically start built player as clients - MultiprocessLogger.Log($"logPath to new process is {logPath}"); - MultiprocessLogger.Log($"Active Worker Count {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}"); - } - } - } - else - { - var launchProcessList = new List(); - if (NetworkManager.Singleton.ConnectedClients.Count - 1 < GetWorkerCount()) - { - var machines = MultiprocessOrchestration.GetRemoteMachineList(); - foreach (var machine in machines) - { - MultiprocessLogger.Log($"Would launch on {machine.Name} too get worker count to {GetWorkerCount()} from {NetworkManager.Singleton.ConnectedClients.Count - 1}"); - launchProcessList.Add(MultiprocessOrchestration.StartWorkersOnRemoteNodes(machine)); - } - } - } - - var timeOutTime = Time.realtimeSinceStartup + TestCoordinator.MaxWaitTimeoutSec; - while (NetworkManager.Singleton.ConnectedClients.Count <= WorkerCount) - { - yield return new WaitForSeconds(0.2f); - - if (Time.realtimeSinceStartup > timeOutTime) - { - throw new Exception($" {DateTime.Now:T} Waiting too long to see clients to connect, got {NetworkManager.Singleton.ConnectedClients.Count - 1} clients, and ActiveWorkerCount: {MultiprocessOrchestration.ActiveWorkerCount()} but was expecting {WorkerCount}, failing"); - } - } - TestCoordinator.Instance.KeepAliveClientRpc(); - MultiprocessLogger.Log($"Active Worker Count {MultiprocessOrchestration.ActiveWorkerCount()} and connected client count is {NetworkManager.Singleton.ConnectedClients.Count}"); - } - - - [TearDown] - public virtual void Teardown() - { - MultiprocessLogger.Log("Running teardown"); - if (!IgnoreMultiprocessTests) - { - TestCoordinator.Instance.TestRunTeardown(); - } - } - - [OneTimeTearDown] - public virtual void TeardownSuite() - { - MultiprocessLogger.Log($"TeardownSuite"); - if (!IgnoreMultiprocessTests) - { - MultiprocessLogger.Log($"TeardownSuite - ShutdownAllProcesses"); - MultiprocessOrchestration.ShutdownAllProcesses(); - MultiprocessLogger.Log($"TeardownSuite - NetworkManager.Singleton.Shutdown"); - NetworkManager.Singleton.Shutdown(); - Object.Destroy(NetworkManager.Singleton.gameObject); // making sure we clear everything before reloading our scene - MultiprocessLogger.Log($"Currently active scene {SceneManager.GetActiveScene().name}"); - MultiprocessLogger.Log($"m_OriginalActiveScene.IsValid {m_OriginalActiveScene.IsValid()}"); - if (m_OriginalActiveScene.IsValid()) - { - SceneManager.SetActiveScene(m_OriginalActiveScene); - } - MultiprocessLogger.Log($"TeardownSuite - Unload {BuildMultiprocessTestPlayer.MainSceneName}"); - SceneManager.UnloadSceneAsync(BuildMultiprocessTestPlayer.MainSceneName); - MultiprocessLogger.Log($"TeardownSuite - Unload {BuildMultiprocessTestPlayer.MainSceneName}"); - } - } - } -} - diff --git a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContext.cs b/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContext.cs deleted file mode 100644 index f09dc0f412..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContext.cs +++ /dev/null @@ -1,293 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using NUnit.Framework; -using NUnit.Framework.Interfaces; -using Unity.Netcode; -using Unity.Netcode.MultiprocessRuntimeTests; -using UnityEngine; -using UnityEngine.TestTools; -using Debug = UnityEngine.Debug; - -/// -/// Allows for context based delegate execution. -/// Can specify where you want that lambda executed (client side? server side?) and it'll automatically wait for the end -/// of a clientRPC server side and vice versa. -/// todo this could be used as an in-game tool too? for protocols that require a lot of back and forth? -/// -public class ExecuteStepInContext : CustomYieldInstruction -{ - public enum StepExecutionContext - { - Server, - Clients - } - - [AttributeUsage(AttributeTargets.Method)] - public class MultiprocessContextBasedTestAttribute : NUnitAttribute, IOuterUnityTestAction - { - public IEnumerator BeforeTest(ITest test) - { - yield return new WaitUntil(() => TestCoordinator.Instance != null && HasRegistered); - } - - public IEnumerator AfterTest(ITest test) - { - yield break; - } - } - - private StepExecutionContext m_ActionContext; - private Action m_StepToExecute; - private string m_CurrentActionId; - - // as a remote worker, I store all available actions so I can execute them when triggered from RPCs - public static Dictionary AllActions = new Dictionary(); - private static Dictionary s_MethodIdCounter = new Dictionary(); - - private NetworkManager m_NetworkManager; - private bool m_IsRegistering; - private List> m_ClientIsFinishedChecks = new List>(); - private Func m_AdditionalIsFinishedWaiter; - - private bool m_WaitMultipleUpdates; - private bool m_IgnoreTimeoutException; - - private float m_StartTime; - private bool isTimingOut => Time.time - m_StartTime > TestCoordinator.MaxWaitTimeoutSec; - private bool shouldExecuteLocally => (m_ActionContext == StepExecutionContext.Server && m_NetworkManager.IsServer) || (m_ActionContext == StepExecutionContext.Clients && !m_NetworkManager.IsServer); - - public static bool IsRegistering; - public static bool HasRegistered; - private static List s_AllClientTestInstances = new List(); // to keep an instance for each tests, so captured context in each step is kept - - /// - /// This MUST be called at the beginning of each test in order to use context based steps. - /// Assumes this is called from same callsite as ExecuteStepInContext (and assumes this is called from IEnumerator, the method full name is unique - /// even with the same method name and different parameters). - /// This relies on the name to be unique for each generated IEnumerator state machines - /// - public static void InitializeContextSteps() - { - var callerMethod = new StackFrame(1).GetMethod(); - var methodIdentifier = GetMethodIdentifier(callerMethod); // since this is called from IEnumerator, this should be a generated class, making it unique - s_MethodIdCounter[methodIdentifier] = 0; - } - - private static string GetMethodIdentifier(MethodBase callerMethod) - { - return callerMethod.DeclaringType.FullName; - } - - internal static void InitializeAllSteps() - { - MultiprocessLogger.Log("InitializeAllSteps - Start"); - // registering magically all context based steps - IsRegistering = true; - var registeredMethods = typeof(TestCoordinator).Assembly.GetTypes().SelectMany(t => t.GetMethods()) - .Where(m => m.GetCustomAttributes(typeof(MultiprocessContextBasedTestAttribute), true).Length > 0) - .ToArray(); - var typesWithContextMethods = new HashSet(); - foreach (var method in registeredMethods) - { - typesWithContextMethods.Add(method.ReflectedType); - } - - if (registeredMethods.Length == 0) - { - throw new Exception($"Couldn't find any registered methods for multiprocess testing. Is {nameof(TestCoordinator)} in same assembly as test methods?"); - } - - object[] GetParameterValuesToPassFunc(ParameterInfo[] parameterInfo) - { - object[] parametersToReturn = new object[parameterInfo.Length]; - for (int i = 0; i < parameterInfo.Length; i++) - { - var paramType = parameterInfo[i].GetType(); - object defaultObj = null; - if (paramType.IsValueType) - { - defaultObj = Activator.CreateInstance(paramType); - } - - parametersToReturn[i] = defaultObj; - } - - return parametersToReturn; - } - - foreach (var contextType in typesWithContextMethods) - { - var allConstructors = contextType.GetConstructors(); - if (allConstructors.Length > 1) - { - throw new NotImplementedException("Case not implemented where test has more than one constructor"); - } - - var instance = Activator.CreateInstance(contextType, allConstructors.Length > 0 ? GetParameterValuesToPassFunc(allConstructors[0].GetParameters()) : null); - s_AllClientTestInstances.Add(instance); // keeping that instance so tests can use captured local attributes - - var typeMethodsWithContextSteps = new List(); - foreach (var method in contextType.GetMethods()) - { - if (method.GetCustomAttributes(typeof(MultiprocessContextBasedTestAttribute), true).Length > 0) - { - typeMethodsWithContextSteps.Add(method); - } - } - - foreach (var method in typeMethodsWithContextSteps) - { - var parametersToPass = GetParameterValuesToPassFunc(method.GetParameters()); - var enumerator = (IEnumerator)method.Invoke(instance, parametersToPass.ToArray()); - while (enumerator.MoveNext()) { } - } - } - - IsRegistering = false; - HasRegistered = true; - MultiprocessLogger.Log("InitializeAllSteps - Done"); - } - - /// - /// Executes an action with the specified context. This allows writing tests all in the same sequential flow, - /// making it more readable. This allows not having to jump between static client methods and test method - /// - /// context to use. for example, should execute client side? server side? - /// action to execute - /// waits for timeout and just finishes step execution silently - /// parameters to pass to action - /// - /// waits multiple frames before allowing the execution to continue. This means ClientFinishedServerRpc must be called manually - /// - public ExecuteStepInContext(StepExecutionContext actionContext, Action stepToExecute, bool ignoreTimeoutException = false, byte[] paramToPass = default, NetworkManager networkManager = null, bool waitMultipleUpdates = false, Func additionalIsFinishedWaiter = null) - { - m_StartTime = Time.time; - m_IsRegistering = IsRegistering; - m_ActionContext = actionContext; - m_StepToExecute = stepToExecute; - m_WaitMultipleUpdates = waitMultipleUpdates; - m_IgnoreTimeoutException = ignoreTimeoutException; - - if (additionalIsFinishedWaiter != null) - { - m_AdditionalIsFinishedWaiter = additionalIsFinishedWaiter; - } - - if (networkManager == null) - { - networkManager = NetworkManager.Singleton; - } - - m_NetworkManager = networkManager; // todo test using this for multiinstance tests too? - - var callerMethod = new StackFrame(1).GetMethod(); // one skip frame for current method - - var methodId = GetMethodIdentifier(callerMethod); // assumes called from IEnumerator MoveNext, which should be the case since we're a CustomYieldInstruction. This will return a generated class name which should be unique - if (!s_MethodIdCounter.ContainsKey(methodId)) - { - s_MethodIdCounter[methodId] = 0; - } - - string currentActionId = $"{methodId}-{s_MethodIdCounter[methodId]++}"; - m_CurrentActionId = currentActionId; - - if (m_IsRegistering) - { - Assert.That(AllActions, Does.Not.Contain(currentActionId)); // sanity check - AllActions[currentActionId] = this; - MultiprocessLogger.Log($"InitializeAllSteps - Registering {currentActionId}"); - } - else - { - MultiprocessLogger.Log($"InitializeAllSteps - Not Registering {currentActionId}"); - if (shouldExecuteLocally) - { - m_StepToExecute.Invoke(paramToPass); - } - else - { - if (networkManager.IsServer) - { - TestCoordinator.Instance.TriggerActionIdClientRpc(currentActionId, paramToPass, m_IgnoreTimeoutException, - clientRpcParams: new ClientRpcParams - { - Send = new ClientRpcSendParams { TargetClientIds = TestCoordinator.AllClientIdsExceptMine.ToArray() } - }); - foreach (var clientId in TestCoordinator.AllClientIdsExceptMine) - { - m_ClientIsFinishedChecks.Add(TestCoordinator.ConsumeClientIsFinished(clientId)); - } - } - else - { - throw new NotImplementedException(); - } - } - } - } - - public void Invoke(byte[] args) - { - m_StepToExecute.Invoke(args); - if (!m_WaitMultipleUpdates) - { - if (!m_NetworkManager.IsServer) - { - TestCoordinator.Instance.ClientFinishedServerRpc(); - } - else - { - throw new NotImplementedException("todo implement"); - } - } - } - - public override bool keepWaiting - { - get - { - if (isTimingOut) - { - if (m_IgnoreTimeoutException) - { - Debug.LogWarning($"Timeout ignored for action ID {m_CurrentActionId}"); - return false; - } - - throw new Exception($"timeout for Context Step with action ID {m_CurrentActionId}"); - } - - if (m_AdditionalIsFinishedWaiter != null) - { - var isFinished = m_AdditionalIsFinishedWaiter.Invoke(); - if (!isFinished) - { - return true; - } - } - - if (m_IsRegistering || shouldExecuteLocally || m_ClientIsFinishedChecks == null) - { - return false; - } - - for (int i = m_ClientIsFinishedChecks.Count - 1; i >= 0; i--) - { - if (m_ClientIsFinishedChecks[i].Invoke()) - { - m_ClientIsFinishedChecks.RemoveAt(i); - } - else - { - return true; - } - } - - return false; - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContext.cs.meta b/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContext.cs.meta deleted file mode 100644 index 2b5f013d83..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContext.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1ff1efc1d00c64914905497db918aadc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContextTests.cs b/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContextTests.cs deleted file mode 100644 index ebacd0ecda..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContextTests.cs +++ /dev/null @@ -1,261 +0,0 @@ -using System; -using System.Collections; -using System.Text.RegularExpressions; -using NUnit.Framework; -using UnityEngine; -using UnityEngine.TestTools; -using static ExecuteStepInContext; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - /// - /// Smoke tests for ExecuteStepInContext, to make sure it's working properly before being used in other tests - /// - [TestFixture(1)] - [TestFixture(2)] - public class ExecuteStepInContextTests : BaseMultiprocessTests - { - private int m_WorkerCountToTest; - - public ExecuteStepInContextTests(int workerCountToTest) - { - m_WorkerCountToTest = workerCountToTest; - } - - protected override int WorkerCount => m_WorkerCountToTest; - protected override bool IsPerformanceTest => false; - - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestWithSameName([Values(1)] int a) - { - // ExecuteStepInContext bases itself on method name to identify steps. We need to make sure that methods with - // same names, but different signatures behave correctly - InitializeContextSteps(); - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Assert.That(a, Is.EqualTo(1)); - }); - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - Assert.That(BitConverter.ToInt32(bytes, 0), Is.EqualTo(1)); - }, paramToPass: BitConverter.GetBytes(a)); - } - - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestWithSameName([Values(2)] int a, [Values(3)] int b) - { - InitializeContextSteps(); - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Assert.That(b, Is.EqualTo(3)); - }); - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - Assert.That(BitConverter.ToInt32(bytes, 0), Is.EqualTo(3)); - }, paramToPass: BitConverter.GetBytes(b)); - } - - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestWithParameters([Values(1, 2, 3)] int a) - { - InitializeContextSteps(); - - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Assert.Less(a, 4); - Assert.Greater(a, 0); - }); - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - var clientA = BitConverter.ToInt32(bytes, 0); - Assert.True(!NetworkManager.Singleton.IsServer); - Assert.Less(clientA, 4); - Assert.Greater(clientA, 0); - }, paramToPass: BitConverter.GetBytes(a)); - } - - [UnityTest, MultiprocessContextBasedTest] - [TestCase(1, 2, ExpectedResult = null)] - [TestCase(2, 3, ExpectedResult = null)] - [TestCase(3, 4, ExpectedResult = null)] - public IEnumerator TestWithParameters(int a, int b) - { - InitializeContextSteps(); - - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Assert.Less(a, 4); - Assert.Greater(a, 0); - Assert.Less(b, 5); - Assert.Greater(b, 1); - }); - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - var clientB = BitConverter.ToInt32(bytes, 0); - Assert.True(!NetworkManager.Singleton.IsServer); - Assert.Less(clientB, 5); - Assert.Greater(clientB, 1); - }, paramToPass: BitConverter.GetBytes(b)); - } - - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestExceptionClientSide() - { - InitializeContextSteps(); - - const string exceptionMessageToTest = "This is an exception for TestCoordinator that's expected"; - yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => - { - throw new Exception(exceptionMessageToTest); - }, ignoreTimeoutException: true); - yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => - { - for (int i = 0; i < m_WorkerCountToTest; i++) - { - LogAssert.Expect(LogType.Error, new Regex($".*{exceptionMessageToTest}.*")); - } - }); - - const string exceptionUpdateMessageToTest = "This is an exception for update loop client side that's expected"; - yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => - { - void UpdateFunc(float _) - { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; - throw new Exception(exceptionUpdateMessageToTest); - } - - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; - }, ignoreTimeoutException: true); - yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => - { - for (int i = 0; i < m_WorkerCountToTest; i++) - { - LogAssert.Expect(LogType.Error, new Regex($".*{exceptionUpdateMessageToTest}.*")); - } - }); - } - - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator ContextTestWithAdditionalWait() - { - InitializeContextSteps(); - - const int maxValue = 10; - yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => - { - int count = 0; - - void UpdateFunc(float _) - { - TestCoordinator.Instance.WriteTestResultsServerRpc(count++); - if (count > maxValue) - { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; - } - } - - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; - }, additionalIsFinishedWaiter: () => - { - int nbFinished = 0; - for (int i = 0; i < m_WorkerCountToTest; i++) - { - if (TestCoordinator.PeekLatestResult(TestCoordinator.AllClientIdsExceptMine[i]) == maxValue) - { - nbFinished++; - } - } - - return nbFinished == m_WorkerCountToTest; - }); - yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => - { - Assert.That(TestCoordinator.AllClientIdsExceptMine.Count, Is.EqualTo(m_WorkerCountToTest)); - foreach (var clientId in TestCoordinator.AllClientIdsExceptMine) - { - var current = 0; - foreach (var res in TestCoordinator.ConsumeCurrentResult(clientId)) - { - Assert.That(res, Is.EqualTo(current++)); - } - - Assert.That(current - 1, Is.EqualTo(maxValue)); - } - }); - } - - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator TestExecuteInContext() - { - InitializeContextSteps(); - - int stepCountExecuted = 0; - yield return new ExecuteStepInContext(StepExecutionContext.Server, args => - { - stepCountExecuted++; - int count = BitConverter.ToInt32(args, 0); - Assert.That(count, Is.EqualTo(1)); - }, paramToPass: BitConverter.GetBytes(1)); - - yield return new ExecuteStepInContext(StepExecutionContext.Clients, args => - { - int count = BitConverter.ToInt32(args, 0); - Assert.That(count, Is.EqualTo(2)); - TestCoordinator.Instance.WriteTestResultsServerRpc(12345); -#if UNITY_EDITOR - Assert.Fail("Should not be here!! This should only execute on client!!"); -#endif - }, paramToPass: BitConverter.GetBytes(2)); - - yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => - { - stepCountExecuted++; - int resultCountFromWorkers = 0; - foreach (var res in TestCoordinator.ConsumeCurrentResult()) - { - resultCountFromWorkers++; - Assert.AreEqual(12345, res.result); - } - - Assert.That(resultCountFromWorkers, Is.EqualTo(WorkerCount)); - }); - - const int timeToWait = 4; - yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => - { - void UpdateFunc(float _) - { - if (Time.time > timeToWait) - { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; - TestCoordinator.Instance.WriteTestResultsServerRpc(Time.time); - - TestCoordinator.Instance.ClientFinishedServerRpc(); // since finishOnInvoke is false, we need to do this manually - } - } - - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; - }, waitMultipleUpdates: true); // waits multiple frames before allowing the next action to continue. - - yield return new ExecuteStepInContext(StepExecutionContext.Server, args => - { - stepCountExecuted++; - int count = 0; - foreach (var res in TestCoordinator.ConsumeCurrentResult()) - { - count++; - Assert.GreaterOrEqual(res.result, timeToWait); - } - - Assert.Greater(count, 0); - }); - - if (!IsRegistering) - { - Assert.AreEqual(3, stepCountExecuted); - } - } - } -} - diff --git a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta b/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta deleted file mode 100644 index 3f89ca9cb5..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/ExecuteStepInContextTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 80b877babc0ce4b0d8cf31e73216d49a -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers.meta b/testproject/Legacy/MultiprocessRuntime/Helpers.meta deleted file mode 100644 index 2b9c70c07b..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ae0eb1e25098241b182babd91479ea26 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs deleted file mode 100644 index b992dfb53b..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; -using System.IO; -#if UNITY_EDITOR -using UnityEditor; -using UnityEditor.Build.Reporting; -#endif -using UnityEngine; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - /// - /// This is needed as Unity throws "An abnormal situation has occurred: the PlayerLoop internal function has been called recursively. Please contact Customer Support with a sample project so that we can reproduce the problem and troubleshoot it." - /// when trying to build from Setup() steps in tests. - /// - public static class BuildMultiprocessTestPlayer - { - public const string MultiprocessBaseMenuName = "Netcode/Multiprocess Test"; - public const string BuildAndExecuteMenuName = MultiprocessBaseMenuName + "/Build Test Player #t"; - public const string MainSceneName = "MultiprocessTestScene"; - - private static string BuildPathDirectory => Path.Combine(Path.GetDirectoryName(Application.dataPath), "Builds", "MultiprocessTests"); - public static string BuildPath => Path.Combine(BuildPathDirectory, "MultiprocessTestPlayer"); - public const string BuildInfoFileName = "BuildInfo.json"; - -#if UNITY_EDITOR - /// - /// Build the standalone player on the current platform - /// This method is both a menu item as well as a public method that can be called from CI - /// in order to build the standalone player - /// - [MenuItem(BuildAndExecuteMenuName)] - public static void BuildRelease() - { - var report = BuildPlayerUtility(); - if (report.summary.result != BuildResult.Succeeded) - { - throw new Exception($"Build failed! {report.summary.totalErrors} errors"); - } - } - - [MenuItem(MultiprocessBaseMenuName + "/Build Test Player (Debug)")] - public static void BuildDebug() - { - var report = BuildPlayerUtility(BuildTarget.NoTarget, null, true); - if (report.summary.result != BuildResult.Succeeded) - { - throw new Exception($"Build failed! {report.summary.totalErrors} errors"); - } - } - - [MenuItem(MultiprocessBaseMenuName + "/Delete Test Build")] - public static void DeleteBuild() - { - if (Directory.Exists(BuildPathDirectory)) - { - Directory.Delete(BuildPathDirectory, recursive: true); - } - else - { - Debug.Log($"[{nameof(BuildMultiprocessTestPlayer)}] build directory does not exist ({BuildPathDirectory}) not deleting anything"); - } - } - - private static BuildReport BuildPlayerUtility(BuildTarget buildTarget = BuildTarget.NoTarget, string buildPathExtension = null, bool buildDebug = false) - { - SaveBuildInfo(new BuildInfo() { BuildPath = BuildPath }); - - // deleting so we don't end up testing on outdated builds if there's a build failure - DeleteBuild(); - - if (buildTarget == BuildTarget.NoTarget) - { - if (Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsEditor) - { - buildPathExtension += ".exe"; - buildTarget = BuildTarget.StandaloneWindows64; - } - else if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor) - { - buildPathExtension += ".app"; - buildTarget = BuildTarget.StandaloneOSX; - } - else if (Application.platform == RuntimePlatform.LinuxEditor || Application.platform == RuntimePlatform.LinuxPlayer) - { - buildPathExtension += ""; - buildTarget = BuildTarget.StandaloneLinux64; - } - } - - var buildPathToUse = BuildPath; - buildPathToUse += buildPathExtension; - - var buildPlayerOptions = new BuildPlayerOptions - { - scenes = new[] { "Assets/Scenes/MultiprocessTestScene.unity" }, - locationPathName = buildPathToUse, - target = buildTarget - }; - var buildOptions = BuildOptions.None; - if (buildDebug || buildTarget == BuildTarget.Android) - { - buildOptions |= BuildOptions.Development; - buildOptions |= BuildOptions.AllowDebugging; - } - - buildOptions |= BuildOptions.StrictMode; - buildOptions |= BuildOptions.IncludeTestAssemblies; - buildPlayerOptions.options = buildOptions; - - BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions); - BuildSummary summary = report.summary; - - if (summary.result == BuildResult.Succeeded) - { - Debug.Log($"Build succeeded: {summary.totalSize} bytes at {summary.outputPath}"); - } - - return report; - } - - [MenuItem(MultiprocessBaseMenuName + "/Windows Standalone Player")] - public static void BuildWindowsStandalonePlayer() - { - var report = BuildPlayerUtility(BuildTarget.StandaloneWindows64, ".exe"); - if (report.summary.result != BuildResult.Succeeded) - { - throw new Exception($"Build failed! {report.summary.totalErrors} errors"); - } - } - - [MenuItem(MultiprocessBaseMenuName + "/Build OSX")] - public static void BuildOSX() - { - var report = BuildPlayerUtility(BuildTarget.StandaloneOSX, ".app"); - if (report.summary.result != BuildResult.Succeeded) - { - throw new Exception($"Build failed! {report.summary.totalErrors} errors"); - } - } - - [MenuItem(MultiprocessBaseMenuName + "/Build Linux")] - public static void BuildLinux() - { - var report = BuildPlayerUtility(BuildTarget.StandaloneLinux64, ""); - if (report.summary.result != BuildResult.Succeeded) - { - throw new Exception($"Build failed! {report.summary.totalErrors} errors"); - } - } - - [MenuItem(MultiprocessBaseMenuName + "/Build Android")] - public static void BuildAndroid() - { - var report = BuildPlayerUtility(BuildTarget.Android, ".apk"); - if (report.summary.result != BuildResult.Succeeded) - { - throw new Exception($"Build failed! {report.summary.totalErrors} errors"); - } - } -#endif - - [Serializable] - public struct BuildInfo - { - public string BuildPath; - public bool IsDebug; - } - - public static bool DoesBuildInfoExist() - { - var buildfileInfo = new FileInfo(Path.Combine(Application.streamingAssetsPath, BuildInfoFileName)); - return buildfileInfo.Exists; - } - - public static BuildInfo ReadBuildInfo() - { - var jsonString = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, BuildInfoFileName)); - return JsonUtility.FromJson(jsonString); - } - - public static void SaveBuildInfo(BuildInfo toSave) - { - var buildInfoJson = JsonUtility.ToJson(toSave); - File.WriteAllText(Path.Combine(Application.streamingAssetsPath, BuildInfoFileName), buildInfoJson); - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta deleted file mode 100644 index 87acf05da8..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/BuildMultiprocessTestPlayer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b389565fd8544431db4c24940cb569c6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/CallbackComponent.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/CallbackComponent.cs deleted file mode 100644 index df0e14f61c..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/CallbackComponent.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using UnityEngine; - -/// -/// Component who's purpose is to expose callbacks to code tests -/// -public class CallbackComponent : MonoBehaviour -{ - public Action OnUpdate; - - // Update is called once per frame - private void Update() - { - try - { - OnUpdate?.Invoke(Time.deltaTime); - } - catch (Exception e) - { - TestCoordinator.Instance.WriteErrorServerRpc(e.ToString()); - throw; - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta deleted file mode 100644 index 7347e89e7b..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/CallbackComponent.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 55d1c75ce242745ac98f7e7aca6d2d19 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationTools.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationTools.cs deleted file mode 100644 index efca1c8970..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationTools.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using UnityEngine; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class ConfigurationTools - { - public static async Task GetRemoteConfig() - { - var theList = new JobQueueItemArray(); - using var client = new HttpClient(); - var cancelAfterDelay = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var response = await client.GetAsync("https://multiprocess-log-event-manager.cds.internal.unity3d.com/api/JobWithFile", - HttpCompletionOption.ResponseHeadersRead, cancelAfterDelay.Token).ConfigureAwait(false); - var content = await response.Content.ReadAsStringAsync(); - JsonUtility.FromJsonOverwrite(content, theList); - return theList; - } - - public static async void CompleteJobQueueItem(JobQueueItem item) - { - await PostJobQueueItem(item, "/complete"); - } - - public static async void ClaimJobQueueItem(JobQueueItem item) - { - await PostJobQueueItem(item, "/claim"); - } - - public static async Task PostJobQueueItem(JobQueueItem item, string path = "") - { - using var client = new HttpClient(); - using var request = new HttpRequestMessage(HttpMethod.Post, "https://multiprocess-log-event-manager.cds.internal.unity3d.com/api/JobWithFile" + path); - var json = JsonUtility.ToJson(item); - using var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - request.Content = stringContent; - MultiprocessLogger.Log($"Posting remoteConfig to server {json}"); - var cancelAfterDelay = new CancellationTokenSource(TimeSpan.FromSeconds(20)); - var response = await client - .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancelAfterDelay.Token).ConfigureAwait(false); - MultiprocessLogger.Log($"remoteConfig posted, checking response {response.StatusCode}"); - } - } - - [Serializable] - public class JobQueueItemArray - { - public List JobQueueItems; - } - - [Serializable] - public class JobQueueItem - { - public int Id; - public long JobId; - public string GitHash; - public string HostIp; - public int PlatformId; - public int JobStateId; - public string CreatedBy; - public string UpdatedBy; - public string TransportName; - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationTools.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationTools.cs.meta deleted file mode 100644 index daf965ddca..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationTools.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ad11397b80c04404cb24e82cc7872334 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationType.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationType.cs deleted file mode 100644 index bb9d097f62..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationType.cs +++ /dev/null @@ -1,9 +0,0 @@ - -public enum ConfigurationType -{ - Unknown, - Remote, - CommandLine, - ResourceFile, - Host -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationType.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationType.cs.meta deleted file mode 100644 index 9e89a3cb23..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/ConfigurationType.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5b189bac115ca4587ba64943bfcc67f6 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/CustomPrefabSpawnerForPerformanceTests.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/CustomPrefabSpawnerForPerformanceTests.cs deleted file mode 100644 index 41558e04dc..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/CustomPrefabSpawnerForPerformanceTests.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using UnityEngine; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class CustomPrefabSpawnerForPerformanceTests : INetworkPrefabInstanceHandler, IDisposable where T : NetworkBehaviour - { - private GameObjectPool m_ObjectPool; - private Action m_SetupSpawnedObject; - private Action m_OnRelease; - - public CustomPrefabSpawnerForPerformanceTests(T prefabToSpawn, int maxObjectsToSpawn, Action setupSpawnedObject, Action onRelease) - { - m_ObjectPool = new GameObjectPool(); - m_ObjectPool.Initialize(maxObjectsToSpawn, prefabToSpawn); - m_SetupSpawnedObject = setupSpawnedObject; - m_OnRelease = onRelease; - } - - public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation) - { - var netBehaviour = m_ObjectPool.Get(); - var networkObject = netBehaviour.NetworkObject; - Transform netTransform = networkObject.transform; - netTransform.position = position; - netTransform.rotation = rotation; - m_SetupSpawnedObject(netBehaviour); - return networkObject; - } - - public void Destroy(NetworkObject networkObject) - { - var behaviour = networkObject.gameObject.GetComponent(); // todo expensive, only used in teardown for now, should optimize eventually - m_OnRelease(behaviour); - Transform netTransform = networkObject.transform; - netTransform.position = Vector3.zero; - netTransform.rotation = Quaternion.identity; - m_ObjectPool.Release(behaviour); - } - - public void Dispose() - { - m_ObjectPool.Dispose(); - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/CustomPrefabSpawnerForPerformanceTests.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/CustomPrefabSpawnerForPerformanceTests.cs.meta deleted file mode 100644 index e36dcb4466..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/CustomPrefabSpawnerForPerformanceTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: dbe82ff88ee654428b03632ec6ffff07 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/GameObjectPool.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/GameObjectPool.cs deleted file mode 100644 index 41224a47c5..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/GameObjectPool.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using Object = UnityEngine.Object; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - /// - /// Have to implement our own pool here for compatibility with Unity 2020LTS - /// This shouldn't be needed if we were supporting only 2021 (and its new Pool) - /// - public class GameObjectPool : IDisposable where T : NetworkBehaviour - { - private List m_AllGameObject; - private Stack m_FreeIndexes; - private Dictionary m_ReverseLookup = new Dictionary(); - - public void Initialize(int originalCount, T prefabToSpawn) - { - m_AllGameObject = new List(originalCount); - m_FreeIndexes = new Stack(originalCount); - for (int i = 0; i < originalCount; i++) - { - var go = Object.Instantiate(prefabToSpawn); - go.gameObject.SetActive(false); - m_AllGameObject.Add(go); - m_FreeIndexes.Push(i); - m_ReverseLookup[go] = i; - } - } - - public void Dispose() - { - foreach (var gameObject in m_AllGameObject) - { - Object.Destroy(gameObject); - } - m_AllGameObject = null; - m_FreeIndexes = null; - m_ReverseLookup = null; - } - - public T Get() - { - if (m_FreeIndexes.Count == 0) - { - throw new Exception("Pool full!"); - } - var o = m_AllGameObject[m_FreeIndexes.Pop()]; - o.gameObject.SetActive(true); - return o; - } - - public void Release(T toRelease) - { - int index = m_ReverseLookup[toRelease]; - m_FreeIndexes.Push(index); - toRelease.gameObject.SetActive(false); - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/GameObjectPool.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/GameObjectPool.cs.meta deleted file mode 100644 index 5a5f42a8e8..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/GameObjectPool.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: dc81fb2a3c7347a3a0b5e98d2ba49ed7 -timeCreated: 1622655847 \ No newline at end of file diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessLogger.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessLogger.cs deleted file mode 100644 index 37ea12c6ee..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessLogger.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using NUnit.Framework; -using UnityEngine; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class MultiprocessLogger - { - private static Logger s_Logger; - - static MultiprocessLogger() => s_Logger = new Logger(logHandler: new MultiprocessLogHandler()); - - public static void Log(string msg) - { - s_Logger.Log(msg); - } - - public static void LogError(string msg) - { - s_Logger.LogError("", msg); - } - - public static void LogWarning(string msg) - { - s_Logger.LogWarning("", msg); - } - } - - public class MultiprocessLogHandler : ILogHandler - { - public static long JobId; - static MultiprocessLogHandler() - { - if (JobId == 0) - { - string sJobId = Environment.GetEnvironmentVariable("YAMATO_JOB_ID"); - if (!long.TryParse(sJobId, out JobId)) - { - JobId = -2; - } - } - } - public void LogException(Exception exception, UnityEngine.Object context) - { - Debug.unityLogger.LogException(exception, context); - } - - public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args) - { - string testName = null; - try - { - testName = TestContext.CurrentContext.Test.Name; - } - catch (Exception) - { - // ignored - } - - if (string.IsNullOrEmpty(testName)) - { - testName = "unknown"; - } - - Debug.LogFormat(logType, LogOption.NoStacktrace, context, $"MPLOG({DateTime.Now:T}) : {testName} : {format}", args); - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessLogger.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessLogger.cs.meta deleted file mode 100644 index 2c4934f392..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessLogger.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8c1a196a93520415cbf79751b2bb8eee -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs b/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs deleted file mode 100644 index 6776bc4151..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs +++ /dev/null @@ -1,278 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using Unity.Netcode.MultiprocessRuntimeTests; -using UnityEngine; -using Debug = UnityEngine.Debug; - -public class MultiprocessOrchestration -{ - public static bool IsPerformanceTest; - public const string IsWorkerArg = "-isWorker"; - private static DirectoryInfo s_MultiprocessDirInfo; - public static DirectoryInfo MultiprocessDirInfo - { - private set => s_MultiprocessDirInfo = value; - get => s_MultiprocessDirInfo ?? initMultiprocessDirinfo(); - } - private static List s_Processes = new List(); - private static int s_TotalProcessCounter = 0; - public static string PathToDll { get; private set; } - public static List ProcessList = new List(); - private static FileInfo s_Localip_fileinfo; - - private static DirectoryInfo initMultiprocessDirinfo() - { - string userprofile = ""; - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - userprofile = Environment.GetEnvironmentVariable("USERPROFILE"); - } - else - { - userprofile = Environment.GetEnvironmentVariable("HOME"); - } - s_MultiprocessDirInfo = new DirectoryInfo(Path.Combine(userprofile, ".multiprocess")); - if (!MultiprocessDirInfo.Exists) - { - MultiprocessDirInfo.Create(); - } - s_Localip_fileinfo = new FileInfo(Path.Combine(s_MultiprocessDirInfo.FullName, "localip")); - - return s_MultiprocessDirInfo; - } - - static MultiprocessOrchestration() - { - initMultiprocessDirinfo(); - MultiprocessLogger.Log($" userprofile: {s_MultiprocessDirInfo.FullName} localipfile: {s_Localip_fileinfo}"); - var rootdir_FileInfo = new FileInfo(Path.Combine(MultiprocessDirInfo.FullName, "rootdir")); - MultiprocessLogger.Log($"Checking for the existence of {rootdir_FileInfo.FullName}"); - if (rootdir_FileInfo.Exists) - { - var rootDirText = (File.ReadAllText(rootdir_FileInfo.FullName)).Trim(); - PathToDll = Path.Combine(rootDirText, "multiplayer-multiprocess-test-tools/BokkenForNetcode/ProvisionBokkenMachines/bin/Debug/netcoreapp3.1/osx-x64", "ProvisionBokkenMachines.dll"); - } - else - { - MultiprocessLogger.Log("PathToDll cannot be set as rootDir doesn't exist"); - PathToDll = "unknown"; - } - } - - /// - /// This is to detect if we should ignore Multiprocess tests - /// For testing, include the -bypassIgnoreUTR command line parameter when running UTR. - /// - public static bool ShouldIgnoreUTRTests() - { - return Environment.GetCommandLineArgs().Contains("-automated") && !Environment.GetCommandLineArgs().Contains("-bypassIgnoreUTR"); - } - - public static int ActiveWorkerCount() - { - int activeWorkerCount = 0; - if (s_Processes == null) - { - return activeWorkerCount; - } - - if (s_Processes.Count > 0) - { - foreach (var p in s_Processes) - { - if ((p != null) && (!p.HasExited)) - { - activeWorkerCount++; - } - } - } - return activeWorkerCount; - } - - public static string StartWorkerNode() - { - if (s_Processes == null) - { - s_Processes = new List(); - } - - var workerProcess = new Process(); - s_TotalProcessCounter++; - if (s_Processes.Count > 0) - { - string message = ""; - foreach (var p in s_Processes) - { - message += $" {p.Id} {p.HasExited} {p.StartTime} "; - } - MultiprocessLogger.Log($"Current process count {s_Processes.Count} with data {message}"); - } - - //TODO this should be replaced eventually by proper orchestration for all supported platforms - // Starting new local processes is a solution to help run perf tests locally. CI should have multi machine orchestration to - // run performance tests with more realistic conditions. - string buildInstructions = $"You probably didn't generate your build. Please make sure you build a player using the '{BuildMultiprocessTestPlayer.BuildAndExecuteMenuName}' menu"; - string extraArgs = ""; - try - { - var buildPath = BuildMultiprocessTestPlayer.ReadBuildInfo().BuildPath; - switch (Application.platform) - { - case RuntimePlatform.OSXPlayer: - case RuntimePlatform.OSXEditor: - workerProcess.StartInfo.FileName = $"{buildPath}.app/Contents/MacOS/testproject"; - // extraArgs += "-popupwindow -screen-width 100 -screen-height 100"; - extraArgs += "-batchmode -nographics"; - break; - case RuntimePlatform.WindowsPlayer: - case RuntimePlatform.WindowsEditor: - workerProcess.StartInfo.FileName = $"{buildPath}.exe"; - //extraArgs += "-popupwindow -screen-width 100 -screen-height 100"; - extraArgs += "-popupwindow"; - break; - case RuntimePlatform.LinuxPlayer: - case RuntimePlatform.LinuxEditor: - workerProcess.StartInfo.FileName = $"{buildPath}"; - // extraArgs += "-popupwindow -screen-width 100 -screen-height 100"; - extraArgs += "-batchmode -nographics"; - break; - default: - throw new NotImplementedException($"{nameof(StartWorkerNode)}: Current platform is not supported"); - } - } - catch (FileNotFoundException) - { - Debug.LogError($"Could not find build info file. {buildInstructions}"); - throw; - } - - string logPath = Path.Combine(MultiprocessDirInfo.FullName, $"logfile-mp{s_TotalProcessCounter}.log"); - - workerProcess.StartInfo.UseShellExecute = false; - workerProcess.StartInfo.RedirectStandardError = true; - workerProcess.StartInfo.RedirectStandardOutput = true; - workerProcess.StartInfo.Arguments = $"{IsWorkerArg} {extraArgs} -logFile {logPath}"; - - try - { - MultiprocessLogger.Log($"Attempting to start new process, current process count: {s_Processes.Count} with arguments {workerProcess.StartInfo.Arguments}"); - var newProcessStarted = workerProcess.Start(); - if (!newProcessStarted) - { - throw new Exception("Failed to start worker process!"); - } - s_Processes.Add(workerProcess); - } - catch (Win32Exception e) - { - MultiprocessLogger.LogError($"Error starting player, {buildInstructions}, {e}"); - throw; - } - return logPath; - } - - public static void ShutdownAllProcesses() - { - MultiprocessLogger.Log("Shutting down all processes.."); - foreach (var process in s_Processes) - { - MultiprocessLogger.Log($"Shutting down process {process.Id} with state {process.HasExited}"); - try - { - if (!process.HasExited) - { - // Close process by sending a close message to its main window. - process.CloseMainWindow(); - - // Free resources associated with process. - process.Close(); - } - } - catch (Exception ex) - { - Debug.LogException(ex); - } - } - - s_Processes.Clear(); - } - - public static bool IsRemoteOperationEnabled() - { - string encodedPlatformList = Environment.GetEnvironmentVariable("MP_PLATFORM_LIST"); - if (encodedPlatformList != null && encodedPlatformList.Split(',').Length > 1) - { - return true; - } - return false; - } - - public static string[] GetRemotePlatformList() - { - // "default-win:test-win,default-mac:test-mac" - if (!IsRemoteOperationEnabled()) - { - return null; - } - string encodedPlatformList = Environment.GetEnvironmentVariable("MP_PLATFORM_LIST"); - string[] separated = encodedPlatformList.Split(','); - return separated; - } - - public static List GetRemoteMachineList() - { - var machineJson = new List(); - foreach (var f in MultiprocessDirInfo.GetFiles("*.json")) - { - if (f.Name.Equals("remoteConfig.json")) - { - continue; - } - else - { - machineJson.Add(f); - } - } - return machineJson; - } - - public static Process StartWorkersOnRemoteNodes(FileInfo machine) - { - string command = $" --command launch " + - $"--input-path {machine.FullName} "; - - var workerProcess = new Process(); - - workerProcess.StartInfo.FileName = Path.Combine("dotnet"); - workerProcess.StartInfo.UseShellExecute = false; - workerProcess.StartInfo.RedirectStandardError = true; - workerProcess.StartInfo.RedirectStandardOutput = true; - workerProcess.StartInfo.Arguments = $"{PathToDll} {command} "; - try - { - var newProcessStarted = workerProcess.Start(); - - if (!newProcessStarted) - { - throw new Exception("Failed to start worker process!"); - } - } - catch (Win32Exception e) - { - MultiprocessLogger.LogError($"Error starting bokken process, {e.Message} {e.Data} {e.ErrorCode}"); - throw; - } - - - ProcessList.Add(workerProcess); - - MultiprocessLogger.Log($"Execute Command: {PathToDll} {command} End"); - return workerProcess; - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta b/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta deleted file mode 100644 index 4797a6c5a7..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/Helpers/MultiprocessOrchestration.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2b59a46cbb2c54f4d977a05103227453 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/NetworkVariablePerformanceTests.cs b/testproject/Legacy/MultiprocessRuntime/NetworkVariablePerformanceTests.cs deleted file mode 100644 index 218c80d61a..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/NetworkVariablePerformanceTests.cs +++ /dev/null @@ -1,263 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using NUnit.Framework; -using Unity.PerformanceTesting; -using UnityEngine; -using UnityEngine.Profiling; -using UnityEngine.SceneManagement; -using UnityEngine.TestTools; -using static ExecuteStepInContext; -using Object = UnityEngine.Object; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class NetworkVariablePerformanceTests : BaseMultiprocessTests - { - protected override int WorkerCount { get; } = 1; - private const int k_MaxObjectsToSpawn = 10000; - private List m_ServerSpawnedObjects = new List(); - private static GameObjectPool s_ServerObjectPool; - private CustomPrefabSpawnerForPerformanceTests m_ClientPrefabHandler; - private OneNetVar m_PrefabToSpawn; - protected override bool IsPerformanceTest => true; - - private class OneNetVar : NetworkBehaviour - { - public static int InstanceCount; - public NetworkVariable OneInt = new NetworkVariable(); - - public void Initialize() - { - InstanceCount++; - if (IsServer) - { - OneInt.Value = 1; - } - } - - public static void Stop() - { - InstanceCount--; - } - } - - [OneTimeSetUp] - public override void SetupTestSuite() - { - base.SetupTestSuite(); - if (!IgnoreMultiprocessTests) - { - SceneManager.sceneLoaded += OnSceneLoadedInitSetupSuite; - } - } - - private void OnSceneLoadedInitSetupSuite(Scene scene, LoadSceneMode loadSceneMode) - { - SceneManager.sceneLoaded -= OnSceneLoadedInitSetupSuite; - InitializePrefab(); - s_ServerObjectPool = new GameObjectPool(); - s_ServerObjectPool.Initialize(k_MaxObjectsToSpawn, m_PrefabToSpawn); - } - - private void InitializePrefab() - { - if (m_PrefabToSpawn == null) - { - var prefabCopy = Object.Instantiate(PrefabReference.Instance.ReferencedPrefab); - m_PrefabToSpawn = prefabCopy.AddComponent(); - } - } - - [UnityTest, Performance, MultiprocessContextBasedTest] - public IEnumerator TestSpawningManyObjects([Values(1, 2, 1000, 2000, 10000)] int nbObjects) - { - InitializeContextSteps(); - - if (!IsRegistering && TestCoordinator.Instance.NetworkManager.IsServer && BuildMultiprocessTestPlayer.ReadBuildInfo().IsDebug) - { - // build test player in debug mode to enable this - var timeToWait = 20; - Debug.Log($"Debug mode tests enabled, waiting {timeToWait} seconds to give some time to attach debugger"); - yield return new WaitForSeconds(timeToWait); - } - - yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => - { - Assert.LessOrEqual(nbObjects, k_MaxObjectsToSpawn); // sanity check - }); - - yield return new ExecuteStepInContext(StepExecutionContext.Clients, stepToExecute: nbObjectsBytes => - { - // setup clients - InitializePrefab(); - var targetCount = BitConverter.ToInt32(nbObjectsBytes, 0); - - m_ClientPrefabHandler = new CustomPrefabSpawnerForPerformanceTests(m_PrefabToSpawn, k_MaxObjectsToSpawn, SetupSpawnedObject, StopSpawnedObject); - var hasAddedHandler = NetworkManager.Singleton.PrefabHandler.AddHandler(m_PrefabToSpawn.NetworkObject, m_ClientPrefabHandler); - Assert.That(hasAddedHandler); - - // add client side reporter for later spawn steps - void UpdateFunc(float deltaTime) - { - var count = OneNetVar.InstanceCount; - if (count > 0) - { - TestCoordinator.Instance.WriteTestResultsServerRpc(count); - - if (count >= targetCount) - { - // we got what we want, don't update results any longer - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateFunc; - } - } - } - - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateFunc; - }, paramToPass: BitConverter.GetBytes(nbObjects)); - - yield return new ExecuteStepInContext(StepExecutionContext.Server, _ => - { - // start test - using (Measure.Scope($"Time Taken For Spawning {nbObjects} objects server side and getting report")) - { - // spawn prefabs for test - var totalAllocSampleGroup = new SampleGroup("GC Alloc", SampleUnit.Kilobyte); - var beforeAllocatedMemory = Profiler.GetTotalAllocatedMemoryLong(); - Measure.Custom(totalAllocSampleGroup, beforeAllocatedMemory / 1024f); - for (int i = 0; i < nbObjects; i++) - { - var spawnedObject = s_ServerObjectPool.Get(); - SetupSpawnedObject(spawnedObject); - spawnedObject.NetworkObject.Spawn(destroyWithScene: true); - m_ServerSpawnedObjects.Add(spawnedObject); - } - - var afterAllocatedMemory = Profiler.GetTotalAllocatedMemoryLong(); - Measure.Custom(totalAllocSampleGroup, afterAllocatedMemory / 1024f); - var diffAllocSampleGroup = new SampleGroup("GC Alloc diff for Spawn Server side", SampleUnit.Byte); - Measure.Custom(diffAllocSampleGroup, afterAllocatedMemory - beforeAllocatedMemory); - } - }, additionalIsFinishedWaiter: () => - { - // wait for spawn results coming from clients - int finishedCount = 0; - if (TestCoordinator.AllClientIdsWithResults.Count != WorkerCount) - { - return false; - } - - foreach (var clientIdWithResult in TestCoordinator.AllClientIdsWithResults) - { - var latestResult = TestCoordinator.PeekLatestResult(clientIdWithResult); - if (latestResult == nbObjects) - { - finishedCount++; - } - } - - return finishedCount == WorkerCount; - }); - - var serverLastResult = 0f; - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - // add measurements - // todo add more client-side metrics like memory usage, time taken to execute, etc - var allocated = new SampleGroup("NbSpawnedPerFrame client side", SampleUnit.Undefined); - - foreach (var clientId in TestCoordinator.AllClientIdsWithResults) - { - var lastResult = TestCoordinator.PeekLatestResult(clientId); - Assert.That(lastResult, Is.EqualTo(nbObjects)); - } - - Assert.That(TestCoordinator.AllClientIdsWithResults.Count, Is.EqualTo(WorkerCount)); - foreach (var (clientId, result) in TestCoordinator.ConsumeCurrentResult()) - { - Measure.Custom(allocated, result); - serverLastResult = result; - } - }); - yield return new ExecuteStepInContext(StepExecutionContext.Clients, nbObjectsBytes => - { - var nbObjectsParam = BitConverter.ToInt32(nbObjectsBytes, 0); -#if UNITY_2023_1_OR_NEWER - Assert.That(Object.FindObjectsByType(FindObjectsSortMode.None).Length, Is.EqualTo(nbObjectsParam + 1), "Wrong number of spawned objects client side"); // +1 for the prefab to spawn -#else - Assert.That(Object.FindObjectsOfType(typeof(OneNetVar)).Length, Is.EqualTo(nbObjectsParam + 1), "Wrong number of spawned objects client side"); // +1 for the prefab to spawn -#endif - - - }, paramToPass: BitConverter.GetBytes(nbObjects)); - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Debug.Log($"finished with test for {nbObjects} expected objects and got {serverLastResult} objects"); - }); - } - - [UnityTearDown, MultiprocessContextBasedTest] - public IEnumerator UnityTeardown() - { - if (!IgnoreMultiprocessTests) - { - InitializeContextSteps(); - - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - foreach (var spawnedObject in m_ServerSpawnedObjects) - { - spawnedObject.NetworkObject.Despawn(false); - s_ServerObjectPool.Release(spawnedObject); - StopSpawnedObject(spawnedObject); - } - - m_ServerSpawnedObjects.Clear(); - }); - - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate = null; // todo move access to callbackcomponent to singleton - - void UpdateWaitForAllOneNetVarToDespawnFunc(float deltaTime) - { - if (OneNetVar.InstanceCount == 0) - { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= UpdateWaitForAllOneNetVarToDespawnFunc; - TestCoordinator.Instance.ClientFinishedServerRpc(); - } - } - - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += UpdateWaitForAllOneNetVarToDespawnFunc; - }, waitMultipleUpdates: true, ignoreTimeoutException: true); // ignoring timeout since you don't want to hide any issues in the main tests - - yield return new ExecuteStepInContext(StepExecutionContext.Clients, _ => - { - m_ClientPrefabHandler.Dispose(); - NetworkManager.Singleton.PrefabHandler.RemoveHandler(m_PrefabToSpawn.NetworkObject); - }); - } - yield return null; - } - - [OneTimeTearDown] - public override void TeardownSuite() - { - base.TeardownSuite(); - if (!IsPerformanceTest && !IgnoreMultiprocessTests) - { - s_ServerObjectPool.Dispose(); - } - } - - private static void SetupSpawnedObject(OneNetVar spawnedObject) - { - spawnedObject.Initialize(); - } - - private static void StopSpawnedObject(OneNetVar destroyedObject) - { - OneNetVar.Stop(); - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/NetworkVariablePerformanceTests.cs.meta b/testproject/Legacy/MultiprocessRuntime/NetworkVariablePerformanceTests.cs.meta deleted file mode 100644 index 492f738794..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/NetworkVariablePerformanceTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 91f4160a1de3f40c1bcdb9c18daf9bf2 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/TestCoordinator.cs b/testproject/Legacy/MultiprocessRuntime/TestCoordinator.cs deleted file mode 100644 index 0e62bf0edb..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/TestCoordinator.cs +++ /dev/null @@ -1,506 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using Unity.Netcode; -using NUnit.Framework; -using UnityEngine; -using Unity.Netcode.MultiprocessRuntimeTests; -using Unity.Netcode.Transports.UTP; - -/// -/// TestCoordinator -/// Used for coordinating multiprocess end to end tests. Used to call RPCs on other nodes and gather results -/// This is needed to coordinate server and client execution steps. The current remote player test runner hardcodes test -/// to run in a bootstrap scene before launching the player and doesn't call each tests individually. There's not opportunity -/// to coordinate test execution between client and server with that model. -/// The only per tests communication already existing is to get the results per test as they are running -/// With this test coordinator, it's not possible to start a main test node with the test runner and have that server start other worker nodes -/// on which to execute client tests. We use netcode as both a test framework and as the target of our performance tests. -/// -[RequireComponent(typeof(NetworkObject))] -public class TestCoordinator : NetworkBehaviour -{ - public const int PerTestTimeoutSec = 5 * 60; // seconds - - public const float MaxWaitTimeoutSec = 60; - private const char k_MethodFullNameSplitChar = '@'; - - private bool m_ShouldShutdown; - private float m_TimeSinceLastConnected; - private float m_TimeSinceLastKeepAlive; - - public static TestCoordinator Instance; - - private Dictionary> m_TestResultsLocal = new Dictionary>(); // this isn't super efficient, but since it's used for signaling around the tests, shouldn't be too bad - private Dictionary m_ClientIsFinished = new Dictionary(); - - public static List AllClientIdsWithResults => Instance.m_TestResultsLocal.Keys.ToList(); - public static List AllClientIdsExceptMine => NetworkManager.Singleton.ConnectedClients.Keys.ToList().FindAll(client => client != NetworkManager.Singleton.LocalClientId); - - // Multimachine support - private static int s_ProcessId; - public static string Rawgithash; - - private ConfigurationType m_ConfigurationType; - public ConfigurationType ConfigurationType - { - get { return m_ConfigurationType; } - private set - { - if (m_ConfigurationType != value) - { - m_ConfigurationType = value; - } - } - } - private string m_ConnectAddress = "127.0.0.1"; - public static string Port = "7777"; - private bool m_IsClient; - - private void SetConfigurationTypeAndConnect(ConfigurationType type) - { - ConfigurationType = type; - SetAddressAndPort(); - bool startClientResult = NetworkManager.Singleton.StartClient(); - MultiprocessLogger.Log($"Starting client"); - } - - public void Awake() - { - enabled = false; - NetworkManager.OnClientConnectedCallback += OnClientConnectedCallback; - - MultiprocessLogger.Log("Awake - Initialize All Steps"); - ExecuteStepInContext.InitializeAllSteps(); - - s_ProcessId = Process.GetCurrentProcess().Id; - ReadGitHashFile(); - - // Configuration via command line (supported for many but not all platforms) - bool isClient = Environment.GetCommandLineArgs().Any(value => value == MultiprocessOrchestration.IsWorkerArg); - if (isClient) - { - MultiprocessLogger.Log("Setting up via command line - client"); - m_IsClient = isClient; - var cli = new CommandLineProcessor(Environment.GetCommandLineArgs()); - if (Environment.GetCommandLineArgs().Any(value => value == "-ip")) - { - m_ConnectAddress = cli.TransportAddress; - } - if (Environment.GetCommandLineArgs().Any(value => value == "-p")) - { - Port = cli.TransportPort; - } - SetConfigurationTypeAndConnect(ConfigurationType.CommandLine); - } - - if (ConfigurationType == ConfigurationType.Unknown) - { - bool isHost = Environment.GetCommandLineArgs().Any(value => value == "host"); - if (isHost) - { - MultiprocessLogger.Log("Setting up via command line - host"); - var cli = new CommandLineProcessor(Environment.GetCommandLineArgs()); - ConfigurationType = ConfigurationType.CommandLine; - } - } - - - // Configuration via configuration file - all platform support but set at build time - if (ConfigurationType == ConfigurationType.Unknown) - { - //TODO: For next PR - } - - // configuration via WebApi - works on all platforms and is set at run time - if (ConfigurationType == ConfigurationType.Unknown) - { - MultiprocessLogger.Log($"Awake {s_ProcessId} - Calling ConfigureViewWebApi"); - ConfigureViaWebApi(); - MultiprocessLogger.Log($"Awake {s_ProcessId} - Calling ConfigureViewWebApi completed"); - } - - - // if we've tried all the configuration types and none of them are correct then we should log it and just go with the default values - if (ConfigurationType == ConfigurationType.Unknown) - { - MultiprocessLogger.Log("Unable to determine configuration for NetworkManager via commandline, webapi or config file"); - } - - if (Instance != null) - { - MultiprocessLogger.LogError("Multiple test coordinator, destroying this instance"); - Destroy(gameObject); - return; - } - - Instance = this; - } - - private async void ConfigureViaWebApi() - { - MultiprocessLogger.Log($"ConfigureViaWebApi - start"); - var jobQueue = await ConfigurationTools.GetRemoteConfig(); - foreach (var job in jobQueue.JobQueueItems) - { - if (Rawgithash.Equals(job.GitHash)) - { - ConfigurationTools.ClaimJobQueueItem(job); - m_ConnectAddress = job.HostIp; - m_IsClient = true; - MultiprocessLogHandler.JobId = job.JobId; - SetConfigurationTypeAndConnect(ConfigurationType.Remote); - break; - } - else - { - MultiprocessLogger.Log($"No match between {Rawgithash} and {job.GitHash}"); - } - } - MultiprocessLogger.Log($"ConfigureViaWebApi - end {ConfigurationType}"); - } - - private void ReadGitHashFile() - { - Rawgithash = "uninitialized"; - try - { - var githash_resource = Resources.Load("Text/githash"); - if (githash_resource != null) - { - Rawgithash = githash_resource.ToString(); - if (!string.IsNullOrEmpty(Rawgithash)) - { - Rawgithash = Rawgithash.Trim(); - MultiprocessLogger.Log($"Rawgithash is {Rawgithash}"); - } - } - } - catch (Exception e) - { - MultiprocessLogger.Log($"Exception getting githash resource file: {e.Message}"); - } - } - - private void SetAddressAndPort() - { - MultiprocessLogger.Log($"SetAddressAndPort - {Port} {m_ConnectAddress} {m_IsClient} "); - var ushortport = ushort.Parse(Port); - var transport = NetworkManager.Singleton.NetworkConfig.NetworkTransport; - MultiprocessLogger.Log($"transport is {transport}"); - switch (transport) - { - case UnityTransport unityTransport: - MultiprocessLogger.Log($"Setting unityTransport.ConnectionData.Port {ushortport}, isClient: {m_IsClient}, Address {m_ConnectAddress}"); - unityTransport.ConnectionData.Port = ushortport; - unityTransport.ConnectionData.Address = m_ConnectAddress; - break; - default: - MultiprocessLogger.LogError($"The transport {transport} has no case"); - break; - } - } - - public void Start() - { - MultiprocessLogger.Log($"TestCoordinator - Start"); - } - - public void Update() - { - if (Time.time - m_TimeSinceLastKeepAlive > PerTestTimeoutSec) - { - QuitApplication(); - Assert.Fail("Stayed idle too long"); - } - - if ((IsServer && NetworkManager.Singleton.IsListening) || (IsClient && NetworkManager.Singleton.IsConnectedClient)) - { - m_TimeSinceLastConnected = Time.time; - } - else if (Time.time - m_TimeSinceLastConnected > MaxWaitTimeoutSec || m_ShouldShutdown) - { - // Make sure we don't have zombie processes - MultiprocessLogger.Log($"quitting application, shouldShutdown set to {m_ShouldShutdown}, is listening {NetworkManager.Singleton.IsListening}, is connected client {NetworkManager.Singleton.IsConnectedClient}"); - if (!m_ShouldShutdown) - { - QuitApplication(); - Assert.Fail($"something wrong happened, was not connected for {Time.time - m_TimeSinceLastConnected} seconds"); - } - } - } - - private static void QuitApplication() - { -#if UNITY_EDITOR - UnityEditor.EditorApplication.isPlaying = false; -#else - Application.Quit(); -#endif - } - - public void TestRunTeardown() - { - m_TestResultsLocal.Clear(); - } - - public void OnEnable() - { - MultiprocessLogger.Log("OnEnable - Setting OnClientDisconnectCallback"); - NetworkManager.OnClientDisconnectCallback += OnClientDisconnectCallback; - } - - public void OnDisable() - { - if (IsSpawned && NetworkObject != null && NetworkObject.NetworkManager != null) - { - MultiprocessLogger.Log("OnDisable - Removing OnClientDisconnectCallback"); - NetworkManager.OnClientDisconnectCallback -= OnClientDisconnectCallback; - } - - base.OnDestroy(); - } - - // Once we are connected, we can run the update method - public void OnClientConnectedCallback(ulong clientId) - { - if (enabled == false) - { - MultiprocessLogger.Log($"OnClientConnectedCallback enabling behavior clientId: {clientId} {NetworkManager.Singleton.IsHost}/{NetworkManager.Singleton.IsClient} IsRegistering:{ExecuteStepInContext.IsRegistering}"); - enabled = true; - } - } - - private static void OnClientDisconnectCallback(ulong clientId) - { - if (clientId == NetworkManager.ServerClientId || clientId == NetworkManager.Singleton.LocalClientId) - { - // if disconnect callback is for me or for server, quit, we're done here - MultiprocessLogger.Log($"received disconnect from {clientId}, quitting"); - QuitApplication(); - } - } - - private static string GetMethodInfo(Action method) - { - return $"{method.Method.DeclaringType.FullName}{k_MethodFullNameSplitChar}{method.Method.Name}"; - } - - private static string GetMethodInfo(Action method) - { - return $"{method.Method.DeclaringType.FullName}{k_MethodFullNameSplitChar}{method.Method.Name}"; - } - - public static IEnumerable<(ulong clientId, float result)> ConsumeCurrentResult() - { - foreach (var kv in Instance.m_TestResultsLocal) - { - while (kv.Value.Count > 0) - { - var toReturn = (kv.Key, kv.Value[0]); - kv.Value.RemoveAt(0); - yield return toReturn; - } - } - } - - public static IEnumerable ConsumeCurrentResult(ulong clientId) - { - var allResults = Instance.m_TestResultsLocal[clientId]; - while (allResults.Count > 0) - { - var toReturn = allResults[0]; - allResults.RemoveAt(0); - yield return toReturn; - } - } - - public static float PeekLatestResult(ulong clientId) - { - if (Instance.m_TestResultsLocal.ContainsKey(clientId) && Instance.m_TestResultsLocal[clientId].Count > 0) - { - return Instance.m_TestResultsLocal[clientId].Last(); - } - - return float.NaN; - } - - /// - /// Returns appropriate lambda according to parameters - /// Includes time check to make sure this times out - /// - /// - /// - /// - public static Func ResultIsSet(bool useTimeoutException = true) - { - var startWaitTime = Time.time; - return () => - { - if (Time.time - startWaitTime > MaxWaitTimeoutSec) - { - if (useTimeoutException) - { - throw new Exception($"timeout while waiting for results, didn't get results for {Time.time - startWaitTime} seconds"); - } - - return true; - } - - foreach (var clientIdAndTestResultList in Instance.m_TestResultsLocal) - { - if (clientIdAndTestResultList.Value.Count > 0) - { - return true; - } - } - - return false; - }; - } - - public static Func ConsumeClientIsFinished(ulong clientId, bool useTimeoutException = true) - { - var startWaitTime = Time.time; - return () => - { - if (Time.time - startWaitTime > MaxWaitTimeoutSec) - { - if (useTimeoutException) - { - throw new Exception($"timeout while waiting for client finished, didn't get results for {Time.time - startWaitTime} seconds"); - } - else - { - return true; - } - } - - if (Instance.m_ClientIsFinished.ContainsKey(clientId) && Instance.m_ClientIsFinished[clientId]) - { - Instance.m_ClientIsFinished[clientId] = false; // consume - return true; - } - - return false; - }; - } - - [Rpc(SendTo.Server)] - public void ClientFinishedServerRpc(ServerRpcParams p = default) - { - // signal from clients to the server to say the client is done with it's task - m_ClientIsFinished[p.Receive.SenderClientId] = true; - } - - public void InvokeFromMethodActionRpc(Action methodInfo, params byte[] args) - { - var methodInfoString = GetMethodInfo(methodInfo); - InvokeFromMethodNameClientRpc(methodInfoString, args, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdsExceptMine.ToArray() } }); - } - - public void InvokeFromMethodActionRpc(Action methodInfo) - { - var methodInfoString = GetMethodInfo(methodInfo); - InvokeFromMethodNameClientRpc(methodInfoString, null, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = AllClientIdsExceptMine.ToArray() } }); - } - - [ClientRpc] - public void TriggerActionIdClientRpc(string actionId, byte[] args, bool ignoreException, ClientRpcParams clientRpcParams = default) - { - MultiprocessLogger.Log($"received RPC from server, client side triggering action ID {actionId}"); - WriteLogServerRpc($"received RPC from server, client side triggering action ID {actionId} {ExecuteStepInContext.AllActions.Count}"); - try - { - ExecuteStepInContext.AllActions[actionId].Invoke(args); - } - catch (Exception e) - { - WriteErrorServerRpc(e.ToString()); - - if (!ignoreException) - { - throw; - } - else - { - Instance.ClientFinishedServerRpc(); - } - } - } - - [ClientRpc] - public void InvokeFromMethodNameClientRpc(string methodInfoString, byte[] args, ClientRpcParams clientRpcParams = default) - { - try - { - var split = methodInfoString.Split(k_MethodFullNameSplitChar); - var (classToExecute, staticMethodToExecute) = (split[0], split[1]); - - var foundType = Type.GetType(classToExecute) ?? throw new Exception($"couldn't find {classToExecute}"); - var foundMethod = foundType.GetMethod(staticMethodToExecute, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) ?? throw new MissingMethodException($"couldn't find method {staticMethodToExecute}"); - foundMethod.Invoke(null, args != null ? new object[] { args } : null); - } - catch (Exception e) - { - WriteErrorServerRpc(e.ToString()); - throw; - } - } - - [ClientRpc] - public void CloseRemoteClientRpc() - { - try - { - NetworkManager.Singleton.Shutdown(); - m_ShouldShutdown = true; // wait until isConnectedClient is false to run Application Quit in next update - MultiprocessLogger.Log("Quitting player cleanly"); - Application.Quit(); - } - catch (Exception e) - { - WriteErrorServerRpc(e.ToString()); - throw; - } - } - - [ClientRpc] - public void KeepAliveClientRpc() - { - m_TimeSinceLastKeepAlive = Time.time; - } - - [Rpc(SendTo.Server)] - public void WriteTestResultsServerRpc(float result, ServerRpcParams receiveParams = default) - { - var senderId = receiveParams.Receive.SenderClientId; - MultiprocessLogger.Log($"Server received result [{result}] from sender [{senderId}]"); - if (!m_TestResultsLocal.ContainsKey(senderId)) - { - m_TestResultsLocal[senderId] = new List(); - } - - m_TestResultsLocal[senderId].Add(result); - } - - /// - /// Use this to communicate client-side errors for server-side logging using the MultiprocessLogger. - /// - /// - /// Use to log server-side without MultiprocessLogger formatting. - /// - [Rpc(SendTo.Server)] - public void WriteErrorServerRpc(string errorMessage, ServerRpcParams receiveParams = default) - { - MultiprocessLogger.LogError($"[Netcode-Server Sender={receiveParams.Receive.SenderClientId}] {errorMessage}"); - } - - [Rpc(SendTo.Server)] - public void WriteLogServerRpc(string logMessage, ServerRpcParams receiveParams = default) - { - MultiprocessLogger.Log($"[Netcode-Server Sender={receiveParams.Receive.SenderClientId}] {logMessage}"); - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/TestCoordinator.cs.meta b/testproject/Legacy/MultiprocessRuntime/TestCoordinator.cs.meta deleted file mode 100644 index f8c2a3c472..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/TestCoordinator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ef1240e0784f84eadb77fe822e2e03c7 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/TestCoordinatorTests.cs b/testproject/Legacy/MultiprocessRuntime/TestCoordinatorTests.cs deleted file mode 100644 index 3152627cbd..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/TestCoordinatorTests.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Collections; -using System.Linq; -using NUnit.Framework; -using UnityEngine; -using UnityEngine.TestTools; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - [TestFixture(1)] - [TestFixture(2)] - public class TestCoordinatorTests : BaseMultiprocessTests - { - private int m_WorkerCount; - protected override int WorkerCount => m_WorkerCount; - - protected override bool IsPerformanceTest => false; - - public TestCoordinatorTests(int workerCount) - { - m_WorkerCount = workerCount; - } - - private static float s_ValueToValidateAgainst; - private static void ValidateSimpleCoordinatorTestValue(float resultReceived) - { - Assert.AreEqual(s_ValueToValidateAgainst, resultReceived); - } - - private static void ExecuteSimpleCoordinatorTest() - { - s_ValueToValidateAgainst = float.PositiveInfinity; - TestCoordinator.Instance.WriteTestResultsServerRpc(s_ValueToValidateAgainst); - } - - private static void ExecuteWithArgs(byte[] args) - { - s_ValueToValidateAgainst = args[0]; - TestCoordinator.Instance.WriteTestResultsServerRpc(s_ValueToValidateAgainst); - } - - [UnityTest] - public IEnumerator CheckTestCoordinator() - { - // Sanity check for TestCoordinator - // Call the method - TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteSimpleCoordinatorTest); - - var nbResults = 0; - for (int i = 0; i < WorkerCount; i++) // wait and test for the two clients - { - yield return new WaitUntil(TestCoordinator.ResultIsSet()); - - var (clientId, result) = TestCoordinator.ConsumeCurrentResult().Take(1).Single(); - Assert.Greater(result, 0f); - nbResults++; - } - Assert.That(nbResults, Is.EqualTo(WorkerCount)); - } - - [UnityTest] - public IEnumerator CheckTestCoordinatorWithArgs() - { - TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteWithArgs, 99); - var nbResults = 0; - - for (int i = 0; i < WorkerCount; i++) // wait and test for the two clients - { - yield return new WaitUntil(TestCoordinator.ResultIsSet()); - - var (clientId, result) = TestCoordinator.ConsumeCurrentResult().Take(1).Single(); - Assert.That(result, Is.EqualTo(99)); - nbResults++; - } - Assert.That(nbResults, Is.EqualTo(WorkerCount)); - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/TestCoordinatorTests.cs.meta b/testproject/Legacy/MultiprocessRuntime/TestCoordinatorTests.cs.meta deleted file mode 100644 index 104be914d0..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/TestCoordinatorTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f5e62651568514685a0b50d623fa8a96 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/ThreeDText.cs b/testproject/Legacy/MultiprocessRuntime/ThreeDText.cs deleted file mode 100644 index 232c8ca05f..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/ThreeDText.cs +++ /dev/null @@ -1,88 +0,0 @@ -using UnityEngine; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class ThreeDText : MonoBehaviour - { - public bool IsTestCoordinatorActiveAndEnabled = false; - public string CommandLineArguments = ""; - private long m_UpdateCounter; - private bool m_HasFired; - private string m_TransportString; - - public void Awake() - { - if (MultiprocessOrchestration.IsPerformanceTest) - { - gameObject.SetActive(false); - } - } - - // Start is called before the first frame update - public void Start() - { - Debug.Log("ThreeDText - Start"); - m_HasFired = false; - m_UpdateCounter = 0; - m_TransportString = "null"; - var jsonTextFile = Resources.Load("Text/multiprocess_tests"); - Debug.Log(jsonTextFile); - - var t = GetComponent(); - t.text = "On Start"; - CommandLineArguments = System.Environment.CommandLine; - - string[] args = System.Environment.GetCommandLineArgs(); - foreach (var arg in args) - { - if (arg.Length > 15) - { - CommandLineArguments += " " + arg.Substring(0, 14); - } - else - { - CommandLineArguments += "\n" + arg; - } - } - } - - // Update is called once per frame - public void Update() - { - m_UpdateCounter++; - var testCoordinator = TestCoordinator.Instance; - if (testCoordinator == null) - { - return; - } - - var transport = NetworkManager.Singleton?.NetworkConfig.NetworkTransport; - var transportString = ""; - if (transport == null) - { - transportString = "null"; - } - else - { - transportString = transport.ToString(); - } - - var t = GetComponent(); - - if (IsTestCoordinatorActiveAndEnabled != testCoordinator.isActiveAndEnabled || - !m_HasFired || - m_UpdateCounter % 25 == 0 || - !m_TransportString.Equals(transportString)) - { - m_HasFired = true; - m_TransportString = transportString; - IsTestCoordinatorActiveAndEnabled = testCoordinator.isActiveAndEnabled; - t.text = $"On Update -\ntestCoordinator.isActiveAndEnabled:{testCoordinator.isActiveAndEnabled} {testCoordinator.ConfigurationType}\n" + - $"Transport: {transportString}\n" + - $"{CommandLineArguments}\n" + - $"IsHost: {NetworkManager.Singleton.IsHost} IsClient: {NetworkManager.Singleton.IsClient} {NetworkManager.Singleton.IsConnectedClient}\n" + - $"{m_UpdateCounter}\n"; - } - } - } -} diff --git a/testproject/Legacy/MultiprocessRuntime/ThreeDText.cs.meta b/testproject/Legacy/MultiprocessRuntime/ThreeDText.cs.meta deleted file mode 100644 index 9d9011054b..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/ThreeDText.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 04cf3cc1396054b009a1ed283aa50021 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Building-Player.jpg b/testproject/Legacy/MultiprocessRuntime/readme-ressources/Building-Player.jpg deleted file mode 100644 index 8663fcf757..0000000000 Binary files a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Building-Player.jpg and /dev/null differ diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Multiprocess.jpg b/testproject/Legacy/MultiprocessRuntime/readme-ressources/Multiprocess.jpg deleted file mode 100644 index 72f13b3f05..0000000000 Binary files a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Multiprocess.jpg and /dev/null differ diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Multiprocess.jpg.meta b/testproject/Legacy/MultiprocessRuntime/readme-ressources/Multiprocess.jpg.meta deleted file mode 100644 index 6d73b54a8f..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/readme-ressources/Multiprocess.jpg.meta +++ /dev/null @@ -1,96 +0,0 @@ -fileFormatVersion: 2 -guid: d2e6ce5793e6a4e74843dca06fd36778 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources/OrchestrationOverview.jpg b/testproject/Legacy/MultiprocessRuntime/readme-ressources/OrchestrationOverview.jpg deleted file mode 100644 index f346dd85b7..0000000000 Binary files a/testproject/Legacy/MultiprocessRuntime/readme-ressources/OrchestrationOverview.jpg and /dev/null differ diff --git a/testproject/Legacy/MultiprocessRuntime/readme-ressources/OrchestrationOverview.jpg.meta b/testproject/Legacy/MultiprocessRuntime/readme-ressources/OrchestrationOverview.jpg.meta deleted file mode 100644 index 84c6f4f98b..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/readme-ressources/OrchestrationOverview.jpg.meta +++ /dev/null @@ -1,96 +0,0 @@ -fileFormatVersion: 2 -guid: 7b6f909ad23994f9c9cb51710d1e1e07 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 11 - mipmaps: - mipMapMode: 0 - enableMipMap: 1 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 0 - wrapV: 0 - wrapW: 0 - nPOTScale: 1 - lightmap: 0 - compressionQuality: 50 - spriteMode: 0 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 0 - spriteTessellationDetail: -1 - textureType: 0 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spritePackingTag: - pSDRemoveMatte: 0 - pSDShowRemoveMatteOption: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Legacy/MultiprocessRuntime/readme.md b/testproject/Legacy/MultiprocessRuntime/readme.md deleted file mode 100644 index 6efdcba540..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/readme.md +++ /dev/null @@ -1,279 +0,0 @@ -# Multiprocess testing - -## Why -Multiprocess testing can be used for different use cases like -- integration tests (Netcode + actual transport or multi-scene testing for example) -- performance testing. -- Anything requiring a more realistic environment for testing that involves having a full client and server, communicating on a real network interface using real transports in separate Unity processes. - -The tests you write and test locally will be deployed dynamically to bokken instances. The tests shouldn't have to worry about what hardware it runs on, this should be abstracted away by "workers" and "coordinator". - -## How to write a multiprocess test -There's a few steps to write a multiprocess test - -1. Your test class needs to inherit from `BaseMultiprocessTests` -2. Each test method needs the `MultiprocessContextBasedTest` attribute -3. Each test method needs to run `InitializeContextSteps();` -4. Each context based step can use -```cs -yield return new ExecuteStepInContext(StepExecutionContext.Clients, stepToExecute: nbObjectsBytes => { - // Something here -}); -``` -A test method would look like -```cs - [UnityTest, MultiprocessContextBasedTest] - public IEnumerator MyTest() - { - InitializeContextSteps(); // the only call that should be made outside of context based tests - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Debug.Log("server stuff"); - }); - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - Debug.Log("client stuff"); - Assert.That(1, Is.EqualTo(1)); - throw new Exception("asdf"); // this client side exception will be communicated to the coordinator, making the test fail - }); - } -``` -Your test code shouldn't execute outside of these steps (as that test method can be executed multiple times, once for step registration and once for the actual test run for example) - -Another way to write a multiprocess test without context based steps is to use TestCoordinator directly. -```cs - private static void ExecuteSimpleCoordinatorTest() - { - TestCoordinator.Instance.WriteTestResultsServerRpc(float.PositiveInfinity); - } - - [UnityTest] - public IEnumerator CheckTestCoordinator() - { - // Call the client side method - TestCoordinator.Instance.InvokeFromMethodActionRpc(ExecuteSimpleCoordinatorTest); - - var resultCount = 0; - for (int i = 0; i < WorkerCount; i++) // wait and test for the two clients - { - yield return new WaitUntil(TestCoordinator.ResultIsSet()); - - var (clientId, result) = TestCoordinator.ConsumeCurrentResult().Take(1).Single(); - Assert.Greater(result, 0f); - resultCount++; - } - - Assert.That(resultCount, Is.EqualTo(WorkerCount)); - } -``` - -Here's a complete set of examples using the API - -```cs -using System; -using System.Collections; -using System.Collections.Generic; -using NUnit.Framework; -using Unity.PerformanceTesting; -using UnityEngine; -using UnityEngine.Profiling; -using UnityEngine.TestTools; -using static ExecuteStepInContext; - -namespace Unity.Netcode.MultiprocessRuntimeTests -{ - public class DemoProcessTest : BaseMultiprocessTests - { - protected override int WorkerCount { get; } = 2; // spawns 2 clients connecting to the test runner - protected override bool m_IsPerformanceTest { get; } = false; // specifies whether this should execute from editor or not - - [UnityTest, MultiprocessContextBasedTest] // attribute necessary for context based step execution - public IEnumerator MyTest() - { - InitializeContextSteps(); // necessary to initialize context based steps - - // These steps execute sequentially. - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - Debug.Log("server stuff"); - }); - // for example, the test runner will yield on the same step until clients all report they are done with this step. Once all clients report they are done, the test can continue to the same step. - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - Debug.Log("client stuff"); - Assert.That(1, Is.EqualTo(1)); - throw new Exception("asdf"); // this client side exception will be communicated to the coordinator, making the test fail - }); - - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - // To write results to the test runner, call this method: - TestCoordinator.Instance.WriteTestResultsServerRpc(123); - TestCoordinator.Instance.WriteTestResultsServerRpc(123); - TestCoordinator.Instance.WriteTestResultsServerRpc(123); // could be replaced by json string instead for ease of use? - }); - yield return new ExecuteStepInContext(StepExecutionContext.Server, bytes => - { - // consumes first result sent above from any client - TestCoordinator.ConsumeCurrentResult(); - // consumes all results from all clients - foreach (var (clientID, result) in TestCoordinator.ConsumeCurrentResult()) - { - Assert.That(result, Is.EqualTo(123)); - } - // consumes results for individual clients - foreach (var clientID in TestCoordinator.AllClientIdsExceptMine) - { - TestCoordinator.ConsumeCurrentResult(clientID); - } - }); - - int someValue = 456; // one caveat to executeStepInContext is contrary to instinct, this is not shared between server and client execution. - // to send that value to clients, "paramToPass" needs to be used - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - var valueComingFromServer = BitConverter.ToInt32(bytes, 0); - }, paramToPass: BitConverter.GetBytes(456)); // could be replaced by JSON string instead for ease of use? - // useful for taking in [Values] method parameters as these are only known by the server - - // when you have client steps that take more than one frame, you can subscribe to the OnUpdate callback on CallbackComponent - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - void Update(float _) - { - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate -= Update; - TestCoordinator.Instance.ClientFinishedServerRpc(); // since finishOnInvoke is false, we need to do this manually - } - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; - }, waitMultipleUpdates: true); // this keeps waiting "are you done? are you done? are you done?" and relies on the clients calling the "ClientFinishedServerRpc" - - yield return new ExecuteStepInContext(StepExecutionContext.Clients, bytes => - { - int cpt = 0; - void Update(float _) - { - TestCoordinator.Instance.WriteTestResultsServerRpc(Time.time); - } - NetworkManager.Singleton.gameObject.GetComponent().OnUpdate += Update; - }, additionalIsFinishedWaiter: () => // this keeps waiting "are you done? are you done? are you done?" until this lambda returns true - { - foreach (var (clientId, latest) in TestCoordinator.ConsumeCurrentResult()) - { - return latest >= 10; - } - return false; - }); - } - - [UnityTest, Performance] // already existing performance framework https://docs.unity3d.com/Packages/com.unity.test-framework.performance@2.8/manual/index.html - public IEnumerator PerfTest() - { - var totalAllocSampleGroup = new SampleGroup("GC Alloc", SampleUnit.Kilobyte); - var allocStat = Profiler.GetTotalAllocatedMemoryLong(); - Measure.Custom(totalAllocSampleGroup, allocStat / 1024); // this will record in Unity's shared Performance DB. - // Dashboards will be able to display these stats overtime - yield return null; - } - } -} - - -``` - - -## How to run a test -**Local**: Test players need to be built first to test locally. - -**Automated**: Integration with CI should do this automatically. - -![](readme-ressources/Building-Player.jpg) - -Then run the tests from Unity's test runner. - -Note that performance tests should be run from external processes (not from editor). This way the server code will run in a build, just as much as client code, for more realistic test results. - -![](readme-ressources/Multiprocess.jpg) - -## How it's done -### Multiple processes orchestration - -Test code and host code execute in the same process: When writing play mode tests, Unity will start a unity environment for that test, including game loop, scene, object hierarchy, all that fun stuff. This means the test itself has access to everything other unity scripts would have access to. At test startup, the test will ask unity to switch scene to MultiprocessTestScene containing a GameObject already placed in that scene called TestCoordinator . The test will callStartHost that will listen for connections, still all in the same process. -Once that's done, that same test will then spawn new client processes. These clients will also start with that MultiprocessTestScene loaded at startup, also containing a TestCoordinator . These client side TestCoordinators will detect they are clients (using command line arg) and instead of calling StartHost will call StartClient . This is where new code to specify the IP to connect to would stand (the lines I sent you). -A good way I could have clarified that code is to separate TestCoordinator into TestCoordinatorClient and TestCoordinatorServer thinking of it. Right now TestCoordinator code does both. -Once the connection is established (tests yield wait for connection in Setup code), then the tests can start sending RPCs to each other. -The test (that's server side) will call multiple TriggerActionIdClientRpc . This will trigger these actions on all clients. The clients execute their test code, then answer back with ClientFinishedServerRpc. -Once all the tests are done exchanging commands, a final RPC CloseRemoteClientRpc is called to tell the clients they are done. -If that RPC fails to send for some reason, clients also have a keep alive that tells them to self destroy when it expires. -If you look at the “how it's done” section in the multiprocess readme.md testproject/Assets/Tests/Runtime/MultiprocessRuntime/readme.md there's a few drawings to explain that flow. - -So: -Editor -- Run tests -- Run host code -- Launches builds -Separate build -- Runs client RPCs that execute test code, not the tests themselves - - -Now just to bake your noodles a bit more, Unity will take an additional step before launching these steps. The above is true if you launch these tests from the editor. If you launch these tests in a separate player, Unity in the background will create a separate process for that player. That player will then connect using a plain tcp connection to the editor to report back on its test results. This is important to know if you want to have the test/host part launch on different platforms like mobile. - -So the above would become -Editor -- Launches test player on platform -Test player -- Run tests -- Run host code -- Launches builds -Separate build -- Runs client RPCs … - -With the bokken integration, we'll need to be careful about ressource contention at Unity, these tests could be heavy on ressources. -Tests when launched locally will simply create new OS processes for each worker players. - - - -![](readme-ressources/OrchestrationOverview.jpg) -*Note that this diagram is still WIP for the CI part* -### Bokken orchestration -Bokken Orchestration can be performed with the support of the following tool: -[Multiplayer Multiprocess Test Tools](https://github.cds.internal.unity3d.com/unity/multiplayer-multiprocess-test-tools) -[Documentation](https://backstage.corp.unity3d.com/catalog/default/component/multiplayer-multiprocess-test-tools/docs/) - -### CI -todo -#### Performance report dashboards -todo -### Client-server test coordination -A Test Coordinator is in charge of managing communication between the nodes, executing remote test code. The test coordinator is also in charge of process cleanup, if for example the server crashes, so we don't have zombie clients laying around. -The test coordinator in client mode will automatically try to connect to a server on Start(). -### Context based step execution -Test methods are executed twice. Once in "registration" mode, to have all the steps register themselves using a unique ID. This ID is deterministic between client and server processes, so that when a server calls a step during actual test execution, the clients have the same ID associated with the same lambda. -During test execution, the main node's step will call an RPC on clients to trigger their pre-registered lambda. The main node's step will then yield until it receives a "client done" RPC from all clients. The main node's test will then be able to continue execution to the next step. - -## The MultiprocessTestPlayer -The MultiprocessTestPlayer, which is built by the sub-menu items under "Netcode" -> "Multiprocess Test", supports many workflows and configurations. - -### Command Line -Currently the MultiprocessTestPlayer can be configured via the command line on all platforms that support parsing of command line arguments in the C# layer. -For example, this means that command line configuration is not available on Android. - -#### Setting the transport address -Default Values on Client: 127.0.0.1, 3076 - -In order to set the transport address for either the server/host or the client, the options of "-ip" and "-p" can be used. For example: - - -ip 127.0.0.1 -p 3076 - -These options can be passed when starting the client, for example, in order to let it know where the host is to connect to. - -#### Setting the transport -Default Values: UNET - -The default transport is UNET but this can be switched to UTP by using - - -transport utp - - -# Future considerations -- Integrate with local MultiInstance tests? -- Have ExecuteStepInContext a game facing feature for sequencing client-server actions? diff --git a/testproject/Legacy/MultiprocessRuntime/testproject.multiprocesstests.asmdef b/testproject/Legacy/MultiprocessRuntime/testproject.multiprocesstests.asmdef deleted file mode 100644 index 13baf50a69..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/testproject.multiprocesstests.asmdef +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "TestProject.MultiprocessTests", - "rootNamespace": "", - "references": [ - "Unity.Netcode.Runtime", - "TestProject", - "Unity.Netcode.Editor", - "Unity.Netcode.Components", - "ScriptsForAutomatedTesting", - "Unity.PerformanceTesting", - "UnityEngine.TestRunner", - "UnityEditor.TestRunner" - ], - "includePlatforms": [ - "Editor", - "macOSStandalone", - "LinuxStandalone64", - "WindowsStandalone32", - "WindowsStandalone64" - ], - "excludePlatforms": [], - "allowUnsafeCode": true, - "overrideReferences": false, - "precompiledReferences": [ - "nunit.framework.dll" - ], - "autoReferenced": true, - "defineConstraints": [ - "UNITY_INCLUDE_TESTS" - ], - "noEngineReferences": false, - "versionDefines": [ - ] -} diff --git a/testproject/Legacy/MultiprocessRuntime/testproject.multiprocesstests.asmdef.meta b/testproject/Legacy/MultiprocessRuntime/testproject.multiprocesstests.asmdef.meta deleted file mode 100644 index a06b37d08b..0000000000 --- a/testproject/Legacy/MultiprocessRuntime/testproject.multiprocesstests.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 66273ab9e01074f7da305fe84e13da47 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/testproject/Packages/manifest.json b/testproject/Packages/manifest.json index f7832aaad0..7b76e49c59 100644 --- a/testproject/Packages/manifest.json +++ b/testproject/Packages/manifest.json @@ -1,23 +1,23 @@ { "disableProjectUpdate": false, "dependencies": { - "com.unity.addressables": "2.7.4", - "com.unity.ai.navigation": "2.0.9", - "com.unity.collab-proxy": "2.10.1", - "com.unity.ide.rider": "3.0.38", - "com.unity.ide.visualstudio": "2.0.25", + "com.unity.addressables": "2.9.1", + "com.unity.ai.navigation": "2.0.12", + "com.unity.collab-proxy": "2.12.4", + "com.unity.ide.rider": "3.0.40", + "com.unity.ide.visualstudio": "2.0.26", "com.unity.mathematics": "1.3.3", - "com.unity.multiplayer.tools": "2.2.6", + "com.unity.multiplayer.tools": "2.2.8", "com.unity.netcode.gameobjects": "file:../../com.unity.netcode.gameobjects", "com.unity.package-validation-suite": "0.49.0-preview", - "com.unity.services.authentication": "3.5.2", - "com.unity.services.multiplayer": "1.2.0", + "com.unity.services.authentication": "3.6.1", + "com.unity.services.multiplayer": "2.1.3", "com.unity.test-framework": "1.6.0", - "com.unity.test-framework.performance": "3.2.0", - "com.unity.timeline": "1.8.9", - "com.unity.toolchain.win-x86_64-linux-x86_64": "2.0.11", + "com.unity.test-framework.performance": "3.5.0", + "com.unity.timeline": "1.8.12", "com.unity.ugui": "2.0.0", "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.adaptiveperformance": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", @@ -44,6 +44,7 @@ "com.unity.modules.unitywebrequestaudio": "1.0.0", "com.unity.modules.unitywebrequesttexture": "1.0.0", "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vectorgraphics": "1.0.0", "com.unity.modules.vehicles": "1.0.0", "com.unity.modules.video": "1.0.0", "com.unity.modules.vr": "1.0.0", diff --git a/testproject/Packages/packages-lock.json b/testproject/Packages/packages-lock.json deleted file mode 100644 index 675de94bf2..0000000000 --- a/testproject/Packages/packages-lock.json +++ /dev/null @@ -1,570 +0,0 @@ -{ - "dependencies": { - "com.unity.addressables": { - "version": "2.7.4", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.profiling.core": "1.0.2", - "com.unity.test-framework": "1.4.5", - "com.unity.modules.assetbundle": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.modules.imageconversion": "1.0.0", - "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.scriptablebuildpipeline": "2.4.3", - "com.unity.modules.unitywebrequestassetbundle": "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.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.1", - "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.ext.nunit": { - "version": "2.0.5", - "depth": 1, - "source": "builtin", - "dependencies": {} - }, - "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.3", - "depth": 0, - "source": "registry", - "dependencies": {}, - "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": "file:../../com.unity.netcode.gameobjects", - "depth": 0, - "source": "local", - "dependencies": { - "com.unity.nuget.mono-cecil": "1.11.4", - "com.unity.transport": "2.6.0" - } - }, - "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.package-validation-suite": { - "version": "0.49.0-preview", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.nuget.mono-cecil": "0.1.6-preview.2" - }, - "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.scriptablebuildpipeline": { - "version": "2.4.3", - "depth": 1, - "source": "registry", - "dependencies": { - "com.unity.test-framework": "1.4.5", - "com.unity.modules.assetbundle": "1.0.0" - }, - "url": "https://packages.unity.com" - }, - "com.unity.services.authentication": { - "version": "3.5.2", - "depth": 0, - "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.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": 0, - "source": "registry", - "dependencies": { - "com.unity.test-framework": "1.1.33", - "com.unity.modules.jsonserialize": "1.0.0" - }, - "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.11", - "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": 1, - "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.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.physics": "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/testproject/ProjectSettings/PackageManagerSettings.asset b/testproject/ProjectSettings/PackageManagerSettings.asset index b01b2f8da9..6e57db2799 100644 --- a/testproject/ProjectSettings/PackageManagerSettings.asset +++ b/testproject/ProjectSettings/PackageManagerSettings.asset @@ -12,32 +12,33 @@ MonoBehaviour: m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} m_Name: m_EditorClassIdentifier: - m_EnablePreviewPackages: 1 - m_EnablePackageDependencies: 1 + m_EnablePreReleasePackages: 0 m_AdvancedSettingsExpanded: 1 m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + m_DismissPreviewPackagesInUse: 0 oneTimeWarningShown: 1 - m_Registries: - - m_Id: main + oneTimePackageErrorsPopUpShown: 0 + m_MainRegistry: + m_Id: main m_Name: m_Url: https://packages.unity.com m_Scopes: [] m_IsDefault: 1 + m_IsUnityRegistry: 1 m_Capabilities: 7 + m_ConfigSource: 0 + m_Compliance: + m_Status: 0 + m_Violations: [] + m_ScopedRegistries: [] m_UserSelectedRegistryName: m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: - m_ErrorMessage: - m_Original: - m_Id: - m_Name: - m_Url: - m_Scopes: [] - m_IsDefault: 0 - m_Capabilities: 0 m_Modified: 0 - m_Name: - m_Url: - m_Scopes: - - - m_SelectedScopeIndex: 0 + m_ErrorMessage: + m_UserModificationsEntityId: + m_rawData: 568105584918791443 + m_OriginalEntityId: + m_rawData: 568105584918791444 + m_LoadAssets: 0 diff --git a/testproject/ProjectSettings/ProjectSettings.asset b/testproject/ProjectSettings/ProjectSettings.asset index 3bb16ba357..06561ea008 100644 --- a/testproject/ProjectSettings/ProjectSettings.asset +++ b/testproject/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 28 + serializedVersion: 30 productGUID: bba99b16607b94720b7d04f7f1a82989 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -41,7 +41,6 @@ PlayerSettings: height: 1 m_SplashScreenLogos: [] m_VirtualRealitySplashScreen: {fileID: 0} - m_HolographicTrackingLossScreen: {fileID: 0} defaultScreenWidth: 1280 defaultScreenHeight: 720 defaultScreenWidthWeb: 960 @@ -66,10 +65,15 @@ PlayerSettings: useOSAutorotation: 1 use32BitDisplayBuffer: 1 preserveFramebufferAlpha: 0 + adjustIOSFPSUsingThermalState: 1 + thermalStateSeriousIOSFPS: 30 + thermalStateCriticalIOSFPS: 15 disableDepthAndStencilBuffers: 0 androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 1 androidUseSwappy: 1 + androidRequestedVisibleInsets: 0 + androidSystemBarsBehavior: 2 androidDisplayOptions: 1 androidBlitType: 0 androidResizeableActivity: 0 @@ -84,6 +88,7 @@ PlayerSettings: defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 1 + callOnDisableOnAssetBundleUnload: 1 muteOtherAudioSources: 0 Prepare IOS For Recording: 0 Force IOS Speakers When Recording: 0 @@ -114,6 +119,7 @@ PlayerSettings: xboxEnableGuest: 0 xboxEnablePIXSampling: 0 metalFramebufferOnly: 0 + metalUseMetalDisplayLink: 0 xboxOneResolution: 0 xboxOneSResolution: 0 xboxOneXResolution: 3 @@ -147,12 +153,10 @@ PlayerSettings: preloadedAssets: [] metroInputSource: 0 wsaTransparentSwapchain: 0 - m_HolographicPauseOnTrackingLoss: 1 xboxOneDisableKinectGpuReservation: 1 xboxOneEnable7thCore: 1 vrSettings: enable360StereoCapture: 0 - isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 enableOpenGLProfilerGPURecorders: 1 allowHDRDisplaySupport: 0 @@ -174,9 +178,10 @@ PlayerSettings: tvOS: 0 overrideDefaultApplicationIdentifier: 0 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 23 + AndroidMinSdkVersion: 26 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 + AndroidPreferredDataLocation: 1 aotOptions: nimt-trampolines=1024 stripEngineCode: 1 iPhoneStrippingLevel: 0 @@ -191,13 +196,14 @@ PlayerSettings: VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 iOSSimulatorArchitecture: 0 - iOSTargetOSVersionString: 13.0 + iOSTargetOSVersionString: 15.0 tvOSSdkVersion: 0 tvOSSimulatorArchitecture: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 13.0 + tvOSTargetOSVersionString: 15.0 VisionOSSdkVersion: 0 VisionOSTargetOSVersionString: 1.0 + xcodeProjectType: 0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 @@ -451,12 +457,6 @@ PlayerSettings: - m_BuildTarget: WindowsStandaloneSupport m_APIs: 0200000012000000 m_Automatic: 0 - m_BuildTargetVRSettings: - - m_BuildTarget: Standalone - m_Enabled: 0 - m_Devices: - - Oculus - - OpenVR m_DefaultShaderChunkSizeInMB: 16 m_DefaultShaderChunkCount: 0 openGLRequireES31: 0 @@ -484,7 +484,7 @@ PlayerSettings: locationUsageDescription: microphoneUsageDescription: bluetoothUsageDescription: - macOSTargetOSVersion: 11.0 + macOSTargetOSVersion: 12.0 switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 @@ -630,6 +630,8 @@ PlayerSettings: switchMicroSleepForYieldTime: 25 switchRamDiskSpaceSize: 12 switchUpgradedPlayerSettingsToNMETA: 0 + switchCaStoreSource: 0 + switchCaStoreFilePath: ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -739,7 +741,7 @@ PlayerSettings: webWasm2023: 0 webEnableSubmoduleStrippingCompatibility: 0 scriptingDefineSymbols: - Standalone: UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT + Standalone: UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT;NETCODE_GAMEOBJECT_BRIDGE_EXPERIMENTAL;NETCODE_EXPERIMENTAL_SINGLE_WORLD_HOST;OUT_OF_BAND_RPC additionalCompilerArguments: Standalone: - -warnaserror @@ -747,6 +749,7 @@ PlayerSettings: scriptingBackend: {} il2cppCompilerConfiguration: {} il2cppCodeGeneration: {} + il2cppLTOMode: {} il2cppStacktraceInformation: {} managedStrippingLevel: EmbeddedLinux: 1 @@ -794,8 +797,7 @@ PlayerSettings: metroDefaultTileSize: 1 metroTileForegroundText: 2 metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} - metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, - a: 1} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} metroSplashScreenUseBackgroundColor: 0 syncCapabilities: 0 platformCapabilities: {} @@ -831,7 +833,6 @@ PlayerSettings: XboxOneXTitleMemory: 8 XboxOneOverrideIdentityName: XboxOneOverrideIdentityPublisher: - vrEditorSettings: {} cloudServicesEnabled: Analytics: 0 Build: 0 @@ -862,6 +863,7 @@ PlayerSettings: captureStartupLogs: {} activeInputHandler: 0 windowsGamepadBackendHint: 0 + enableDirectStorage: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 qualitySettingsNames: [] @@ -877,3 +879,4 @@ PlayerSettings: androidVulkanAllowFilterList: [] androidVulkanDeviceFilterListAsset: {fileID: 0} d3d12DeviceFilterListAsset: {fileID: 0} + allowedHttpConnections: 3 diff --git a/testproject/ProjectSettings/ProjectVersion.txt b/testproject/ProjectSettings/ProjectVersion.txt index c31f18a127..33390a1c17 100644 --- a/testproject/ProjectSettings/ProjectVersion.txt +++ b/testproject/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 6000.2.12f1 -m_EditorVersionWithRevision: 6000.2.12f1 (e89d5df0e333) +m_EditorVersion: 6000.3.17f1 +m_EditorVersionWithRevision: 6000.3.17f1 (cf0352b38e81)