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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Unity.Netcode.Logging;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
Expand All @@ -19,8 +20,22 @@
public int callbackOrder => 0;
public void OnProcessScene(Scene scene, BuildReport report)
{
var log = new ContextualLogger();
log.AddInfo(scene.name, scene.handle);
foreach (var networkObject in FindObjects.FromSceneByType<NetworkObject>(scene, true))
{
if (networkObject.SceneOrigin.IsValid() && networkObject.SceneOrigin.handle != scene.handle)
{
log.Warning(new Context(LogLevel.Developer, $"{nameof(NetworkObject)}'s SceneOrigin doesn't match current scene being processed! Skipping processing.").AddInfo("SceneOrigin", networkObject.SceneOriginHandle).AddNetworkObject(networkObject));
continue;

Check warning on line 30 in com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs#L27-L30

Added lines #L27 - L30 were not covered by tests
}

if (networkObject.HasBeenSpawned)
{
log.Error(new Context(LogLevel.Normal, $"Processing {nameof(NetworkObject)} that has already been spawned! This should not be possible. Skipping processing.").AddNetworkObject(networkObject));
continue;

Check warning on line 36 in com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Editor/InScenePlacedProcessor.cs#L33-L36

Added lines #L33 - L36 were not covered by tests
}

networkObject.InScenePlaced = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,22 @@
return false;
}

if (networkObject.InScenePlaced)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
{
NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} InScenePlaced {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!");
}
}

Check warning on line 175 in com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs#L170-L175

Added lines #L170 - L175 were not covered by tests

if (networkObject.IsSpawned)
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer)
{
NetworkLog.LogWarning($"{NetworkPrefabHandler.PrefabDebugHelper(this)} Currently spawned {nameof(NetworkObject)} is being registered as a Prefab. This can cause issues!");
}
}

Check warning on line 183 in com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefab.cs#L178-L183

Added lines #L178 - L183 were not covered by tests

return true;
}

Expand Down
77 changes: 57 additions & 20 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Runtime.CompilerServices;
using System.Text;
using Unity.Netcode.Components;
using Unity.Netcode.Logging;
using Unity.Netcode.Runtime;
#if UNITY_EDITOR
using UnityEditor;
Expand Down Expand Up @@ -106,6 +107,9 @@
/// </summary>
public NetworkObject CurrentParent { get; private set; }

private int m_SpawnCount;
internal bool HasBeenSpawned => m_SpawnCount > 0;

#if UNITY_EDITOR
private const string k_GlobalIdTemplate = "GlobalObjectId_V1-{0}-{1}-{2}-{3}";

Expand Down Expand Up @@ -1448,12 +1452,16 @@

set
{
if (SceneOriginHandle.IsEmpty() && value.IsValid() && value.isLoaded)
{
SceneOriginHandle = value.handle;
}

// The scene origin should only be set once.
// Once set, it should never change.
if (SceneOriginHandle.IsEmpty() && value.IsValid() && value.isLoaded)
if (!m_SceneOrigin.IsValid())
{
m_SceneOrigin = value;
SceneOriginHandle = value.handle;
}
}
}
Expand Down Expand Up @@ -1782,7 +1790,7 @@
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject)
private void SpawnInternal(bool destroyWithScene, ulong ownerClientId, bool playerObject)
{
if (NetworkManagerOwner == null)
{
Expand Down Expand Up @@ -1853,7 +1861,28 @@
}
}

if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), InScenePlaced, playerObject, ownerClientId, destroyWithScene))

// Calculate the legacy IsSceneObject value as the public field is obsolete with warning
// We can't break the public behavior of the field.
#pragma warning disable CS0618 // Type or member is obsolete
var legacyIsSceneObject = IsSceneObject.HasValue && IsSceneObject.Value;
#pragma warning restore CS0618 // Type or member is obsolete

