Skip to content
Closed
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
27 changes: 0 additions & 27 deletions com.unity.netcode.gameobjects/Editor/NetworkObjectEditor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

Expand Down Expand Up @@ -62,32 +61,6 @@ public override void OnInspectorGUI()
EditorGUILayout.Toggle(nameof(NetworkObject.DestroyWithScene), m_NetworkObject.DestroyWithScene);
EditorGUILayout.TextField(nameof(NetworkObject.NetworkManager), m_NetworkObject.NetworkManager == null ? "null" : m_NetworkObject.NetworkManager.gameObject.name);
GUI.enabled = guiEnabled;

if (m_NetworkObject.NetworkManager != null && m_NetworkObject.NetworkManager.IsServer)
{
m_ShowObservers = EditorGUILayout.Foldout(m_ShowObservers, "Observers");

if (m_ShowObservers)
{
HashSet<ulong>.Enumerator observerClientIds = m_NetworkObject.GetObservers();

EditorGUI.indentLevel += 1;

while (observerClientIds.MoveNext())
{
if (m_NetworkObject.NetworkManager.ConnectedClients[observerClientIds.Current].PlayerObject != null)
{
EditorGUILayout.ObjectField($"ClientId: {observerClientIds.Current}", m_NetworkObject.NetworkManager.ConnectedClients[observerClientIds.Current].PlayerObject, typeof(GameObject), false);
}
else
{
EditorGUILayout.TextField($"ClientId: {observerClientIds.Current}", EditorStyles.label);
}
}

EditorGUI.indentLevel -= 1;
}
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,10 @@ internal void NetworkBehaviourUpdate(NetworkManager networkManager)
m_Touched.UnionWith(spawnedObjs);
foreach (var sobj in spawnedObjs)
{
if (sobj.IsNetworkVisibleTo(client.ClientId))
// Sync just the variables for just the objects this client sees
for (int k = 0; k < sobj.ChildNetworkBehaviours.Count; k++)
{
// Sync just the variables for just the objects this client sees
for (int k = 0; k < sobj.ChildNetworkBehaviours.Count; k++)
{
sobj.ChildNetworkBehaviours[k].VariableUpdate(client.ClientId);
}
sobj.ChildNetworkBehaviours[k].VariableUpdate(client.ClientId);
}
}
}
Expand Down
11 changes: 1 addition & 10 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1366,13 +1366,6 @@ internal void OnClientDisconnectFromServer(ulong clientId)
}
}
}

// TODO: Could(should?) be replaced with more memory per client, by storing the visibility

foreach (var sobj in SpawnManager.SpawnedObjectsList)
{
sobj.Observers.Remove(clientId);
}
}

for (int i = 0; i < ConnectedClientsList.Count; i++)
Expand Down Expand Up @@ -1471,7 +1464,6 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint?
}
else // Server just adds itself as an observer to all spawned NetworkObjects
{
SpawnManager.UpdateObservedNetworkObjects(ownerClientId);
InvokeOnClientConnectedCallback(ownerClientId);
}

Expand Down Expand Up @@ -1501,8 +1493,7 @@ internal void ApprovedPlayerSpawn(ulong clientId, uint playerPrefabHash)
{
if (clientPair.Key == clientId ||
clientPair.Key == ServerClientId || // Server already spawned it
ConnectedClients[clientId].PlayerObject == null ||
!ConnectedClients[clientId].PlayerObject.Observers.Contains(clientPair.Key))
ConnectedClients[clientId].PlayerObject == null)
{
continue; //The new client.
}
Expand Down
216 changes: 2 additions & 214 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEngine;

Expand Down Expand Up @@ -165,218 +163,11 @@ internal set
/// </summary>
public bool AutoObjectParentSync = true;

internal readonly HashSet<ulong> Observers = new HashSet<ulong>();

/// <summary>
/// Returns Observers enumerator
/// </summary>
/// <returns>Observers enumerator</returns>
public HashSet<ulong>.Enumerator GetObservers()
{
if (!IsSpawned)
{
throw new SpawnStateException("Object is not spawned");
}

return Observers.GetEnumerator();
}

