//Client only public void SpawnOnNetworkClient(NetworkBehaviour behaviour, ClientBehaviourConnectedDelegate connectedCallback, BehaviourDisconnectedDelegate disconnectedCallback, NetworkBehaviourRPCDelegate localRPCCallback, OwnerChangeDelegate ownerChangeCallback) { if (behaviour == null || !behaviour.isNetworkSpawned || behaviour.isNetworkReady || m_LocalPendingBehavioursList.Contains(behaviour) || string.IsNullOrWhiteSpace(behaviour.uniqueID)) { throw new InvalidOperationException("NetworkBehaviourManager.SpawnNetworkClient is only allowed to be called internally by a Network Behaviour."); } //Check if this is the Unique Behaviour being spawned in HandleAddObjectMessage where the Unique ID is blank and SpawnOnNetwork is called in Awake. if (m_TrackAwakeSpawns) { m_BehavioursAwaitingSpawn.Enqueue(new NetworkBehaviourReference() { networkBehaviour = behaviour, connectedClientCallback = connectedCallback, disconnectedDelegate = disconnectedCallback, localRPCDelegate = localRPCCallback, ownerChangeDelegate = ownerChangeCallback }); return; } ulong uniqueHash = behaviour.uniqueID.GetStableHash(networkManager.config.rpcHashSize); if (m_RemotePendingBehavioursHashes.TryGetValue(uniqueHash, out PendingNetworkBehaviour pendingBehaviour)) { m_RemotePendingBehavioursHashes.Remove(uniqueHash); m_RemotePendingBehaviours.Remove(pendingBehaviour.networkID); OnObjectConnectSuccess(new NetworkBehaviourReference() { networkBehaviour = behaviour, connectedClientCallback = connectedCallback, disconnectedDelegate = disconnectedCallback, localRPCDelegate = localRPCCallback, ownerChangeDelegate = ownerChangeCallback }, pendingBehaviour.networkID, pendingBehaviour.ownerID, pendingBehaviour.ownerCanUnspawn, pendingBehaviour.destroyOnUnspawn, pendingBehaviour.spawnPayload); pendingBehaviour.spawnPayload?.Dispose(); } else if (m_LocalPendingBehaviours.TryGetValue(uniqueHash, out pendingBehaviour)) { //Check if the unique hash has already been added by this client if (m_BehaviourByHashedID.TryGetValue(uniqueHash, out NetworkBehaviour otherBehaviour)) { if (!BehaviourWasDestroyed(otherBehaviour)) { throw new NetworkException("A Network Behaviour already has the unique ID '" + behaviour.uniqueID + "'."); } } if (m_HashedStrings.TryGetValue(uniqueHash, out string otherUniqueID)) { if (otherUniqueID == behaviour.uniqueID) { throw new NetworkException("A Network Behaviour already has the unique ID '" + behaviour.uniqueID + "'."); } else { //This occurs when 2 different strings hash to the same value from MLAPI.Hashing.GetStableHash. throw new NetworkException("A hash collision occurred. Either change the unique ID or increase the hash size in the config. '" + behaviour.uniqueID + "' and '" + otherUniqueID + "' both hashed to '" + uniqueHash + "'."); } } } else { if (m_BehaviourByHashedID.TryGetValue(uniqueHash, out NetworkBehaviour otherBehaviour)) { if (!BehaviourWasDestroyed(otherBehaviour)) { throw new NetworkException("A Network Behaviour already has the unique ID '" + behaviour.uniqueID + "'."); } } if (m_HashedStrings.TryGetValue(uniqueHash, out string otherUniqueID)) { if (otherUniqueID == behaviour.uniqueID) { throw new NetworkException("A Network Behaviour already has the unique ID '" + behaviour.uniqueID + "'."); } else { //This occurs when 2 different strings hash to the same value from MLAPI.Hashing.GetStableHash. throw new NetworkException("A hash collision occurred. Either change the unique ID or increase the hash size in the config. '" + behaviour.uniqueID + "' and '" + otherUniqueID + "' both hashed to '" + uniqueHash + "'."); } } //Add to pending pendingBehaviour = new PendingNetworkBehaviour() { isRemoteBehaviour = false, uniqueHash = uniqueHash, ownerID = networkManager.serverID, networkID = 0, reference = new NetworkBehaviourReference { networkBehaviour = behaviour, connectedClientCallback = connectedCallback, disconnectedDelegate = disconnectedCallback, localRPCDelegate = localRPCCallback, ownerChangeDelegate = ownerChangeCallback } }; m_LocalPendingBehavioursList.Add(pendingBehaviour.reference.networkBehaviour); m_LocalPendingBehaviours.Add(uniqueHash, pendingBehaviour); m_HashedStrings.Add(uniqueHash, behaviour.uniqueID); m_BehaviourByHashedID.Add(uniqueHash, behaviour); } }
//Server only public void SpawnOnNetworkServer(NetworkBehaviour behaviour, ServerBehaviourConnectedDelegate connectedCallback, BehaviourDisconnectedDelegate disconnectCallback, NetworkBehaviourRPCDelegate localRPCCallback, OwnerChangeDelegate ownerChangeCallback, ulong owner, List <ulong> observers, Stream spawnPayload) { if (behaviour == null || !behaviour.isNetworkSpawned || behaviour.isNetworkReady) { throw new InvalidOperationException("NetworkBehaviourManager.SpawnOnNetworkServer is only allowed to be called internally by a Network Behaviour."); } ulong newNetworkID = GetNewNetworkID(); if (!string.IsNullOrWhiteSpace(behaviour.uniqueID)) { ulong uniqueHash = behaviour.uniqueID.GetStableHash(networkManager.config.rpcHashSize); if (m_BehaviourByHashedID.TryGetValue(uniqueHash, out NetworkBehaviour otherBehaviour)) { if (!BehaviourWasDestroyed(otherBehaviour)) { throw new NetworkException("A Network Behaviour already has the unique ID '" + behaviour.uniqueID + "'."); } } if (m_HashedStrings.TryGetValue(uniqueHash, out string otherUniqueID)) { if (otherUniqueID == behaviour.uniqueID) { throw new NetworkException("A Network Behaviour already has the unique ID '" + behaviour.uniqueID + "'."); } else { //This occurs when 2 different strings hash to the same value from MLAPI.Hashing.GetStableHash. throw new NetworkException("A hash collision occurred. Either change the unique ID or increase the hash size in the config. '" + behaviour.uniqueID + "' and '" + otherUniqueID + "' both hashed to '" + uniqueHash + "'."); } } m_HashedStrings.Add(uniqueHash, behaviour.uniqueID); m_BehaviourByHashedID.Add(uniqueHash, behaviour); } m_NetworkBehaviours.Add(new NetworkBehaviourReference() { networkBehaviour = behaviour, connectedServerCallback = connectedCallback, disconnectedDelegate = disconnectCallback, localRPCDelegate = localRPCCallback, ownerChangeDelegate = ownerChangeCallback }); m_NetworkBehaviourDictionary.Add(newNetworkID, m_NetworkBehaviours[m_NetworkBehaviours.Count - 1]); //Spawn payload if (spawnPayload == null) { connectedCallback.Invoke(newNetworkID, owner, networkManager.serverID, observers, null); } else { using (PooledBitStream payloadStream = PooledBitStream.Get()) { payloadStream.CopyFrom(spawnPayload); payloadStream.Position = 0; connectedCallback.Invoke(newNetworkID, owner, networkManager.serverID, observers, payloadStream); } } }