// If SpawnInternal is being called on an object that is marked as InScenePlaced,
// The scene object was never automatically spawned when the scene was loaded.
// Count this object as a dynamically spawned object.
// TODO-[MTT-15388]: Actually support disabled/not spawned InScenePlaced NetworkObjects
if (InScenePlaced && !HasBeenSpawned)
{
if (NetworkManagerOwner.NetworkConfig.EnableSceneManagement && NetworkManagerOwner.LogLevel <= LogLevel.Developer)
{
Debug.LogWarning($"[{name}][SceneOrigin={SceneOriginHandle}] Dynamically spawning InScenePlaced network object. This can cause issues!", this);
}

Check warning on line 1880 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L1876-L1880

Added lines #L1876 - L1880 were not covered by tests

InScenePlaced = false;
}

Check warning on line 1883 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L1882-L1883

Added lines #L1882 - L1883 were not covered by tests

if (!NetworkManagerOwner.SpawnManager.AuthorityLocalSpawn(this, NetworkManagerOwner.SpawnManager.GetNetworkObjectId(), legacyIsSceneObject, playerObject, ownerClientId, destroyWithScene))
{
if (NetworkManagerOwner.LogLevel <= LogLevel.Normal)
{
Expand Down Expand Up @@ -2053,6 +2082,7 @@
// When spawned, previous owner is always the first assigned owner
PreviousOwnerId = ownerClientId;
m_HasAuthority = NetworkManagerOwner.DistributedAuthorityMode ? OwnerClientId == NetworkManagerOwner.LocalClientId : NetworkManagerOwner.IsServer;
m_SpawnCount++;
IsSpawned = true;

// If this is the player, and the client is the owner, then lock ownership by default
Expand Down Expand Up @@ -2094,6 +2124,17 @@
}
}

/// <summary>
/// Resets this NetworkObject at the end of a session.
/// Ensures scene objects are ready to be reused
/// </summary>
internal void ResetOnShutdown()
{

Check warning on line 2132 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L2132

Added line #L2132 was not covered by tests
NetworkLog.InternalAssert(NetworkManager.ShutdownInProgress, "This method should only be called while the NetworkManager is shutting down");
m_SpawnCount = 0;
ResetOnDespawn();
}

Check warning on line 2136 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L2134-L2136

Added lines #L2134 - L2136 were not covered by tests

internal void ResetOnDespawn()
{
// Always clear out the observers list when despawned
Expand Down Expand Up @@ -3466,11 +3507,7 @@

if (serializedObject.NetworkObjectId == default)
{
if (networkManager.LogLevel <= LogLevel.Error)
{
NetworkLog.LogErrorServer($"[{nameof(GlobalObjectIdHash)}={serializedObject.Hash}] Received spawn request with invalid {nameof(NetworkObjectId)} {serializedObject.NetworkObjectId}. This should not happen!");
}

NetworkLog.LogErrorServer(new Context(LogLevel.Error, $"Received spawn request with invalid {nameof(NetworkObjectId)}. This should not happen!").AddInfo(nameof(NetworkObjectId), serializedObject.NetworkObjectId).AddInfo(nameof(GlobalObjectIdHash), serializedObject.Hash));

Check warning on line 3510 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L3510

Added line #L3510 was not covered by tests
reader.Seek(endOfSynchronizationData);
return null;
}
Expand Down Expand Up @@ -3627,17 +3664,17 @@
NetworkSceneHandle = SceneOriginHandle;
}
}
else // Otherwise, the client did not find the client to server scene handle
if (NetworkManagerOwner.LogLevel <= LogLevel.Developer)
{
// There could be a scenario where a user has some client-local scene loaded that they migrate the NetworkObject
// into, but that scenario seemed very edge case and under most instances a user should be notified that this
// server - client scene handle mismatch has occurred. It also seemed pertinent to make the message replicate to
// the server-side too.
NetworkLog.LogWarningServer($"[Client-{NetworkManagerOwner.LocalClientId}][{name}] Server - " +
$"client scene mismatch detected! Client-side scene handle ({SceneOriginHandle}) for scene ({gameObject.scene.name})" +
$"has no associated server side (network) scene handle!");
}
// Otherwise, the client did not find the client to server scene handle
else if (NetworkManagerOwner.LogLevel <= LogLevel.Developer)
{

Check warning on line 3669 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L3668-L3669

Added lines #L3668 - L3669 were not covered by tests
// There could be a scenario where a user has some client-local scene loaded that they migrate the NetworkObject
// into, but that scenario seemed very edge case and under most instances a user should be notified that this
// server - client scene handle mismatch has occurred. It also seemed pertinent to make the message replicate to
// the server-side too.
NetworkLog.LogWarningServer($"[Client-{NetworkManagerOwner.LocalClientId}][{name}] Server - " +

Check warning on line 3674 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L3674

Added line #L3674 was not covered by tests
$"client scene mismatch detected! Client-side scene handle ({SceneOriginHandle}) for scene ({gameObject.scene.name})" +
$"has no associated server side (network) scene handle!");
}

