/* * internal static void FlushSceneObjects() * { * if (!NetworkingManager.singleton.isServer) * return; * * //This loop is bad. For each client, we loop over every object twice. * foreach (KeyValuePair<uint, NetworkedClient> client in netManager.connectedClients) * { * int sceneObjects = 0; * foreach (var netObject in SpawnManager.spawnedObjects) * if (netObject.Value.sceneObject == null || netObject.Value.sceneObject == true) * sceneObjects++; * * using (BitWriter writer = BitWriter.Get()) * { * writer.WriteUShort((ushort)sceneObjects); * foreach (var netObject in SpawnManager.spawnedObjects) * { * if (netObject.Value.sceneObject == null || netObject.Value.sceneObject == true) * { * writer.WriteBool(false); //isLocalPlayer * writer.WriteUInt(netObject.Value.NetworkId); * writer.WriteUInt(netObject.Value.OwnerClientId); * writer.WriteInt(NetworkingManager.singleton.NetworkConfig.NetworkPrefabIds[netObject.Value.NetworkedPrefabName]); * writer.WriteBool(netObject.Value.sceneObject == null ? true : netObject.Value.sceneObject.Value); * writer.WriteBool(netObject.Value.observers.Contains(client.Key)); * * writer.WriteFloat(netObject.Value.transform.position.x); * writer.WriteFloat(netObject.Value.transform.position.y); * writer.WriteFloat(netObject.Value.transform.position.z); * * writer.WriteFloat(netObject.Value.transform.rotation.eulerAngles.x); * writer.WriteFloat(netObject.Value.transform.rotation.eulerAngles.y); * writer.WriteFloat(netObject.Value.transform.rotation.eulerAngles.z); * * if (netObject.Value.observers.Contains(client.Key)) * netObject.Value.WriteFormattedSyncedVarData(writer); * } * } * InternalMessageHandler.Send(client.Key, "MLAPI_ADD_OBJECTS", "MLAPI_INTERNAL", writer, null); * } * } * } */ internal static NetworkedObject CreateSpawnedObject(int networkedPrefabId, uint networkId, uint owner, bool playerObject, Vector3 position, Quaternion rotation, BitReader reader, bool readSyncedVar, bool readPayload) { if (!netManager.NetworkConfig.NetworkPrefabNames.ContainsKey(networkedPrefabId)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot spawn the object, invalid prefabIndex"); } return(null); } GameObject go = MonoBehaviour.Instantiate(netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab, position, rotation); 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 (readSyncedVar) { netObject.SetFormattedSyncedVarData(reader); } netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkPrefabNames[networkedPrefabId]; netObject.isSpawned = true; netObject.isPooledObject = false; if (netManager.isServer) { netObject.NetworkId = GetNetworkObjectId(); } else { netObject.NetworkId = networkId; } netObject.sceneObject = false; netObject.OwnerClientId = owner; netObject.isPlayerObject = playerObject; netObject.transform.position = position; netObject.transform.rotation = rotation; spawnedObjects.Add(netObject.NetworkId, netObject); if (playerObject) { NetworkingManager.singleton.ConnectedClients[owner].PlayerObject = netObject; } netObject.InvokeBehaviourNetworkSpawn(reader); return(netObject); }
//RETURNS THE CLIENTIDS WHICH WAS NOT BEING OBSERVED internal static ref List <uint> Send(string messageType, string channelName, BitWriter messageWriter, uint?fromNetId, uint?networkId = null, ushort?orderId = null) { failedObservers.Clear(); if (netManager.connectedClients.Count == 0) { return(ref failedObservers); } if (netManager.NetworkConfig.EncryptedChannels.Contains(channelName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot send messages over encrypted channel to multiple clients"); } return(ref failedObservers); } using (BitWriter writer = BitWriter.Get()) { writer.WriteGenericMessageHeader(MessageManager.messageTypes[messageType], networkId != null, networkId.GetValueOrDefault(), orderId.GetValueOrDefault(), false, 0, 0); writer.WriteWriter(messageWriter); int channel = MessageManager.channels[channelName]; foreach (KeyValuePair <uint, NetworkedClient> pair in netManager.connectedClients) { uint targetClientId = pair.Key; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. continue; } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we continue if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(pair.Key)) { failedObservers.Add(pair.Key); continue; } writer.Finalize(ref FinalMessageBuffer); NetworkProfiler.StartEvent(TickType.Send, (uint)messageWriter.GetFinalizeSize(), channelName, messageType); byte error; netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), channel, false, out error); NetworkProfiler.EndEvent(); } return(ref failedObservers); } }
internal static void SetCurrentSceneIndex() { if (!sceneNameToIndex.ContainsKey(SceneManager.GetActiveScene().name)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Scene switching is enabled but the current scene (" + SceneManager.GetActiveScene().name + ") is not regisered as a network scene."); } return; } CurrentSceneIndex = sceneNameToIndex[SceneManager.GetActiveScene().name]; }
/// <summary> /// Turns time back a given amount of seconds, invokes an action and turns it back. The time is based on the estimated RTT of a clientId /// </summary> /// <param name="clientId">The clientId's RTT to use</param> /// <param name="action">The action to invoke when time is turned back</param> public static void Simulate(uint clientId, Action action) { if (!NetworkingManager.singleton.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Lag compensation simulations are only to be ran on the server"); } return; } float milisecondsDelay = NetworkingManager.singleton.NetworkConfig.NetworkTransport.GetCurrentRTT(clientId, out error) / 2f; Simulate(milisecondsDelay * 1000f, action); }
/// <summary> /// Creates a networked object pool. Can only be called from the server /// </summary> /// <param name="poolName">Name of the pool</param> /// <param name="spawnablePrefabIndex">The index of the prefab to use in the spawnablePrefabs array</param> /// <param name="size">The amount of objects in the pool</param> public static void CreatePool(string poolName, int spawnablePrefabIndex, uint size = 16) { if (!NetworkingManager.singleton.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Pools can only be created on the server"); } return; } NetworkPool pool = new NetworkPool(spawnablePrefabIndex, size, PoolIndex); PoolNamesToIndexes.Add(poolName, PoolIndex); PoolIndex++; }
internal static int AddIncomingMessageHandler(string name, Action <uint, BitReader> action) { if (messageTypes.ContainsKey(name)) { if (messageCallbacks.ContainsKey(messageTypes[name])) { int handlerId = 0; if (messageHandlerCounter.ContainsKey(messageTypes[name])) { if (!releasedMessageHandlerCounters.ContainsKey(messageTypes[name])) { releasedMessageHandlerCounters.Add(messageTypes[name], new Stack <int>()); } if (releasedMessageHandlerCounters[messageTypes[name]].Count == 0) { handlerId = messageHandlerCounter[messageTypes[name]]; messageHandlerCounter[messageTypes[name]]++; } else { handlerId = releasedMessageHandlerCounters[messageTypes[name]].Pop(); } } else { messageHandlerCounter.Add(messageTypes[name], handlerId + 1); } messageCallbacks[messageTypes[name]].Add(handlerId, action); return(handlerId); } else { messageCallbacks.Add(messageTypes[name], new Dictionary <int, Action <uint, BitReader> >()); messageHandlerCounter.Add(messageTypes[name], 1); messageCallbacks[messageTypes[name]].Add(0, action); return(0); } } else { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The message type " + name + " has not been registered. Please define it in the netConfig"); } return(-1); } }
/// <summary> /// This destroys an object pool and all of it's objects. Can only be called from the server /// </summary> /// <param name="poolName">The name of the pool</param> public static void DestroyPool(string poolName) { if (!NetworkingManager.singleton.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Pools can only be destroyed on the server"); } return; } for (int i = 0; i < Pools[PoolNamesToIndexes[poolName]].objects.Length; i++) { MonoBehaviour.Destroy(Pools[PoolNamesToIndexes[poolName]].objects[i]); } Pools.Remove(PoolNamesToIndexes[poolName]); }
internal static GameObject SpawnPlayerObject(uint clientId, uint networkId, Vector3 position, Quaternion rotation, BitReader reader = null) { if (string.IsNullOrEmpty(netManager.NetworkConfig.PlayerPrefabName) || !netManager.NetworkConfig.NetworkPrefabIds.ContainsKey(netManager.NetworkConfig.PlayerPrefabName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("There is no player prefab in the NetworkConfig, or it's not registered at as a spawnable prefab"); } return(null); } GameObject go = MonoBehaviour.Instantiate(netManager.NetworkConfig.NetworkedPrefabs[netManager.NetworkConfig.NetworkPrefabIds[netManager.NetworkConfig.PlayerPrefabName]].prefab, position, rotation); NetworkedObject netObject = go.GetComponent <NetworkedObject>(); if (netObject == null) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Please add a NetworkedObject component to the root of the player prefab"); } netObject = go.AddComponent <NetworkedObject>(); } if (NetworkingManager.singleton.isServer) { netObject.networkId = GetNetworkObjectId(); } else { netObject.networkId = networkId; } if (reader != null) { netObject.SetFormattedSyncedVarData(reader); } netObject._isPooledObject = false; netObject.ownerClientId = clientId; netObject._isPlayerObject = true; netObject._isSpawned = true; netObject.sceneObject = false; netManager.connectedClients[clientId].PlayerObject = go; spawnedObjects.Add(netObject.NetworkId, netObject); netObject.InvokeBehaviourNetworkSpawn(); return(go); }
/// <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 (BitWriter writer = BitWriter.Get()) { writer.WriteUInt(netObject.NetworkId); InternalMessageHandler.Send("MLAPI_DESTROY_POOL_OBJECT", "MLAPI_INTERNAL", writer, 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 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); sceneLoad.completed += OnSceneLoaded; using (BitWriter writer = BitWriter.Get()) { writer.WriteUInt(sceneNameToIndex[sceneName]); InternalMessageHandler.Send("MLAPI_SWITCH_SCENE", "MLAPI_INTERNAL", writer, null); } }
/// <summary> /// Turns time back a given amount of seconds, invokes an action and turns it back /// </summary> /// <param name="secondsAgo">The amount of seconds</param> /// <param name="action">The action to invoke when time is turned back</param> public static void Simulate(float secondsAgo, Action action) { if (!NetworkingManager.singleton.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Lag compensation simulations are only to be ran on the server"); } return; } for (int i = 0; i < simulationObjects.Count; i++) { simulationObjects[i].ReverseTransform(secondsAgo); } action.Invoke(); for (int i = 0; i < simulationObjects.Count; i++) { simulationObjects[i].ResetStateTransform(); } }
internal static GameObject SpawnPrefabIndexClient(int networkedPrefabId, uint networkId, uint owner, Vector3 position, Quaternion rotation, BitReader reader = null) { if (!netManager.NetworkConfig.NetworkPrefabNames.ContainsKey(networkedPrefabId)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot spawn the object, invalid prefabIndex"); } return(null); } GameObject go = MonoBehaviour.Instantiate(netManager.NetworkConfig.NetworkedPrefabs[networkedPrefabId].prefab, position, rotation); 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 (reader != null) { netObject.SetFormattedSyncedVarData(reader); } netObject.NetworkedPrefabName = netManager.NetworkConfig.NetworkPrefabNames[networkedPrefabId]; netObject._isSpawned = true; netObject._isPooledObject = false; netObject.networkId = networkId; netObject.ownerClientId = owner; netObject.transform.position = position; netObject.transform.rotation = rotation; spawnedObjects.Add(netObject.NetworkId, netObject); netObject.InvokeBehaviourNetworkSpawn(); return(go); }
internal static void RemoveOwnership(uint netId) { if (!netManager.isServer) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("You can only remove ownership from Server"); } return; } NetworkedObject netObject = SpawnManager.spawnedObjects[netId]; NetworkingManager.singleton.connectedClients[netObject.OwnerClientId].OwnedObjects.RemoveAll(x => x.NetworkId == netId); netObject.ownerClientId = NetworkingManager.singleton.NetworkConfig.NetworkTransport.InvalidDummyId; using (BitWriter writer = BitWriter.Get()) { writer.WriteUInt(netId); writer.WriteUInt(netObject.ownerClientId); InternalMessageHandler.Send("MLAPI_CHANGE_OWNER", "MLAPI_INTERNAL", writer, null); } }
internal static void Send(List <uint> clientIds, string messageType, string channelName, BitWriter messageWriter, uint?fromNetId, uint?networkId = null, ushort?orderId = null) { if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName)) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Cannot send messages over encrypted channel to multiple clients"); } return; } using (BitWriter writer = BitWriter.Get()) { writer.WriteUShort(MessageManager.messageTypes[messageType]); writer.WriteBool(networkId != null); if (networkId != null) { writer.WriteUInt(networkId.Value); } if (orderId != null) { writer.WriteUShort(orderId.Value); } writer.WriteBool(false); writer.WriteAlignBits(); writer.WriteWriter(messageWriter); int channel = MessageManager.channels[channelName]; for (int i = 0; i < clientIds.Count; i++) { uint targetClientId = clientIds[i]; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. continue; } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we continue if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(clientIds[i])) { continue; } writer.Finalize(ref FinalMessageBuffer); NetworkProfiler.StartEvent(TickType.Send, (uint)messageWriter.GetFinalizeSize(), channelName, messageType); byte error; netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), channel, false, out error); NetworkProfiler.EndEvent(); } } }
internal static void HandleConnectionApproved(uint clientId, BitReader reader, int channelId) { netManager.LocalClientId = reader.ReadUInt(); uint sceneIndex = 0; if (netManager.NetworkConfig.EnableSceneSwitching) { sceneIndex = reader.ReadUInt(); } #if !DISABLE_CRYPTOGRAPHY if (netManager.NetworkConfig.EnableEncryption) { byte[] serverPublicKey = reader.ReadByteArray(); netManager.clientAesKey = netManager.clientDiffieHellman.GetSharedSecret(serverPublicKey); if (netManager.NetworkConfig.SignKeyExchange) { byte[] publicKeySignature = reader.ReadByteArray(); using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; rsa.FromXmlString(netManager.NetworkConfig.RSAPublicKey); if (!rsa.VerifyData(serverPublicKey, new SHA512CryptoServiceProvider(), publicKeySignature)) { //Man in the middle. if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("Signature doesnt match for the key exchange public part. Disconnecting"); } } netManager.StopClient(); return; } } } } #endif float netTime = reader.ReadFloat(); int remoteStamp = reader.ReadInt(); int msDelay = NetworkingManager.singleton.NetworkConfig.NetworkTransport.GetRemoteDelayTimeMS(clientId, remoteStamp, out byte error); netManager.NetworkTime = netTime + (msDelay / 1000f); netManager.ConnectedClients.Add(netManager.LocalClientId, new NetworkedClient() { ClientId = netManager.LocalClientId }); int clientCount = reader.ReadInt(); for (int i = 0; i < clientCount; i++) { uint _clientId = reader.ReadUInt(); netManager.ConnectedClients.Add(_clientId, new NetworkedClient() { ClientId = _clientId }); netManager.ConnectedClientsList.Add(netManager.ConnectedClients[_clientId]); } if (netManager.NetworkConfig.HandleObjectSpawning) { SpawnManager.DestroySceneObjects(); int objectCount = reader.ReadInt(); for (int i = 0; i < objectCount; i++) { bool isPlayerObject = reader.ReadBool(); uint networkId = reader.ReadUInt(); uint ownerId = reader.ReadUInt(); int prefabId = reader.ReadInt(); bool isActive = reader.ReadBool(); bool sceneObject = reader.ReadBool(); bool visible = reader.ReadBool(); float xPos = reader.ReadFloat(); float yPos = reader.ReadFloat(); float zPos = reader.ReadFloat(); float xRot = reader.ReadFloat(); float yRot = reader.ReadFloat(); float zRot = reader.ReadFloat(); NetworkedObject netObject = SpawnManager.CreateSpawnedObject(prefabId, networkId, ownerId, isPlayerObject, new Vector3(xPos, yPos, zPos), Quaternion.Euler(xRot, yRot, zRot), reader, visible, false); netObject.SetLocalVisibility(visible); netObject.sceneObject = sceneObject; netObject.gameObject.SetActive(isActive); } } if (netManager.NetworkConfig.EnableSceneSwitching) { NetworkSceneManager.OnSceneSwitch(sceneIndex); } netManager.isConnectedClients = true; if (netManager.OnClientConnectedCallback != null) { netManager.OnClientConnectedCallback.Invoke(netManager.LocalClientId); } }
//RETURNS IF IT SUCCEDED OR FAILED BECAUSE OF NON-OBSERVER. ANY OTHER FAIL WILL RETURN TRUE internal static bool Send(uint clientId, string messageType, string channelName, BitWriter messageWriter, uint?fromNetId, uint?networkId = null, ushort?orderId = null, bool skipQueue = false) { uint targetClientId = clientId; if (netManager.isHost && targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Don't invoke the message on our own machine. Instant stack overflow. return(true); } else if (targetClientId == netManager.NetworkConfig.NetworkTransport.HostDummyId) { //Client trying to send data to host targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } //If we respect the observers, and the message is targeted (networkId != null) and the targetedNetworkId isnt observing the receiver. Then we return if (netManager.isServer && fromNetId != null && !SpawnManager.spawnedObjects[fromNetId.Value].observers.Contains(clientId)) { return(false); } bool isPassthrough = (!netManager.isServer && clientId != netManager.NetworkConfig.NetworkTransport.ServerNetId && netManager.NetworkConfig.AllowPassthroughMessages); if (isPassthrough && !netManager.NetworkConfig.PassthroughMessageHashSet.Contains(MessageManager.messageTypes[messageType])) { if (LogHelper.CurrentLogLevel <= LogLevel.Normal) { LogHelper.LogWarning("The The MessageType " + messageType + " is not registered as an allowed passthrough message type"); } return(true); } using (BitWriter writer = BitWriter.Get()) { writer.WriteGenericMessageHeader(MessageManager.messageTypes[messageType], networkId != null, networkId.GetValueOrDefault(), orderId.GetValueOrDefault(), isPassthrough, clientId, null); #if !DISABLE_CRYPTOGRAPHY if (netManager.NetworkConfig.EncryptedChannelsHashSet.Contains(channelName)) { //This is an encrypted message. byte[] encrypted; if (netManager.isServer) { encrypted = CryptographyHelper.Encrypt(messageWriter.Finalize(), netManager.ConnectedClients[clientId].AesKey); } else { encrypted = CryptographyHelper.Encrypt(messageWriter.Finalize(), netManager.clientAesKey); } writer.WriteByteArray(encrypted); } else #endif writer.WriteWriter(messageWriter); if (isPassthrough) { targetClientId = netManager.NetworkConfig.NetworkTransport.ServerNetId; } writer.Finalize(ref FinalMessageBuffer); NetworkProfiler.StartEvent(TickType.Send, (uint)messageWriter.GetFinalizeSize(), channelName, messageType); byte error; if (skipQueue) { netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), MessageManager.channels[channelName], true, out error); } else { netManager.NetworkConfig.NetworkTransport.QueueMessageForSending(targetClientId, ref FinalMessageBuffer, (int)writer.GetFinalizeSize(), MessageManager.channels[channelName], false, out error); } NetworkProfiler.EndEvent(); return(true); } }
internal static void SpawnObject(NetworkedObject netObject, uint?clientOwnerId = null, BitWriter 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; } uint netId = GetNetworkObjectId(); netObject.networkId = netId; spawnedObjects.Add(netId, netObject); netObject._isSpawned = true; netObject.sceneObject = false; if (clientOwnerId != null) { netObject.ownerClientId = clientOwnerId.Value; NetworkingManager.singleton.connectedClients[clientOwnerId.Value].OwnedObjects.Add(netObject); } if (payload == null) { netObject.InvokeBehaviourNetworkSpawn(null); } else { using (BitReader payloadReader = BitReader.Get(payload.Finalize())) netObject.InvokeBehaviourNetworkSpawn(payloadReader); } foreach (var client in netManager.connectedClients) { netObject.RebuildObservers(client.Key); using (BitWriter writer = BitWriter.Get()) { writer.WriteBool(false); writer.WriteUInt(netObject.NetworkId); writer.WriteUInt(netObject.OwnerClientId); writer.WriteInt(netManager.NetworkConfig.NetworkPrefabIds[netObject.NetworkedPrefabName]); writer.WriteBool(netObject.sceneObject == null ? true : netObject.sceneObject.Value); writer.WriteBool(netObject.observers.Contains(client.Key)); writer.WriteFloat(netObject.transform.position.x); writer.WriteFloat(netObject.transform.position.y); writer.WriteFloat(netObject.transform.position.z); writer.WriteFloat(netObject.transform.rotation.eulerAngles.x); writer.WriteFloat(netObject.transform.rotation.eulerAngles.y); writer.WriteFloat(netObject.transform.rotation.eulerAngles.z); writer.WriteBool(payload != null); if (netObject.observers.Contains(client.Key)) { netObject.WriteFormattedSyncedVarData(writer); } if (payload != null) { writer.WriteWriter(payload); } InternalMessageHandler.Send(client.Key, "MLAPI_ADD_OBJECT", "MLAPI_INTERNAL", writer, null); } } }