internal static void OnFirstSceneSwitchSync(uint sceneIndex, Guid switchSceneGuid) { if (!sceneIndexToString.ContainsKey(sceneIndex) || !registeredSceneNames.Contains(sceneIndexToString[sceneIndex])) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Server requested a scene switch to a non registered scene"); } return; } else if (SceneManager.GetActiveScene().name == sceneIndexToString[sceneIndex]) { return; //This scene is already loaded. This usually happends at first load } lastScene = SceneManager.GetActiveScene(); string sceneName = sceneIndexToString[sceneIndex]; nextScene = SceneManager.GetSceneByName(sceneName); CurrentActiveSceneIndex = sceneNameToIndex[sceneName]; SceneManager.LoadScene(sceneName); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteByteArray(switchSceneGuid.ToByteArray()); InternalMessageHandler.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CLIENT_SWITCH_SCENE_COMPLETED, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null); } } isSwitching = false; }
internal static void ChangeOwnership(uint netId, uint clientId) { if (!netManager.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("You can only change ownership from Server"); } return; } NetworkedObject netObject = SpawnManager.SpawnedObjects[netId]; for (int i = NetworkingManager.singleton.ConnectedClients[netObject.OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.singleton.ConnectedClients[netObject.OwnerClientId].OwnedObjects[i].NetworkId == netId) { NetworkingManager.singleton.ConnectedClients[netObject.OwnerClientId].OwnedObjects.RemoveAt(i); } } NetworkingManager.singleton.ConnectedClients[clientId].OwnedObjects.Add(netObject); netObject.OwnerClientId = clientId; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(netId); writer.WriteUInt32Packed(clientId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_CHANGE_OWNER, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } }
internal void SendClientRPCPerformance(ulong hash, uint clientId, Stream messageStream, string channel, SecuritySendFlags security) { if (!IsServer && IsRunning) { //We are NOT a server. if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Only clients and host can invoke ClientRPC"); } return; } using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(NetworkId); writer.WriteUInt16Packed(NetworkedObject.GetOrderIndex(this)); writer.WriteUInt64Packed(hash); stream.CopyFrom(messageStream); if (IsHost && clientId == NetworkingManager.Singleton.LocalClientId) { messageStream.Position = 0; InvokeClientRPCLocal(hash, NetworkingManager.Singleton.LocalClientId, messageStream); } else { InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_CLIENT_RPC, string.IsNullOrEmpty(channel) ? "MLAPI_DEFAULT_MESSAGE" : channel, stream, security); } } } }
/// <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 (!NetworkingManager.Singleton.IsServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Error) { LogHelper.LogError("Can only call NetworkHide on the server"); } return; } if (observers.Contains(clientId) && clientId != NetworkingManager.Singleton.ServerClientId) { // Send destroy call observers.Remove(clientId); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt64Packed(NetworkId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null); } } } }
/// <summary> /// Spawns a object from the pool at a given position and rotation. Can only be called from server. /// </summary> /// <param name="poolName">The name of the pool</param> /// <param name="position">The position to spawn the object at</param> /// <param name="rotation">The rotation to spawn the object at</param> /// <returns></returns> public static NetworkedObject SpawnPoolObject(string poolName, Vector3 position, Quaternion rotation) { if (!NetworkingManager.singleton.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Object spawning can only occur on server"); } return(null); } NetworkedObject netObject = Pools[PoolNamesToIndexes[poolName]].SpawnObject(position, rotation); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(netObject.NetworkId); writer.WriteSinglePacked(position.x); writer.WriteSinglePacked(position.y); writer.WriteSinglePacked(position.z); writer.WriteSinglePacked(rotation.eulerAngles.x); writer.WriteSinglePacked(rotation.eulerAngles.y); writer.WriteSinglePacked(rotation.eulerAngles.z); InternalMessageHandler.Send(MLAPIConstants.MLAPI_SPAWN_POOL_OBJECT, "MLAPI_INTERNAL", stream); } } return(netObject); }
internal static void SendSpawnCallForObject(ulong clientId, NetworkedObject netObject, Stream payload) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteBool(netObject.IsPlayerObject); writer.WriteUInt64Packed(netObject.NetworkId); writer.WriteUInt64Packed(netObject.OwnerClientId); if (NetworkingManager.Singleton.NetworkConfig.UsePrefabSync) { writer.WriteUInt64Packed(netObject.PrefabHash); } else { writer.WriteBool(netObject.IsSceneObject == null ? true : netObject.IsSceneObject.Value); if (netObject.IsSceneObject == null || netObject.IsSceneObject.Value) { writer.WriteUInt64Packed(netObject.NetworkedInstanceId); } else { writer.WriteUInt64Packed(netObject.PrefabHash); } } writer.WriteBool(netObject.DestroyWithScene); writer.WriteSinglePacked(netObject.transform.position.x); writer.WriteSinglePacked(netObject.transform.position.y); writer.WriteSinglePacked(netObject.transform.position.z); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); if (payload != null) { writer.WriteInt32Packed((int)payload.Length); } if (NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar) { netObject.WriteNetworkedVarData(stream, clientId); } if (payload != null) { stream.CopyFrom(payload); } } InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null); } }
/// <summary> /// Switches to a scene with a given name. Can only be called from Server /// </summary> /// <param name="sceneName">The name of the scene to switch to</param> public static SceneSwitchProgress SwitchScene(string sceneName) { if (!NetworkingManager.singleton.NetworkConfig.EnableSceneSwitching) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Scene switching is not enabled"); } return(null); } else if (isSwitching) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Scene switch already in progress"); } return(null); } else if (!registeredSceneNames.Contains(sceneName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The scene " + sceneName + " is not registered as a switchable scene."); } return(null); } SpawnManager.DestroySceneObjects(); //Destroy current scene objects before switching. currentSceneIndex = sceneNameToIndex[sceneName]; isSwitching = true; lastScene = SceneManager.GetActiveScene(); SceneSwitchProgress switchSceneProgress = new SceneSwitchProgress(); sceneSwitchProgresses.Add(switchSceneProgress.guid, switchSceneProgress); currentSceneSwitchProgressGuid = switchSceneProgress.guid; AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); nextScene = SceneManager.GetSceneByName(sceneName); sceneLoad.completed += (AsyncOperation AsyncOp) => { OnSceneLoaded(AsyncOp, switchSceneProgress.guid); }; switchSceneProgress.SetSceneLoadOperation(sceneLoad); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(sceneNameToIndex[sceneName]); writer.WriteByteArray(switchSceneProgress.guid.ToByteArray()); InternalMessageHandler.Send(MLAPIConstants.MLAPI_SWITCH_SCENE, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } return(switchSceneProgress); }
internal static void OnDestroyObject(uint networkId, bool destroyGameObject) { if (!SpawnedObjects.ContainsKey(networkId) || (netManager != null && !netManager.NetworkConfig.HandleObjectSpawning)) { return; } if (!SpawnedObjects[networkId].isOwnedByServer && !SpawnedObjects[networkId].isPlayerObject && netManager.ConnectedClients.ContainsKey(SpawnedObjects[networkId].OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAt(i); } } } SpawnedObjects[networkId].isSpawned = false; if (netManager != null && netManager.isServer) { releasedNetworkObjectIds.Push(networkId); if (SpawnedObjects[networkId] != null) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(networkId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream); } } } } GameObject go = SpawnedObjects[networkId].gameObject; if (destroyGameObject && go != null) { MonoBehaviour.Destroy(go); } SpawnedObjects.Remove(networkId); for (int i = SpawnedObjectsList.Count - 1; i > -1; i--) { if (SpawnedObjectsList[i].NetworkId == networkId) { SpawnedObjectsList.RemoveAt(i); } } }
private static void OnSceneUnload(AsyncOperation operation, Guid switchSceneGuid) { if (NetworkingManager.singleton.isServer) { SpawnManager.MarkSceneObjects(); NetworkedObject[] networkedObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); for (int i = 0; i < networkedObjects.Length; i++) { if (!networkedObjects[i].isSpawned && networkedObjects[i].destroyWithScene == true) { networkedObjects[i].Spawn(null, true); } } } else { SpawnManager.SpawnPendingObjectsForScene(CurrentActiveSceneIndex); NetworkedObject[] netObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); for (int i = 0; i < netObjects.Length; i++) { if (netObjects[i].destroyWithScene == null) { MonoBehaviour.Destroy(netObjects[i].gameObject); } } } //Tell server that scene load is completed if (NetworkingManager.singleton.isHost) { OnClientSwitchSceneCompleted(NetworkingManager.singleton.LocalClientId, switchSceneGuid); } else if (NetworkingManager.singleton.isClient) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteByteArray(switchSceneGuid.ToByteArray()); InternalMessageHandler.Send(NetworkingManager.singleton.ServerClientId, MLAPIConstants.MLAPI_CLIENT_SWITCH_SCENE_COMPLETED, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } } isSwitching = false; }
/// <summary> /// Switches to a scene with a given name. Can only be called from Server /// </summary> /// <param name="sceneName">The name of the scene to switch to</param> public static void SwitchScene(string sceneName) { if (!NetworkingManager.singleton.NetworkConfig.EnableSceneSwitching) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Scene switching is not enabled"); } return; } else if (isSwitching) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Scene switch already in progress"); } return; } else if (!registeredSceneNames.Contains(sceneName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The scene " + sceneName + " is not registered as a switchable scene."); } return; } SpawnManager.DestroySceneObjects(); //Destroy current scene objects before switching. CurrentSceneIndex = sceneNameToIndex[sceneName]; isSwitching = true; lastScene = SceneManager.GetActiveScene(); AsyncOperation sceneLoad = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); nextScene = SceneManager.GetSceneByName(sceneName); sceneLoad.completed += OnSceneLoaded; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(sceneNameToIndex[sceneName]); InternalMessageHandler.Send(MLAPIConstants.MLAPI_SWITCH_SCENE, "MLAPI_INTERNAL", stream); } } }
/// <summary> /// Destroys a NetworkedObject if it's part of a pool. Use this instead of the MonoBehaviour Destroy method. Can only be called from Server. /// </summary> /// <param name="netObject">The NetworkedObject instance to destroy</param> public static void DestroyPoolObject(NetworkedObject netObject) { if (!NetworkingManager.singleton.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Objects can only be destroyed on the server"); } return; } netObject.gameObject.SetActive(false); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(netObject.NetworkId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_DESTROY_POOL_OBJECT, "MLAPI_INTERNAL", stream); } } }
internal void RebuildObservers(uint?clientId = null) { bool initial = clientId != null; if (initial) { bool shouldBeAdded = true; for (int i = 0; i < childNetworkedBehaviours.Count; i++) { bool state = childNetworkedBehaviours[i].OnCheckObserver(clientId.Value); if (state == false) { shouldBeAdded = false; break; } } if (shouldBeAdded) { observers.Add(clientId.Value); } } else { previousObservers.Clear(); foreach (var item in observers) { previousObservers.Add(item); } bool update = false; for (int i = 0; i < childNetworkedBehaviours.Count; i++) { bool changed = childNetworkedBehaviours[i].OnRebuildObservers(observers); if (changed) { update = true; break; } } if (update) { foreach (KeyValuePair <uint, NetworkedClient> pair in NetworkingManager.singleton.connectedClients) { if (pair.Key == NetworkingManager.singleton.NetworkConfig.NetworkTransport.HostDummyId) { continue; } if ((previousObservers.Contains(pair.Key) && !observers.Contains(pair.Key)) || (!previousObservers.Contains(pair.Key) && observers.Contains(pair.Key))) { //Something changed for this client. using (BitWriter writer = BitWriter.Get()) { writer.WriteUInt(networkId); writer.WriteBool(observers.Contains(pair.Key)); if (observers.Contains(pair.Key)) { WriteFormattedSyncedVarData(writer); } InternalMessageHandler.Send(pair.Key, "MLAPI_SET_VISIBILITY", "MLAPI_INTERNAL", writer, null); } } } } else { foreach (var item in previousObservers) { observers.Add(item); } } previousObservers.Clear(); } }
internal void NetworkedVarUpdate() { if (!networkedVarInit) { NetworkedVarInit(); } //TODO: Do this efficiently. if (!CouldHaveDirtyVars()) { return; } networkedVarIndexesToReset.Clear(); networkedVarIndexesToResetSet.Clear(); for (int i = 0; i < NetworkingManager.Singleton.ConnectedClientsList.Count; i++) { //This iterates over every "channel group". for (int j = 0; j < channelMappedVarIndexes.Count; j++) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(NetworkId); writer.WriteUInt16Packed(NetworkedObject.GetOrderIndex(this)); uint clientId = NetworkingManager.Singleton.ConnectedClientsList[i].ClientId; bool writtenAny = false; for (int k = 0; k < networkedVarFields.Count; k++) { if (!channelMappedVarIndexes[j].Contains(k)) { //This var does not belong to the currently iterating channel group. writer.WriteBool(false); continue; } bool isDirty = networkedVarFields[k].IsDirty(); //cache this here. You never know what operations users will do in the dirty methods writer.WriteBool(isDirty); if (isDirty && (!IsServer || networkedVarFields[k].CanClientRead(clientId))) { writtenAny = true; networkedVarFields[k].WriteDelta(stream); if (!networkedVarIndexesToResetSet.Contains(k)) { networkedVarIndexesToResetSet.Add(k); networkedVarIndexesToReset.Add(k); } } } if (writtenAny) { if (IsServer) { InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream, SecuritySendFlags.None); } else { InternalMessageHandler.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream, SecuritySendFlags.None); } } } } } } for (int i = 0; i < networkedVarIndexesToReset.Count; i++) { networkedVarFields[networkedVarIndexesToReset[i]].ResetDirty(); } }
private static void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) { if (NetworkingManager.Singleton.NetworkConfig.UsePrefabSync) { SpawnManager.DestroySceneObjects(); using (PooledBitReader reader = PooledBitReader.Get(objectStream)) { uint newObjectsCount = reader.ReadUInt32Packed(); for (int i = 0; i < newObjectsCount; i++) { bool isPlayerObject = reader.ReadBool(); ulong networkId = reader.ReadUInt64Packed(); ulong owner = reader.ReadUInt64Packed(); ulong prefabHash = reader.ReadUInt64Packed(); bool destroyWithScene = reader.ReadBool(); Vector3 position = new Vector3(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); Quaternion rotation = Quaternion.Euler(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); NetworkedObject networkedObject = SpawnManager.CreateLocalNetworkedObject(false, 0, prefabHash, position, rotation); SpawnManager.SpawnNetworkedObjectLocally(networkedObject, networkId, true, isPlayerObject, owner, objectStream, false, 0, true, destroyWithScene); } } } else { NetworkedObject[] networkedObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); SpawnManager.ClientCollectSoftSyncSceneObjectSweep(networkedObjects); using (PooledBitReader reader = PooledBitReader.Get(objectStream)) { uint newObjectsCount = reader.ReadUInt32Packed(); for (int i = 0; i < newObjectsCount; i++) { bool isPlayerObject = reader.ReadBool(); ulong networkId = reader.ReadUInt64Packed(); ulong owner = reader.ReadUInt64Packed(); ulong instanceId = reader.ReadUInt64Packed(); bool destroyWithScene = reader.ReadBool(); NetworkedObject networkedObject = SpawnManager.CreateLocalNetworkedObject(true, instanceId, 0, null, null); SpawnManager.SpawnNetworkedObjectLocally(networkedObject, networkId, true, isPlayerObject, owner, objectStream, false, 0, true, destroyWithScene); } } } using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteByteArray(switchSceneGuid.ToByteArray()); InternalMessageHandler.Send(NetworkingManager.Singleton.ServerClientId, MLAPIConstants.MLAPI_CLIENT_SWITCH_SCENE_COMPLETED, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null); } } isSwitching = false; if (OnSceneSwitched != null) { OnSceneSwitched(); } }
internal static void SpawnObject(NetworkedObject netObject, uint?clientOwnerId = null, Stream payload = null, bool destroyWithScene = false) { if (netObject.isSpawned) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Object already spawned"); } return; } else if (!netManager.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Only server can spawn objects"); } return; } else if (SpawnManager.GetNetworkedPrefabIndexOfName(netObject.NetworkedPrefabName) == -1) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The prefab name " + netObject.NetworkedPrefabName + " does not exist as a networkedPrefab"); } return; } else if (!netManager.NetworkConfig.HandleObjectSpawning) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("NetworkConfig is set to not handle object spawning"); } return; } uint netId = GetNetworkObjectId(); netObject.NetworkId = netId; SpawnedObjects.Add(netId, netObject); SpawnedObjectsList.Add(netObject); netObject.isSpawned = true; netObject.destroyWithScene = destroyWithScene; netObject.sceneSpawnedInIndex = NetworkSceneManager.CurrentActiveSceneIndex; if (clientOwnerId != null) { netObject.OwnerClientId = clientOwnerId.Value; NetworkingManager.singleton.ConnectedClients[clientOwnerId.Value].OwnedObjects.Add(netObject); } if (payload == null) { netObject.InvokeBehaviourNetworkSpawn(null); } else { netObject.InvokeBehaviourNetworkSpawn(payload); } foreach (var client in netManager.ConnectedClients) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteBool(false); writer.WriteUInt32Packed(netObject.NetworkId); writer.WriteUInt32Packed(netObject.OwnerClientId); writer.WriteUInt64Packed(netObject.NetworkedPrefabHash); writer.WriteBool(netObject.destroyWithScene == null ? true : netObject.destroyWithScene.Value); writer.WriteBool(netObject.SceneDelayedSpawn); writer.WriteUInt32Packed(netObject.sceneSpawnedInIndex); writer.WriteSinglePacked(netObject.transform.position.x); writer.WriteSinglePacked(netObject.transform.position.y); writer.WriteSinglePacked(netObject.transform.position.z); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); if (payload != null) { writer.WriteInt32Packed((int)payload.Length); } netObject.WriteNetworkedVarData(stream, client.Key); if (payload != null) { stream.CopyFrom(payload); } InternalMessageHandler.Send(client.Key, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } } }
internal static void OnDestroyObject(ulong networkId, bool destroyGameObject) { if (NetworkingManager.Singleton == null) { return; } //Removal of spawned object if (!SpawnedObjects.ContainsKey(networkId)) { return; } if (!SpawnedObjects[networkId].IsOwnedByServer && !SpawnedObjects[networkId].IsPlayerObject && NetworkingManager.Singleton.ConnectedClients.ContainsKey(SpawnedObjects[networkId].OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.Singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAt(i); } } } SpawnedObjects[networkId].IsSpawned = false; if (NetworkingManager.Singleton != null && NetworkingManager.Singleton.IsServer) { releasedNetworkObjectIds.Push(networkId); if (SpawnedObjects[networkId] != null) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt64Packed(networkId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, SpawnedObjects[networkId]); } } } } GameObject go = SpawnedObjects[networkId].gameObject; if (destroyGameObject && go != null) { if (customDestroyHandlers.ContainsKey(SpawnedObjects[networkId].PrefabHash)) { customDestroyHandlers[SpawnedObjects[networkId].PrefabHash](SpawnedObjects[networkId]); SpawnManager.OnDestroyObject(networkId, false); } else { MonoBehaviour.Destroy(go); } } SpawnedObjects.Remove(networkId); for (int i = SpawnedObjectsList.Count - 1; i > -1; i--) { if (SpawnedObjectsList[i].NetworkId == networkId) { SpawnedObjectsList.RemoveAt(i); } } }
internal void RebuildObservers(uint?clientId = null) { bool initial = clientId != null; if (initial) { bool shouldBeAdded = true; for (int i = 0; i < childNetworkedBehaviours.Count; i++) { bool state = childNetworkedBehaviours[i].OnCheckObserver(clientId.Value); if (state == false) { shouldBeAdded = false; break; } } if (shouldBeAdded) { observers.Add(clientId.Value); } } else { HashSet <uint> previousObservers = new HashSet <uint>(observers); HashSet <uint> newObservers = new HashSet <uint>(); bool update = false; for (int i = 0; i < childNetworkedBehaviours.Count; i++) { bool changed = childNetworkedBehaviours[i].OnRebuildObservers(newObservers); if (changed) { observers = newObservers; update = true; break; } } if (update) { foreach (KeyValuePair <uint, NetworkedClient> pair in NetworkingManager.singleton.connectedClients) { if (pair.Key == NetworkingManager.singleton.NetworkConfig.NetworkTransport.HostDummyId) { continue; } if ((previousObservers.Contains(pair.Key) && !newObservers.Contains(pair.Key)) || (!previousObservers.Contains(pair.Key) && newObservers.Contains(pair.Key))) { //Something changed for this client. using (BitWriter writer = new BitWriter()) { writer.WriteUInt(networkId); writer.WriteBool(observers.Contains(pair.Key)); InternalMessageHandler.Send(pair.Key, "MLAPI_SET_VISIBILITY", "MLAPI_INTERNAL", writer.Finalize(), null); } FlushToClient(pair.Key); } } } } }
//Server only internal static void SpawnPlayerObject(NetworkedObject netObject, uint clientId, Stream payload = null) { if (netObject.isSpawned) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Object already spawned"); } return; } else if (!netManager.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Only server can spawn objects"); } return; } else if (!netManager.NetworkConfig.NetworkPrefabIds.ContainsKey(netObject.NetworkedPrefabName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The prefab name " + netObject.NetworkedPrefabName + " does not exist as a networkedPrefab"); } return; } else if (!netManager.NetworkConfig.HandleObjectSpawning) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("NetworkConfig is set to not handle object spawning"); } return; } else if (netManager.ConnectedClients[clientId].PlayerObject != null) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Client already have a player object"); } return; } uint netId = GetNetworkObjectId(); netObject.NetworkId = netId; SpawnedObjects.Add(netId, netObject); SpawnedObjectsList.Add(netObject); netObject.isSpawned = true; netObject.sceneObject = false; netObject.isPlayerObject = true; netManager.ConnectedClients[clientId].PlayerObject = netObject; if (payload == null) { netObject.InvokeBehaviourNetworkSpawn(null); } else { netObject.InvokeBehaviourNetworkSpawn(payload); } foreach (var client in netManager.ConnectedClients) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteBool(true); writer.WriteUInt32Packed(netObject.NetworkId); writer.WriteUInt32Packed(netObject.OwnerClientId); writer.WriteInt32Packed(netManager.NetworkConfig.NetworkPrefabIds[netObject.NetworkedPrefabName]); writer.WriteBool(netObject.sceneObject == null ? true : netObject.sceneObject.Value); writer.WriteSinglePacked(netObject.transform.position.x); writer.WriteSinglePacked(netObject.transform.position.y); writer.WriteSinglePacked(netObject.transform.position.z); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.x); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.y); writer.WriteSinglePacked(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); netObject.WriteNetworkedVarData(stream, client.Key); if (payload != null) { stream.CopyFrom(payload); } InternalMessageHandler.Send(client.Key, MLAPIConstants.MLAPI_ADD_OBJECT, "MLAPI_INTERNAL", stream); } } } }
internal static void OnDestroyObject(uint networkId, bool destroyGameObject) { if ((netManager == null || !netManager.NetworkConfig.HandleObjectSpawning)) { return; } //Removal of pending object //Even though pending objects is marked with DontDestroyOnLoad, the OnDestroy method is invoked on pending objects. They are however not //destroyed (probably a unity bug for having an gameobject spawned as inactive). Therefore we only actual remove it from the list if //destroyGameObject is set to true, meaning MLAPI decided to destroy it, not unity. if (destroyGameObject == true && PendingSpawnObjects.ContainsKey(networkId)) { if (!PendingSpawnObjects[networkId].netObject.isOwnedByServer && !PendingSpawnObjects[networkId].netObject.isPlayerObject && netManager.ConnectedClients.ContainsKey(PendingSpawnObjects[networkId].netObject.OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.singleton.ConnectedClients[PendingSpawnObjects[networkId].netObject.OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.singleton.ConnectedClients[PendingSpawnObjects[networkId].netObject.OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.singleton.ConnectedClients[PendingSpawnObjects[networkId].netObject.OwnerClientId].OwnedObjects.RemoveAt(i); } } } GameObject pendingGameObject = PendingSpawnObjects[networkId].netObject.gameObject; if (pendingGameObject != null) { MonoBehaviour.Destroy(pendingGameObject); } PendingSpawnObjects.Remove(networkId); } //Removal of spawned object if (!SpawnedObjects.ContainsKey(networkId)) { return; } if (!SpawnedObjects[networkId].isOwnedByServer && !SpawnedObjects[networkId].isPlayerObject && netManager.ConnectedClients.ContainsKey(SpawnedObjects[networkId].OwnerClientId)) { //Someone owns it. for (int i = NetworkingManager.singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.Count - 1; i > -1; i--) { if (NetworkingManager.singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects[i].NetworkId == networkId) { NetworkingManager.singleton.ConnectedClients[SpawnedObjects[networkId].OwnerClientId].OwnedObjects.RemoveAt(i); } } } SpawnedObjects[networkId].isSpawned = false; if (netManager != null && netManager.isServer) { releasedNetworkObjectIds.Push(networkId); if (SpawnedObjects[networkId] != null) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(networkId); InternalMessageHandler.Send(MLAPIConstants.MLAPI_DESTROY_OBJECT, "MLAPI_INTERNAL", stream, SecuritySendFlags.None); } } } } GameObject go = SpawnedObjects[networkId].gameObject; if (destroyGameObject && go != null) { MonoBehaviour.Destroy(go); } SpawnedObjects.Remove(networkId); for (int i = SpawnedObjectsList.Count - 1; i > -1; i--) { if (SpawnedObjectsList[i].NetworkId == networkId) { SpawnedObjectsList.RemoveAt(i); } } }
private static void OnSceneUnloadServer(Guid switchSceneGuid) { // Justification: Rare alloc, could(should?) reuse List <NetworkedObject> newSceneObjects = new List <NetworkedObject>(); { NetworkedObject[] networkedObjects = MonoBehaviour.FindObjectsOfType <NetworkedObject>(); for (int i = 0; i < networkedObjects.Length; i++) { if (networkedObjects[i].IsSceneObject == null) { SpawnManager.SpawnNetworkedObjectLocally(networkedObjects[i], SpawnManager.GetNetworkObjectId(), true, false, null, null, false, 0, false, true); newSceneObjects.Add(networkedObjects[i]); } } } for (int j = 0; j < NetworkingManager.Singleton.ConnectedClientsList.Count; j++) { if (NetworkingManager.Singleton.ConnectedClientsList[j].ClientId != NetworkingManager.Singleton.ServerClientId) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32Packed(CurrentActiveSceneIndex); writer.WriteByteArray(switchSceneGuid.ToByteArray()); uint sceneObjectsToSpawn = 0; for (int i = 0; i < newSceneObjects.Count; i++) { if (newSceneObjects[i].observers.Contains(NetworkingManager.Singleton.ConnectedClientsList[j].ClientId)) { sceneObjectsToSpawn++; } } writer.WriteUInt32Packed(sceneObjectsToSpawn); for (int i = 0; i < newSceneObjects.Count; i++) { if (newSceneObjects[i].observers.Contains(NetworkingManager.Singleton.ConnectedClientsList[j].ClientId)) { if (NetworkingManager.Singleton.NetworkConfig.UsePrefabSync) { writer.WriteBool(newSceneObjects[i].IsPlayerObject); writer.WriteUInt64Packed(newSceneObjects[i].NetworkId); writer.WriteUInt64Packed(newSceneObjects[i].OwnerClientId); writer.WriteUInt64Packed(newSceneObjects[i].PrefabHash); writer.WriteBool(newSceneObjects[i].DestroyWithScene); writer.WriteSinglePacked(newSceneObjects[i].transform.position.x); writer.WriteSinglePacked(newSceneObjects[i].transform.position.y); writer.WriteSinglePacked(newSceneObjects[i].transform.position.z); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.x); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.y); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.z); if (NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar) { newSceneObjects[i].WriteNetworkedVarData(stream, NetworkingManager.Singleton.ConnectedClientsList[j].ClientId); } } else { writer.WriteBool(newSceneObjects[i].IsPlayerObject); writer.WriteUInt64Packed(newSceneObjects[i].NetworkId); writer.WriteUInt64Packed(newSceneObjects[i].OwnerClientId); writer.WriteUInt64Packed(newSceneObjects[i].NetworkedInstanceId); writer.WriteBool(newSceneObjects[i].DestroyWithScene); if (NetworkingManager.Singleton.NetworkConfig.EnableNetworkedVar) { newSceneObjects[i].WriteNetworkedVarData(stream, NetworkingManager.Singleton.ConnectedClientsList[j].ClientId); } } } } } InternalMessageHandler.Send(NetworkingManager.Singleton.ConnectedClientsList[j].ClientId, MLAPIConstants.MLAPI_SWITCH_SCENE, "MLAPI_INTERNAL", stream, SecuritySendFlags.None, null); } } } //Tell server that scene load is completed if (NetworkingManager.Singleton.IsHost) { OnClientSwitchSceneCompleted(NetworkingManager.Singleton.LocalClientId, switchSceneGuid); } isSwitching = false; if (OnSceneSwitched != null) { OnSceneSwitched(); } }