Check warning on line 3677 in com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs#L3677

Added line #L3677 was not covered by tests
OnMigratedToNewScene?.Invoke();

// Only the authority side will notify clients of non-parented NetworkObject scene changes
Expand Down
40 changes: 27 additions & 13 deletions com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
/// <param name="message">The message to log</param>
[HideInCallstack]
public static void LogErrorServer(string message) => s_Log.ErrorServer(new Context(LogLevel.Error, message, true));
[HideInCallstack]
internal static void LogErrorServer(Context context) => s_Log.ErrorServer(context);

Check warning on line 107 in com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs#L107

Added line #L107 was not covered by tests

internal static LogType GetMessageLogType(UnityEngine.LogType engineLogType)
{
Expand All @@ -115,14 +117,14 @@
};
}


private const string k_SenderId = "SenderId";
internal static Context BuildContextForServerMessage([NotNull] NetworkManager networkManager, LogLevel level, ulong senderId, string message)
{
var ctx = new Context(level, message, true).AddInfo(k_SenderId, senderId);
if (TryGetNetworkObjectName(networkManager, message, out var name))
var ctx = new Context(level, message, true).AddTag("Received log from client").AddInfo(k_SenderId, senderId);
var networkObject = TryGetNetworkObject(networkManager, message);
if (networkObject != null)
{
ctx.AddTag(name);
ctx.AddNetworkObject(networkObject);
}
return ctx;
}
Expand All @@ -135,29 +137,41 @@
None
}

private static readonly Regex k_GlobalObjectIdHash = new($@"\[{nameof(NetworkObject.GlobalObjectIdHash)}=(\d+)\]", RegexOptions.Compiled);
private static readonly Regex k_NetworkObjectId = new($@"\[{nameof(NetworkObject.NetworkObjectId)}:(\d+)\]", RegexOptions.Compiled);
private static readonly Regex k_GlobalObjectIdHash = new($@"\[{nameof(NetworkObject.GlobalObjectIdHash)}:(\d+)\]", RegexOptions.Compiled);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryGetNetworkObjectName([NotNull] NetworkManager networkManager, string message, out string name)
private static NetworkObject TryGetNetworkObject([NotNull] NetworkManager networkManager, string message)
{
name = null;
if (k_NetworkObjectId.IsMatch(message))
{
var stringId = k_NetworkObjectId.Match(message).Groups[1].Value;
if (ulong.TryParse(stringId, out var networkObjectId) && networkObjectId > 0 && networkManager.SpawnManager.SpawnedObjects.TryGetValue(networkObjectId, out var networkObject))
{
return networkObject;
}
}

Check warning on line 152 in com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs#L152

Added line #L152 was not covered by tests

if (!k_GlobalObjectIdHash.IsMatch(message))
{
return false;
return null;

Check warning on line 156 in com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs#L156

Added line #L156 was not covered by tests
}

var stringHash = k_GlobalObjectIdHash.Match(message).Groups[1].Value;
if (!ulong.TryParse(stringHash, out var globalObjectIdHash))
{
return false;
return null;

Check warning on line 162 in com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

com.unity.netcode.gameobjects/Runtime/Logging/NetworkLog.cs#L162

Added line #L162 was not covered by tests
}

if (!networkManager.SpawnManager.SpawnedObjects.TryGetValue(globalObjectIdHash, out var networkObject))
NetworkObject matchingObject = null;
foreach (var networkObject in networkManager.SpawnManager.SpawnedObjectsList)
{
return false;
if (networkObject.GlobalObjectIdHash == globalObjectIdHash)
{
matchingObject = networkObject;
}
}

name = networkObject.name;
return true;
return matchingObject;
}

[HideInCallstack]
Expand Down
Loading
Loading