/// <summary>
/// Whether or not this object is visible to a specific client
/// </summary>
/// <param name="clientId">The clientId of the client</param>
/// <returns>True if the client knows about the object</returns>
public bool IsNetworkVisibleTo(ulong clientId)
{
if (!IsSpawned)
{
throw new SpawnStateException("Object is not spawned");
}

return Observers.Contains(clientId);
}

private void Awake()
{
SetCachedParent(transform.parent);
}

/// <summary>
/// Shows a previously hidden <see cref="NetworkObject"/> to a client
/// </summary>
/// <param name="clientId">The client to show the <see cref="NetworkObject"/> to</param>
public void NetworkShow(ulong clientId)
{
if (!IsSpawned)
{
throw new SpawnStateException("Object is not spawned");
}

if (!NetworkManager.IsServer)
{
throw new NotServerException("Only server can change visibility");
}

if (Observers.Contains(clientId))
{
throw new VisibilityChangeException("The object is already visible");
}

if (NetworkManager.NetworkConfig.UseSnapshotSpawn)
{
SnapshotSpawn(clientId);
}

Observers.Add(clientId);

NetworkManager.SpawnManager.SendSpawnCallForObject(clientId, this);
}

/// <summary>
/// Shows a list of previously hidden <see cref="NetworkObject"/>s to a client
/// </summary>
/// <param name="networkObjects">The <see cref="NetworkObject"/>s to show</param>
/// <param name="clientId">The client to show the objects to</param>
public static void NetworkShow(List<NetworkObject> networkObjects, ulong clientId)
{
if (networkObjects == null || networkObjects.Count == 0)
{
throw new ArgumentNullException("At least one " + nameof(NetworkObject) + " has to be provided");
}

NetworkManager networkManager = networkObjects[0].NetworkManager;

if (!networkManager.IsServer)
{
throw new NotServerException("Only server can change visibility");
}

// Do the safety loop first to prevent putting the netcode in an invalid state.
for (int i = 0; i < networkObjects.Count; i++)
{
if (!networkObjects[i].IsSpawned)
{
throw new SpawnStateException("Object is not spawned");
}

if (networkObjects[i].Observers.Contains(clientId))
{
throw new VisibilityChangeException($"{nameof(NetworkObject)} with NetworkId: {networkObjects[i].NetworkObjectId} is already visible");
}

if (networkObjects[i].NetworkManager != networkManager)
{
throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManager));
}
}

foreach (var networkObject in networkObjects)
{
networkObject.NetworkShow(clientId);
}
}

/// <summary>
/// Hides a object from a specific client
/// </summary>
/// <param name="clientId">The client to hide the object for</param>
public void NetworkHide(ulong clientId)
{
if (!IsSpawned)
{
throw new SpawnStateException("Object is not spawned");
}

if (!NetworkManager.IsServer)
{
throw new NotServerException("Only server can change visibility");
}

if (!Observers.Contains(clientId))
{
throw new VisibilityChangeException("The object is already hidden");
}

if (clientId == NetworkManager.ServerClientId)
{
throw new VisibilityChangeException("Cannot hide an object from the server");
}


Observers.Remove(clientId);

if (NetworkManager.NetworkConfig.UseSnapshotSpawn)
{
SnapshotDespawn(clientId);
}
else
{
// Send destroy call
var context = NetworkManager.MessageQueueContainer.EnterInternalCommandContext(
MessageQueueContainer.MessageType.DestroyObject, NetworkChannel.Internal,
new[] { clientId }, NetworkUpdateStage.PostLateUpdate);
if (context != null)
{
using var nonNullContext = (InternalCommandContext)context;
var bufferSizeCapture = new CommandContextSizeCapture(nonNullContext);
bufferSizeCapture.StartMeasureSegment();

nonNullContext.NetworkWriter.WriteUInt64Packed(NetworkObjectId);

var size = bufferSizeCapture.StopMeasureSegment();
NetworkManager.NetworkMetrics.TrackObjectDestroySent(clientId, NetworkObjectId, name, size);
}
}
}

