diff --git a/.yamato/wrench/validation-jobs.yml b/.yamato/wrench/validation-jobs.yml index ef89d9c058..772cfd9b3e 100644 --- a/.yamato/wrench/validation-jobs.yml +++ b/.yamato/wrench/validation-jobs.yml @@ -27,7 +27,7 @@ validate_-_netcode_gameobjects_-_6000_7_-_macos13arm: retries: 1 - command: echo No internal packages to add. - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp - timeout: 40 + timeout: 90 retries: 0 - command: python PythonScripts/ignore_clean_console_failures.py timeout: 5 @@ -39,10 +39,10 @@ validate_-_netcode_gameobjects_-_6000_7_-_macos13arm: timeout: 10 retries: 0 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 after: - command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh @@ -104,7 +104,7 @@ validate_-_netcode_gameobjects_-_6000_7_-_ubuntu2204: retries: 1 - command: echo No internal packages to add. - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp - timeout: 40 + timeout: 90 retries: 0 - command: python PythonScripts/ignore_clean_console_failures.py timeout: 5 @@ -116,10 +116,10 @@ validate_-_netcode_gameobjects_-_6000_7_-_ubuntu2204: timeout: 10 retries: 0 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 after: - command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh @@ -181,7 +181,7 @@ validate_-_netcode_gameobjects_-_6000_7_-_win10: retries: 1 - command: echo No internal packages to add. - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp - timeout: 40 + timeout: 90 retries: 0 - command: python PythonScripts/ignore_clean_console_failures.py timeout: 5 @@ -193,10 +193,10 @@ validate_-_netcode_gameobjects_-_6000_7_-_win10: timeout: 10 retries: 0 - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 after: - command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd @@ -259,7 +259,7 @@ validate_-_netcode_gameobjects_-_7000_0_-_macos13arm: retries: 1 - command: echo No internal packages to add. - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp - timeout: 40 + timeout: 90 retries: 0 - command: python PythonScripts/ignore_clean_console_failures.py timeout: 5 @@ -271,10 +271,10 @@ validate_-_netcode_gameobjects_-_7000_0_-_macos13arm: timeout: 10 retries: 0 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 after: - command: bash .yamato/generated-scripts/infrastructure-instability-detection-mac.sh @@ -336,7 +336,7 @@ validate_-_netcode_gameobjects_-_7000_0_-_ubuntu2204: retries: 1 - command: echo No internal packages to add. - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp - timeout: 40 + timeout: 90 retries: 0 - command: python PythonScripts/ignore_clean_console_failures.py timeout: 5 @@ -348,10 +348,10 @@ validate_-_netcode_gameobjects_-_7000_0_-_ubuntu2204: timeout: 10 retries: 0 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 - command: 'UnifiedTestRunner --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 after: - command: bash .yamato/generated-scripts/infrastructure-instability-detection-linux.sh @@ -413,7 +413,7 @@ validate_-_netcode_gameobjects_-_7000_0_-_win10: retries: 1 - command: echo No internal packages to add. - command: upm-pvp test --unity .Editor --packages "upm-ci~/packages/*.tgz" --results upm-ci~/pvp - timeout: 40 + timeout: 90 retries: 0 - command: python PythonScripts/ignore_clean_console_failures.py timeout: 5 @@ -425,10 +425,10 @@ validate_-_netcode_gameobjects_-_7000_0_-_win10: timeout: 10 retries: 0 - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/editor --suite=editor "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 - command: 'UnifiedTestRunner.exe --testproject=testproject --editor-location=.Editor --clean-library --reruncount=1 --clean-library-on-rerun --artifacts-path=artifacts/playmode --suite=playmode "--ff={ops.upmpvpevidence.enable=true}" ' - timeout: 40 + timeout: 90 retries: 1 after: - command: .yamato\generated-scripts\infrastructure-instability-detection-win.cmd diff --git a/.yamato/wrench/wrench_config.json b/.yamato/wrench/wrench_config.json index 7d7426cb16..93be7a3da4 100644 --- a/.yamato/wrench/wrench_config.json +++ b/.yamato/wrench/wrench_config.json @@ -23,7 +23,14 @@ "coverageCommands": [ "generateAdditionalMetrics;generateHtmlReport;assemblyFilters:ASSEMBLY_NAME;" ], - "dependantsToIgnoreInPreviewApv": {}, + "dependantsToIgnoreInPreviewApv": { + "6000.7": [ + "com.unity.services.multiplayer" + ], + "7000.0": [ + "com.unity.services.multiplayer" + ] + }, "postPackCommands": [] } }, diff --git a/Tools/CI/Settings/NgoWrenchSettings.cs b/Tools/CI/Settings/NgoWrenchSettings.cs index 28751e115c..b003579bad 100644 --- a/Tools/CI/Settings/NgoWrenchSettings.cs +++ b/Tools/CI/Settings/NgoWrenchSettings.cs @@ -1,7 +1,9 @@ using RecipeEngine.Api.Settings; +using RecipeEngine.Modules.Wrench.Helpers; using RecipeEngine.Modules.Wrench.Models; using RecipeEngine.Modules.Wrench.Platforms; using RecipeEngine.Modules.Wrench.Settings; +using RecipeEngine.Unity.Abstractions.Editors; namespace NGO.Cookbook.Settings; @@ -13,7 +15,7 @@ public class NgoWrenchSettings : AnnotatedSettingsBase static ValidationOptions validationOptions = new ValidationOptions() { ProjectPath = "testproject", - UtrTestingYamatoTimeout = 40 + UtrTestingYamatoTimeout = 90 }; // update this to list all packages in this repo that you want to release. @@ -34,6 +36,14 @@ public NgoWrenchSettings() Wrench = new WrenchSettings(packagesRootPaths, PackageOptions); Wrench.PvpProfilesToCheck = new HashSet() { "supported" }; Wrench.Packages["com.unity.netcode.gameobjects"].PackAndPromotePlatformType = EditorPlatformType.Ubuntu2204; + + // com.unity.services.multiplayer tests reference NGO test helpers that aren't exposed in the APV project, so they fail to compile there. + var apvDependantsToIgnore = new HashSet { "com.unity.services.multiplayer" }; + Wrench.Packages["com.unity.netcode.gameobjects"].DependantsToIgnoreInPreviewApv = new Dictionary> + { + [new EditorVersion("6000.7")] = apvDependantsToIgnore, + [new EditorVersion("7000.0")] = apvDependantsToIgnore + }; } public WrenchSettings Wrench { get; private set; } diff --git a/com.unity.netcode.gameobjects/CHANGELOG.md b/com.unity.netcode.gameobjects/CHANGELOG.md index 15f400f9db..e20d9c1b5a 100644 --- a/com.unity.netcode.gameobjects/CHANGELOG.md +++ b/com.unity.netcode.gameobjects/CHANGELOG.md @@ -6,24 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) Additional documentation and release notes are available at [Multiplayer Documentation](https://docs-multiplayer.unity3d.com). -## [Unreleased] - -### Added +## [3.1.0] - 2026-10-04 ### Changed - Updated Netcode for Entities dependency to 7.1.0 -### Deprecated - -### Removed - -### Fixed - -### Security - -### Obsolete - ## [3.0.0] - 2026-09-14 ### Added diff --git a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs index 4314aa243d..8c326e5107 100644 --- a/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs +++ b/com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs @@ -5,20 +5,47 @@ using UnityEngine; using UnityEngine.SceneManagement; +#if UNITY_7000_0_OR_NEWER +using UnityEditor.Build.Content; +#endif + namespace Unity.Netcode.GameObjects.Editor { /// - /// A that sets the property to true for all s in the scene. /// Ensures that InScenePlaced is always true for all objects in the scene. /// /// - /// This will always run as the game enters the scene, + /// This will always run as a scene is loaded in playmode or while processed for a player build. /// +#if UNITY_7000_0_OR_NEWER + internal class SetInScenePlaced : AssetPostprocessor + { + public override uint GetVersion() => 1; + + public override int GetPostprocessOrder() => 0; + + void OnProcessScene(Scene scene, SceneImportContext sceneImportContext) + { + InScenePlaceChecks.ReportSceneIssues(scene, sceneImportContext.awakeDidRun); + } + } +#else internal class SetInScenePlaced : IProcessSceneWithReport { public int callbackOrder => 0; + public void OnProcessScene(Scene scene, BuildReport report) + { + InScenePlaceChecks.ReportSceneIssues(scene, Application.isPlaying); + } + } +#endif + + internal static class InScenePlaceChecks + { + public static void ReportSceneIssues(Scene scene, bool hasAwakeRun) { var log = new ContextualLogger(); log.AddInfo(scene.name, scene.handle); @@ -42,15 +69,15 @@ public void OnProcessScene(Scene scene, BuildReport report) continue; } - // If already marked, the do nothing. + // If already marked, do nothing. if (networkObject.InScenePlaced) { continue; } networkObject.InScenePlaced = true; - // Will not be true when making a build and the values are serialized. - networkObject.InScenePlacedPostProcessorMarkedDuringRuntime = Application.isPlaying; + // Mark that awake has run so this could have been a dynamically instantiated object. + networkObject.InScenePlacedPostProcessorMarkedDuringRuntime = hasAwakeRun; } } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs index 28ab33223e..8d11a73c16 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/NamedMessageTests.cs @@ -243,6 +243,9 @@ public void WhenSendingNamedMessageToNullClientList_ArgumentNullExceptionIsThrow [Test] public unsafe void ErrorMessageIsPrintedWhenAttemptingToSendNamedMessageWithTooBigBuffer() { +#if !DEBUG + Assert.Ignore("The message size check only exists in builds that define DEBUG."); +#endif // First try a valid send with the maximum allowed size (this is atm 1264) var msgSize = m_ServerNetworkManager.MessageManager.NonFragmentedMessageMaxSize - FastBufferWriter.GetWriteSize() - sizeof(ulong)/*MessageName hash*/ - sizeof(NetworkBatchHeader); var bufferSize = m_ServerNetworkManager.MessageManager.NonFragmentedMessageMaxSize; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/UnnamedMessageTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/UnnamedMessageTests.cs index 8b0c854b59..1c8c8263db 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/UnnamedMessageTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Messaging/UnnamedMessageTests.cs @@ -198,6 +198,9 @@ public void WhenSendingNamedMessageToNullClientList_ArgumentNullExceptionIsThrow [Test] public unsafe void ErrorMessageIsPrintedWhenAttemptingToSendUnnamedMessageWithTooBigBuffer() { +#if !DEBUG + Assert.Ignore("The message size check only exists in builds that define DEBUG."); +#endif // First try a valid send with the maximum allowed size (this is atm 1272) var msgSize = m_ServerNetworkManager.MessageManager.NonFragmentedMessageMaxSize - FastBufferWriter.GetWriteSize() - sizeof(NetworkBatchHeader); var bufferSize = m_ServerNetworkManager.MessageManager.NonFragmentedMessageMaxSize; diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/ObjectNameIdentifierTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/ObjectNameIdentifierTests.cs new file mode 100644 index 0000000000..778cee7fca --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/ObjectNameIdentifierTests.cs @@ -0,0 +1,58 @@ +using System.Collections; +using System.Text; +using NUnit.Framework; +using Unity.Netcode.TestHelpers.Runtime; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Unity.Netcode.RuntimeTests +{ + internal class ObjectNameIdentifierTests : NetcodeIntegrationTest + { + protected override int NumberOfClients => 1; + + private GameObject m_Prefab; + + protected override void OnServerAndClientsCreated() + { + m_Prefab = CreateNetworkObjectPrefab("TrackedObject"); + base.OnServerAndClientsCreated(); + } + + private bool AllInstancesAreRegistered(StringBuilder errorLog, ulong networkObjectId) + { + foreach (var networkManager in m_NetworkManagers) + { + if (!s_GlobalNetworkObjects.TryGetValue(networkManager.LocalClientId, out var networkObjects) || !networkObjects.ContainsKey(networkObjectId)) + { + errorLog.Append($"[Client-{networkManager.LocalClientId}] Object-{networkObjectId} is not registered."); + return false; + } + } + return true; + } + + [UnityTest] + public IEnumerator OwnershipChangesKeepAllInstancesRegistered() + { + var authority = GetAuthorityNetworkManager(); + var client = m_ClientNetworkManagers[0]; + var authorityInstance = SpawnObject(m_Prefab, authority).GetComponent(); + var networkObjectId = authorityInstance.NetworkObjectId; + yield return WaitForSpawnedOnAllOrTimeOut(authorityInstance); + AssertOnTimeout($"Timed out waiting for Object-{networkObjectId} to spawn on all instances!"); + + authorityInstance.ChangeOwnership(client.LocalClientId); + yield return WaitForConditionOrTimeOut(() => client.SpawnManager.SpawnedObjects[networkObjectId].OwnerClientId == client.LocalClientId); + AssertOnTimeout($"Timed out waiting for Client-{client.LocalClientId} to gain ownership of Object-{networkObjectId}!"); + var errorLog = new StringBuilder(); + Assert.IsTrue(AllInstancesAreRegistered(errorLog, networkObjectId), $"After gaining ownership: {errorLog}"); + + authorityInstance.RemoveOwnership(); + yield return WaitForConditionOrTimeOut(() => client.SpawnManager.SpawnedObjects[networkObjectId].OwnerClientId == authority.LocalClientId); + AssertOnTimeout($"Timed out waiting for the authority to regain ownership of Object-{networkObjectId}!"); + errorLog.Clear(); + Assert.IsTrue(AllInstancesAreRegistered(errorLog, networkObjectId), $"After removing ownership: {errorLog}"); + } + } +} diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/ObjectNameIdentifierTests.cs.meta b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/ObjectNameIdentifierTests.cs.meta new file mode 100644 index 0000000000..bde5e655da --- /dev/null +++ b/com.unity.netcode.gameobjects/Tests/Runtime/NetworkObject/ObjectNameIdentifierTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17d56b26ccea49e09cc90aa82c506f61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs index e33b6ea313..f43bbc4c88 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/TestHelpers/Components/ObjectNameIdentifier.cs @@ -9,7 +9,7 @@ namespace Unity.Netcode.TestHelpers.Runtime /// public class ObjectNameIdentifier : NetworkBehaviour { - private ulong m_CurrentOwner; + private ulong m_RegisteredClientId; private ulong m_CurrentNetworkObjectId; private bool m_IsRegistered; @@ -45,7 +45,7 @@ protected void RegisterAndLabelNetworkObject() // This is required otherwise it will try to continue to update the NetworkBehaviour even if // it has been destroyed. m_NetworkObject = NetworkObject; - m_CurrentOwner = OwnerClientId; + m_RegisteredClientId = NetworkManager.LocalClientId; m_CurrentNetworkObjectId = NetworkObjectId; var serverOrClient = IsServer ? "Server" : "Client"; @@ -75,7 +75,7 @@ protected void DeRegisterNetworkObject() { if (m_IsRegistered) { - NetcodeIntegrationTest.DeregisterNetworkObject(m_CurrentOwner, m_CurrentNetworkObjectId); + NetcodeIntegrationTest.DeregisterNetworkObject(m_RegisteredClientId, m_CurrentNetworkObjectId); m_IsRegistered = false; } } diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs index 9b224d6bfe..c4212cb729 100644 --- a/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs +++ b/com.unity.netcode.gameobjects/Tests/Runtime/Transports/UnityTransportTests.cs @@ -569,7 +569,9 @@ public IEnumerator DoesNotActAfterShutdown([Values] AfterShutdownAction afterShu { m_Server.DisconnectRemoteClient(m_Client1.ServerClientId); +#if DEBUG LogAssert.Expect(LogType.Warning, $"{nameof(UnityTransport.DisconnectRemoteClient)} should only be called on a listening server!"); +#endif } else if (afterShutdownAction == AfterShutdownAction.DisconnectLocalClient) {