diff --git a/Assets/Mirage/Runtime/ServerObjectManager.cs b/Assets/Mirage/Runtime/ServerObjectManager.cs index 2e42b46279..7eb156cb43 100644 --- a/Assets/Mirage/Runtime/ServerObjectManager.cs +++ b/Assets/Mirage/Runtime/ServerObjectManager.cs @@ -23,10 +23,10 @@ namespace Mirage public class ServerObjectManager : MonoBehaviour { private static readonly ILogger logger = LogFactory.GetLogger(typeof(ServerObjectManager)); - /// - /// HashSet for NetworkIdentity that can be re-used without allocation - /// - private static HashSet _setCache = new HashSet(); + /// HashSet for NetworkIdentity that can be re-used without allocation + private static HashSet _skipCache = new HashSet(); + /// HashSet for NetworkIdentity that can be re-used without allocation + private static List _spawnCache = new List(); internal RpcHandler _rpcHandler; @@ -136,7 +136,7 @@ public void ReplaceCharacter(INetworkPlayer player, NetworkIdentity identity, bo } if (!player.HasCharacter) { - throw new InvalidOperationException($"ReplaceCharacter can only be called if Player already has a charater"); + throw new InvalidOperationException($"ReplaceCharacter can only be called if Player already has a character"); } //NOTE: there can be an existing player @@ -247,8 +247,8 @@ private void Respawn(NetworkIdentity identity) /// internal void ShowToPlayer(NetworkIdentity identity, INetworkPlayer player) { - var visiblity = identity.Visibility; - if (visiblity is NetworkVisibility networkVisibility) + var visibility = identity.Visibility; + if (visibility is NetworkVisibility networkVisibility) networkVisibility.InvokeVisibilityChanged(player, true); // dont send if loading scene @@ -627,16 +627,16 @@ public void SpawnVisibleObjects(INetworkPlayer player, NetworkIdentity skip) /// NetworkIdentity to skip when spawning. Can be null public void SpawnVisibleObjects(INetworkPlayer player, bool ignoreHasCharacter, NetworkIdentity skip) { - _setCache.Clear(); - _setCache.Add(skip); - SpawnVisibleObjects(player, ignoreHasCharacter, _setCache); + _skipCache.Clear(); + _skipCache.Add(skip); + SpawnVisibleObjects(player, ignoreHasCharacter, _skipCache); } /// /// Sends spawn message for scene objects and other visible objects to the given player if it has a character /// /// The player to spawn objects for - /// If true will spawn visibile objects even if player does not have a spawned character yet + /// If true will spawn visible objects even if player does not have a spawned character yet /// NetworkIdentity to skip when spawning. Can be null public void SpawnVisibleObjects(INetworkPlayer player, bool ignoreHasCharacter, HashSet skip) { @@ -658,11 +658,14 @@ public void SpawnVisibleObjects(INetworkPlayer player, bool ignoreHasCharacter, if (logger.LogEnabled()) logger.Log($"SpawnVisibleObjects: Checking Observers on {_server.World.SpawnedIdentities.Count} objects for player: {player}"); + // add to cache first, so SpawnedIdentities can be modified inside loop without throwing + _spawnCache.Clear(); + _spawnCache.AddRange(_server.World.SpawnedIdentities); // add connection to each nearby NetworkIdentity's observers, which // internally sends a spawn message for each one to the connection. - foreach (var identity in _server.World.SpawnedIdentities) + foreach (var identity in _spawnCache) { - // allow for skips so that addChatacter doesn't send 2 spawn message for existing object + // allow for skips so that addCharacter doesn't send 2 spawn message for existing object if (skip != null && skip.Contains(identity)) continue; @@ -678,6 +681,8 @@ public void SpawnVisibleObjects(INetworkPlayer player, bool ignoreHasCharacter, } } } + + _spawnCache.Clear(); } private sealed class NetworkIdentityComparer : IComparer