public void HandleSpawnMessage(ulong clientID, Stream stream, float receiveTime) { using (PooledBitReader reader = PooledBitReader.Get(stream)) { ulong networkID = reader.ReadUInt64Packed(); //Network ID ulong ownerID = reader.ReadUInt64Packed(); //Owner Type behaviourType = RPCTypeDefinition.GetTypeFromHash(reader.ReadUInt64Packed()); bool hasUniqueHash = reader.ReadBool(); ulong uniqueHash = 0; if (hasUniqueHash) { uniqueHash = reader.ReadUInt64Packed(); } bool ownerCanUnspawn = reader.ReadBool(); bool destroyOnUnspawn = reader.ReadBool(); //Read spawn payload PooledBitStream payloadStream = null; if (reader.ReadBool()) { payloadStream = PooledBitStream.Get(); int payloadLength = reader.ReadInt32Packed(); payloadStream.CopyUnreadFrom(stream, payloadLength); stream.Position += payloadLength; payloadStream.Position = 0; } if (networkManager.enableLogging) { string s = "Received add object event from server. Object: " + behaviourType.ToString() + " | Network ID: " + networkID + " | Owner: " + ownerID + " | Has Unique Hash: " + hasUniqueHash + " | "; if (hasUniqueHash) { s += uniqueHash + " | "; } s += "Owner Can Unspawn: " + ownerCanUnspawn + " | Destroy On Unspawn: " + destroyOnUnspawn; Debug.Log(s); } if (hasUniqueHash) { if (m_LocalPendingBehaviours.TryGetValue(uniqueHash, out PendingNetworkBehaviour pendingBehaviour)) { if (pendingBehaviour.reference.networkBehaviour.GetType() != behaviourType) { Debug.LogError("Received add object message where the remote network behaviour type(" + behaviourType.ToString() + ") does not match up with local network behaviour type (" + pendingBehaviour.reference.networkBehaviour.GetType() + ") with same unique ID(" + pendingBehaviour.reference.networkBehaviour.uniqueID + ").", pendingBehaviour.reference.networkBehaviour); return; } //Clean up pending m_LocalPendingBehaviours.Remove(uniqueHash); m_LocalPendingBehavioursList.Remove(pendingBehaviour.reference.networkBehaviour); OnObjectConnectSuccess(pendingBehaviour.reference, networkID, ownerID, ownerCanUnspawn, destroyOnUnspawn, payloadStream); if (payloadStream != null) { payloadStream.Dispose(); } } else if (m_RemotePendingBehavioursHashes.ContainsKey(uniqueHash)) { Debug.LogError("Received duplicate 'add object' message for hash '" + uniqueHash + "'."); return; } else if (m_RemotePendingBehaviours.ContainsKey(networkID)) { Debug.LogError("Recevied duplicate 'add object' message for network ID '" + networkID + "'."); return; } else { PendingNetworkBehaviour pendingBehaviourReference = new PendingNetworkBehaviour() { isRemoteBehaviour = true, uniqueHash = uniqueHash, ownerID = ownerID, networkID = networkID, ownerCanUnspawn = ownerCanUnspawn, destroyOnUnspawn = destroyOnUnspawn, spawnPayload = payloadStream }; m_RemotePendingBehavioursHashes.Add(uniqueHash, pendingBehaviourReference); m_RemotePendingBehaviours.Add(networkID, pendingBehaviourReference); } } else //No unique hash { //Build network behaviour GameObject behaviourObject = new GameObject("Server Network Object"); //All this stuff just in case the instantiate behaviour also instantiates other network behaviours in its awake function m_TrackAwakeSpawns = true; NetworkBehaviour serverBehaviour = (NetworkBehaviour)behaviourObject.AddComponent(behaviourType); m_TrackAwakeSpawns = false; if (m_BehavioursAwaitingSpawn.Count > 0) { while (m_BehavioursAwaitingSpawn.Count > 0) { NetworkBehaviourReference reference = m_BehavioursAwaitingSpawn.Dequeue(); if (reference.networkBehaviour == serverBehaviour) { OnObjectConnectSuccess(reference, networkID, ownerID, ownerCanUnspawn, destroyOnUnspawn, payloadStream); if (payloadStream != null) { payloadStream.Dispose(); } } else { SpawnOnNetworkClient(reference.networkBehaviour, reference.connectedClientCallback, reference.disconnectedDelegate, reference.localRPCDelegate, reference.ownerChangeDelegate); } } } if (!serverBehaviour.isNetworkSpawned) { serverBehaviour.uniqueID = "NETWORK_SERVER_BEHAVIOUR_" + networkID.ToString(); serverBehaviour.SpawnOnNetwork(); ulong hash = serverBehaviour.uniqueID.GetStableHash(networkManager.config.rpcHashSize); PendingNetworkBehaviour pendingBehaviour = m_LocalPendingBehaviours[hash]; //Clean up pending m_LocalPendingBehaviours.Remove(uniqueHash); m_LocalPendingBehavioursList.Remove(serverBehaviour); OnObjectConnectSuccess(pendingBehaviour.reference, networkID, ownerID, ownerCanUnspawn, destroyOnUnspawn, payloadStream); if (payloadStream != null) { payloadStream.Dispose(); } } } } }
// Ran on both server and client internal static void SpawnNetworkedObjectLocally(NetworkedObject netObject, ulong networkId, bool sceneObject, bool playerObject, ulong?ownerClientId, Stream dataStream, bool readPayload, int payloadLength, bool readNetworkedVar, bool destroyWithScene) { if (netObject == null) { throw new ArgumentNullException(nameof(netObject), "Cannot spawn null object"); } if (netObject.IsSpawned) { throw new SpawnStateException("Object is already spawned"); } if (readNetworkedVar && NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar) { netObject.SetNetworkedVarData(dataStream); } netObject.IsSpawned = true; netObject.IsSceneObject = sceneObject; netObject.NetworkId = networkId; netObject.DestroyWithScene = sceneObject || destroyWithScene; netObject._ownerClientId = ownerClientId; netObject.IsPlayerObject = playerObject; SpawnedObjects.Add(netObject.NetworkId, netObject); SpawnedObjectsList.Add(netObject); if (ownerClientId != null) { if (NetworkingManager.Singleton.IsServer) { if (playerObject) { NetworkingManager.Singleton.ConnectedClients[ownerClientId.Value].PlayerObject = netObject; } else { NetworkingManager.Singleton.ConnectedClients[ownerClientId.Value].OwnedObjects.Add(netObject); } } else if (playerObject && ownerClientId.Value == NetworkingManager.Singleton.LocalClientId) { NetworkingManager.Singleton.ConnectedClients[ownerClientId.Value].PlayerObject = netObject; } } if (NetworkingManager.Singleton.IsServer) { for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++) { if (netObject.CheckObjectVisibility == null || netObject.CheckObjectVisibility(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId)) { netObject.observers.Add(NetworkingManager.Singleton.ConnectedClientsList[i].ClientId); } } } netObject.ResetNetworkedStartInvoked(); if (readPayload) { using (PooledBitStream payloadStream = PooledBitStream.Get()) { payloadStream.CopyUnreadFrom(dataStream, payloadLength); dataStream.Position += payloadLength; payloadStream.Position = 0; netObject.InvokeBehaviourNetworkSpawn(payloadStream); } } else { netObject.InvokeBehaviourNetworkSpawn(null); } }
internal static NetworkedObject CreateSpawnedObject(int networkedPrefabId, uint networkId, uint owner, bool playerObject, uint sceneSpawnedInIndex, bool sceneDelayedSpawn, bool destroyWithScene, Vector3?position, Quaternion?rotation, bool isActive, Stream stream, bool readPayload, int payloadLength, bool readNetworkedVar) { if (networkedPrefabId >= netManager.NetworkConfig.NetworkedPrefabs.Count || networkedPrefabId < 0) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot spawn the object, invalid prefabIndex: " + networkedPrefabId); } return(null); } //Delayed spawning if (sceneDelayedSpawn && sceneSpawnedInIndex != NetworkSceneManager.CurrentActiveSceneIndex) { GameObject prefab = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab; bool prefabActive = prefab.activeSelf; prefab.SetActive(false); GameObject go = (position == null && rotation == null) ? MonoBehaviour.Instantiate(prefab) : MonoBehaviour.Instantiate(prefab, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity)); prefab.SetActive(prefabActive); //Appearantly some wierd behavior when switching scenes can occur that destroys this object even though the scene is //not destroyed, therefor we set it to DontDestroyOnLoad here, to prevent that problem. MonoBehaviour.DontDestroyOnLoad(go); NetworkedObject netObject = go.GetComponent <NetworkedObject>(); if (netObject == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Please add a NetworkedObject component to the root of all spawnable objects"); } netObject = go.AddComponent <NetworkedObject>(); } netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].name; netObject.IsSpawned = false; netObject.IsPooledObject = false; if (netManager.IsServer) { netObject.NetworkId = GetNetworkObjectId(); } else { netObject.NetworkId = networkId; } netObject.destroyWithScene = destroyWithScene; netObject.OwnerClientId = owner; netObject.IsPlayerObject = playerObject; netObject.SceneDelayedSpawn = sceneDelayedSpawn; netObject.sceneSpawnedInIndex = sceneSpawnedInIndex; Dictionary <ushort, List <INetworkedVar> > dummyNetworkedVars = new Dictionary <ushort, List <INetworkedVar> >(); List <NetworkedBehaviour> networkedBehaviours = new List <NetworkedBehaviour>(netObject.GetComponentsInChildren <NetworkedBehaviour>()); for (ushort i = 0; i < networkedBehaviours.Count; i++) { dummyNetworkedVars.Add(i, networkedBehaviours[i].GetDummyNetworkedVars()); } PendingSpawnObject pso = new PendingSpawnObject() { netObject = netObject, dummyNetworkedVars = dummyNetworkedVars, sceneSpawnedInIndex = sceneSpawnedInIndex, playerObject = playerObject, owner = owner, isActive = isActive, payload = null }; PendingSpawnObjects.Add(netObject.NetworkId, pso); pso.SetNetworkedVarData(stream); if (readPayload) { MLAPI.Serialization.BitStream payloadStream = new MLAPI.Serialization.BitStream(); payloadStream.CopyUnreadFrom(stream, payloadLength); stream.Position += payloadLength; pso.payload = payloadStream; } return(netObject); } //Normal spawning { GameObject prefab = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab; GameObject go = (position == null && rotation == null) ? MonoBehaviour.Instantiate(prefab) : MonoBehaviour.Instantiate(prefab, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity)); NetworkedObject netObject = go.GetComponent <NetworkedObject>(); if (netObject == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Please add a NetworkedObject component to the root of all spawnable objects"); } netObject = go.AddComponent <NetworkedObject>(); } if (readNetworkedVar) { netObject.SetNetworkedVarData(stream); } netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].name; netObject.IsSpawned = true; netObject.IsPooledObject = false; if (netManager.IsServer) { netObject.NetworkId = GetNetworkObjectId(); } else { netObject.NetworkId = networkId; } netObject.destroyWithScene = destroyWithScene; netObject.OwnerClientId = owner; netObject.IsPlayerObject = playerObject; netObject.SceneDelayedSpawn = sceneDelayedSpawn; netObject.sceneSpawnedInIndex = sceneSpawnedInIndex; SpawnedObjects.Add(netObject.NetworkId, netObject); SpawnedObjectsList.Add(netObject); if (playerObject) { NetworkingManager.Singleton.ConnectedClients[owner].PlayerObject = netObject; } if (readPayload) { using (PooledBitStream payloadStream = PooledBitStream.Get()) { payloadStream.CopyUnreadFrom(stream, payloadLength); stream.Position += payloadLength; netObject.InvokeBehaviourNetworkSpawn(payloadStream); } } else { netObject.InvokeBehaviourNetworkSpawn(null); } netObject.gameObject.SetActive(isActive); return(netObject); } }