/// <summary>
/// Hides a list of objects from a client
/// </summary>
/// <param name="networkObjects">The objects to hide</param>
/// <param name="clientId">The client to hide the objects from</param>
public static void NetworkHide(List<NetworkObject> networkObjects, ulong clientId)
{
if (networkObjects == null || networkObjects.Count == 0)
{
throw new ArgumentNullException("At least one " + nameof(NetworkObject) + " has to be provided");
}

NetworkManager networkManager = networkObjects[0].NetworkManager;

if (!networkManager.IsServer)
{
throw new NotServerException("Only server can change visibility");
}

if (clientId == networkManager.ServerClientId)
{
throw new VisibilityChangeException("Cannot hide an object from the server");
}

// Do the safety loop first to prevent putting the netcode in an invalid state.
for (int i = 0; i < networkObjects.Count; i++)
{
if (!networkObjects[i].IsSpawned)
{
throw new SpawnStateException("Object is not spawned");
}

if (!networkObjects[i].Observers.Contains(clientId))
{
throw new VisibilityChangeException($"{nameof(NetworkObject)} with {nameof(NetworkObjectId)}: {networkObjects[i].NetworkObjectId} is already hidden");
}

if (networkObjects[i].NetworkManager != networkManager)
{
throw new ArgumentNullException("All " + nameof(NetworkObject) + "s must belong to the same " + nameof(NetworkManager));
}
}

foreach (var networkObject in networkObjects)
{
networkObject.NetworkHide(clientId);
}
}

private void OnDestroy()
{
Expand Down Expand Up @@ -479,10 +270,7 @@ private void SpawnInternal(bool destroyWithScene, ulong? ownerClientId, bool pla
ulong ownerId = ownerClientId != null ? ownerClientId.Value : NetworkManager.ServerClientId;
for (int i = 0; i < NetworkManager.ConnectedClientsList.Count; i++)
{
if (Observers.Contains(NetworkManager.ConnectedClientsList[i].ClientId))
{
NetworkManager.SpawnManager.SendSpawnCallForObject(NetworkManager.ConnectedClientsList[i].ClientId, this);
}
NetworkManager.SpawnManager.SendSpawnCallForObject(NetworkManager.ConnectedClientsList[i].ClientId, this);
}
}

Expand Down Expand Up @@ -721,7 +509,7 @@ private void OnTransformParentChanged()

var context = NetworkManager.MessageQueueContainer.EnterInternalCommandContext(
MessageQueueContainer.MessageType.ParentSync, NetworkChannel.Internal,
NetworkManager.ConnectedClientsIds.Where((id) => Observers.Contains(id)).ToArray(),
NetworkManager.ConnectedClientsIds,
NetworkUpdateLoop.UpdateStage);

if (context != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1128,9 +1128,6 @@ private void OnClientLoadedScene(Scene scene)
/// <param name="clientId">newly joined client identifier</param>
internal void SynchronizeNetworkObjects(ulong clientId)
{
// Update the clients
m_NetworkManager.SpawnManager.UpdateObservedNetworkObjects(clientId);

ClientSynchEventData.InitializeForSynch();
ClientSynchEventData.TargetClientId = clientId;
ClientSynchEventData.LoadSceneMode = LoadSceneMode.Single;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,14 +414,11 @@ internal void SerializeScenePlacedObjects(NetworkWriter writer)
{
foreach (var keyValuePairBySceneHandle in keyValuePairByGlobalObjectIdHash.Value)
{
if (keyValuePairBySceneHandle.Value.Observers.Contains(TargetClientId))
{
// Write our server relative scene handle for the NetworkObject being serialized
writer.WriteInt32Packed(keyValuePairBySceneHandle.Key);
// Serialize the NetworkObject
keyValuePairBySceneHandle.Value.SerializeSceneObject(writer, TargetClientId);
numberOfObjects++;
}
// Write our server relative scene handle for the NetworkObject being serialized
writer.WriteInt32Packed(keyValuePairBySceneHandle.Key);
// Serialize the NetworkObject
keyValuePairBySceneHandle.Value.SerializeSceneObject(writer, TargetClientId);
numberOfObjects++;
}
}

Expand Down
Loading