/// <summary> /// Returns a base64 encoded version of the config /// </summary> /// <returns></returns> public string ToBase64() { NetworkConfig config = this; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteString(config.protocalVersion); writer.WriteInt32Packed(config.receiveTickrate); writer.WriteInt32Packed(config.maxReceiveEventsPerTickRate); writer.WriteInt32Packed(config.eventTickrate); writer.WriteInt32Packed(config.clientConnectionBufferTimeout); writer.WriteInt32Packed(config.secondsHistory); writer.WriteBool(config.enableTimeResync); writer.WriteBool(config.ensureNetworkedVarLengthSafety); writer.WriteBits((byte)config.rpcHashSize, 3); writer.WriteBool(recycleNetworkIDs); writer.WriteSinglePacked(networkIDRecycleDelay); writer.WriteBool(enableNetworkedVar); writer.WriteBool(clientSendSceneEvents); writer.WriteBool(serverSendSceneEvents); stream.PadStream(); return Convert.ToBase64String(stream.ToArray()); } } }
/// <summary> /// Hides an object from all clients. /// Server only. /// </summary> public void NetworkHideAll() { //A faster message send bypassing MessageSender completely using (PooledBitStream baseStream = PooledBitStream.Get()) { DoVisibleHideWrite(baseStream); baseStream.PadStream(); using (BitStream stream = MessagePacker.WrapMessage(networkBehaviourManager.unspawnMessageType, 0, baseStream, SecuritySendFlags.None)) { using (List <ulong> .Enumerator clients = networkManager.clients) { while (clients.MoveNext()) { if (clients.Current == networkManager.serverID) { continue; } if (!m_PendingObservers.Remove(clients.Current) && !m_Observers.Remove(clients.Current)) { continue; } networkManager.transport.Send(clients.Current, new ArraySegment <byte>(stream.GetBuffer(), 0, (int)stream.Length), networkManager.networkInternalChannel); } } } } }
/// <summary> /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance /// </summary> /// <param name="cache"></param> /// <returns></returns> public ulong GetConfig(bool cache = true) { if (ConfigHash != null && cache) return ConfigHash.Value; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteString(protocalVersion); writer.WriteBool(enableNetworkedVar); writer.WriteBool(ensureNetworkedVarLengthSafety); writer.WriteBits((byte)rpcHashSize, 3); stream.PadStream(); if (cache) { ConfigHash = stream.ToArray().GetStableHash64(); return ConfigHash.Value; } return stream.ToArray().GetStableHash64(); } } }
/// <summary> /// Removes all ownership of an object from any client and returns ownership to the server. Can only be called by the server or the owner of this Network Behaviour. /// </summary> public void RemoveOwnership() { if (!networkManager.isRunning) { Debug.LogError("Cannot remove ownership. The network is not running."); return; } if (!isNetworkSpawned) { throw new NetworkException("Cannot change ownership. This Network Behaviour is not spawned."); } if (!isServer && !isOwner) { throw new NotServerException("Only the server can call NetworkBehaviour.RemoveOwnership when they are not the owner of the Network Behaviour."); } //Owner does not change if (isOwnedByServer) { return; } if (isServer) { m_OwnerClientID = networkManager.serverID; OnGainedOwnership(); } using (PooledBitStream baseStream = PooledBitStream.Get()) { DoOwnershipWrite(baseStream, networkManager.serverID); if (isServer) { baseStream.PadStream(); using (BitStream stream = MessagePacker.WrapMessage(networkBehaviourManager.ownerChangeMessageType, 0, baseStream, SecuritySendFlags.None)) { using (HashSet <ulong> .Enumerator observers = GetObservers()) { while (observers.MoveNext()) { if (observers.Current == NetworkManager.Get().serverID) { continue; } NetworkManager.Get().transport.Send(observers.Current, new ArraySegment <byte>(stream.GetBuffer(), 0, (int)stream.Length), networkManager.networkInternalChannel); } } } } else { MessageSender.Send(networkManager.serverID, networkBehaviourManager.ownerChangeMessageType, networkManager.networkInternalChannel, baseStream); } } }
/// <summary> /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance /// </summary> /// <param name="cache"></param> /// <returns></returns> public ulong GetConfig(bool cache = true) { if (ConfigHash != null && cache) { return(ConfigHash.Value); } Sort(); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt16Packed(ProtocolVersion); writer.WriteString(MLAPIConstants.MLAPI_PROTOCOL_VERSION); for (int i = 0; i < Channels.Count; i++) { writer.WriteString(Channels[i].Name); writer.WriteByte((byte)Channels[i].Type); } if (EnableSceneSwitching) { for (int i = 0; i < RegisteredScenes.Count; i++) { writer.WriteString(RegisteredScenes[i]); } } if (HandleObjectSpawning && ForceSamePrefabs) { List <NetworkedPrefab> sortedPrefabList = NetworkedPrefabs.OrderBy(x => x.hash).ToList(); for (int i = 0; i < sortedPrefabList.Count; i++) { writer.WriteUInt64Packed(sortedPrefabList[i].hash); } } writer.WriteBool(ForceSamePrefabs); writer.WriteBool(HandleObjectSpawning); writer.WriteBool(EnableEncryption); writer.WriteBool(EnableSceneSwitching); writer.WriteBool(SignKeyExchange); writer.WriteBits((byte)RpcHashSize, 3); writer.WriteBits((byte)PrefabHashSize, 3); stream.PadStream(); if (cache) { ConfigHash = stream.ToArray().GetStableHash64(); return(ConfigHash.Value); } return(stream.ToArray().GetStableHash64()); } } }
/// <summary> /// Returns a base64 encoded version of the config /// </summary> /// <returns></returns> public string ToBase64() { NetworkConfig config = this; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt16Packed(config.ProtocolVersion); writer.WriteBits((byte)config.Transport, 5); writer.WriteUInt16Packed((ushort)config.Channels.Count); for (int i = 0; i < config.Channels.Count; i++) { writer.WriteString(config.Channels[i].Name); writer.WriteBits((byte)config.Channels[i].Type, 5); } writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count); for (int i = 0; i < config.RegisteredScenes.Count; i++) { writer.WriteString(config.RegisteredScenes[i]); } writer.WriteUInt16Packed((ushort)config.NetworkedPrefabs.Count); for (int i = 0; i < config.NetworkedPrefabs.Count; i++) { writer.WriteBool(config.NetworkedPrefabs[i].playerPrefab); writer.WriteString(config.NetworkedPrefabs[i].name); } writer.WriteInt32Packed(config.MessageBufferSize); writer.WriteInt32Packed(config.ReceiveTickrate); writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate); writer.WriteInt32Packed(config.SendTickrate); writer.WriteInt32Packed(config.EventTickrate); writer.WriteInt32Packed(config.MaxConnections); writer.WriteInt32Packed(config.ConnectPort); writer.WriteString(config.ConnectAddress); writer.WriteInt32Packed(config.ClientConnectionBufferTimeout); writer.WriteBool(config.ConnectionApproval); writer.WriteInt32Packed(config.SecondsHistory); writer.WriteBool(config.HandleObjectSpawning); writer.WriteBool(config.EnableEncryption); writer.WriteBool(config.SignKeyExchange); writer.WriteBool(config.EnableSceneSwitching); writer.WriteInt32Packed(config.LoadSceneTimeOut); writer.WriteBool(config.EnableTimeResync); writer.WriteBits((byte)config.RpcHashSize, 3); stream.PadStream(); return(Convert.ToBase64String(stream.ToArray())); } } }
/// <summary> /// Gets a SHA256 hash of parts of the NetworkingConfiguration instance /// </summary> /// <param name="cache"></param> /// <returns></returns> public ulong GetConfig(bool cache = true) { if (ConfigHash != null && cache) { return(ConfigHash.Value); } Sort(); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt16Packed(ProtocolVersion); writer.WriteString(MLAPIConstants.MLAPI_PROTOCOL_VERSION); if (EnableSceneManagement && !AllowRuntimeSceneChanges) { for (int i = 0; i < RegisteredScenes.Count; i++) { writer.WriteString(RegisteredScenes[i]); } } if (ForceSamePrefabs) { List <NetworkedPrefab> sortedPrefabList = NetworkedPrefabs.OrderBy(x => x.Hash).ToList(); for (int i = 0; i < sortedPrefabList.Count; i++) { writer.WriteUInt64Packed(sortedPrefabList[i].Hash); } } writer.WriteBool(EnableNetworkedVar); writer.WriteBool(ForceSamePrefabs); writer.WriteBool(UsePrefabSync); writer.WriteBool(EnableSceneManagement); writer.WriteBool(EnsureNetworkedVarLengthSafety); writer.WriteBool(EnableEncryption); writer.WriteBool(SignKeyExchange); writer.WriteBits((byte)RpcHashSize, 2); stream.PadStream(); if (cache) { ConfigHash = stream.ToArray().GetStableHash64(); return(ConfigHash.Value); } return(stream.ToArray().GetStableHash64()); } } }
/// <summary> /// Returns a base64 encoded version of the config /// </summary> /// <returns></returns> public string ToBase64() { NetworkConfig config = this; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt16Packed(config.ProtocolVersion); writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count); for (int i = 0; i < config.RegisteredScenes.Count; i++) { writer.WriteString(config.RegisteredScenes[i]); } writer.WriteInt32Packed(config.ServerTargetFramerate); writer.WriteInt32Packed(config.NetworkedTransformTickrate); writer.WriteInt32Packed(config.ClientCommandTickrate); writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate); writer.WriteInt32Packed(config.LagCompensationTickRate); writer.WriteInt32Packed(config.EventTickrate); writer.WriteInt32Packed(config.ClientConnectionBufferTimeout); writer.WriteBool(config.ConnectionApproval); writer.WriteInt32Packed(config.SecondsHistory); writer.WriteBool(config.EnableEncryption); writer.WriteBool(config.SignKeyExchange); writer.WriteInt32Packed(config.LoadSceneTimeOut); writer.WriteBool(config.EnableTimeResync); writer.WriteBool(config.EnsureNetworkedVarLengthSafety); writer.WriteBits((byte)config.RpcHashSize, 2); writer.WriteBool(ForceSamePrefabs); writer.WriteBool(UsePrefabSync); writer.WriteBool(EnableSceneManagement); writer.WriteBool(RecycleNetworkIds); writer.WriteSinglePacked(NetworkIdRecycleDelay); writer.WriteBool(EnableNetworkedVar); writer.WriteBool(AllowRuntimeSceneChanges); writer.WriteBool(EnableNetworkLogs); stream.PadStream(); return(Convert.ToBase64String(stream.ToArray())); } } }
/// <summary> /// Does not supress errors invloving clients that already have visibility of this Network Behaviour. /// Server only. /// </summary> /// <param name="clientIDs"></param> public void NetworkShow(List <ulong> clientIDs, Stream spawnPayload = null) { //A faster message send bypassing MessageSender completely if (clientIDs == null) { throw new ArgumentNullException(nameof(clientIDs)); } using (PooledBitStream baseStream = PooledBitStream.Get()) { DoVisibleShowWrite(baseStream, spawnPayload); baseStream.PadStream(); if (clientIDs.Count == 0) { return; //No one to send to. } using (BitStream stream = MessagePacker.WrapMessage(networkBehaviourManager.spawnMessageType, 0, baseStream, SecuritySendFlags.None)) { for (int i = 0; i < clientIDs.Count; i++) { if (clientIDs[i] == NetworkManager.Get().serverID) { continue; } if (m_PendingObservers.Contains(clientIDs[i])) { Debug.LogError("This Network Behaviour is already pending visibility to client '" + clientIDs[i] + "'. Watch for a call to NetworkStart for when it successfully connects.", this); continue; } if (m_Observers.Contains(clientIDs[i])) { Debug.LogError("This Network Behaviour is already pending visibility to client '" + clientIDs[i] + "'. Watch for a call to NetworkStart for when it successfully connects.", this); continue; } m_PendingObservers.Add(clientIDs[i]); NetworkManager.Get().transport.Send(clientIDs[i], new ArraySegment <byte>(stream.GetBuffer(), 0, (int)stream.Length), networkManager.networkInternalChannel); } } } }
/// <summary> /// Returns a base64 encoded version of the config /// </summary> /// <returns></returns> public string ToBase64() { NetworkConfig config = this; using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt16Packed(config.ProtocolVersion); writer.WriteUInt16Packed((ushort)config.RegisteredScenes.Count); for (int i = 0; i < config.RegisteredScenes.Count; i++) { writer.WriteString(config.RegisteredScenes[i]); } writer.WriteInt32Packed(config.ReceiveTickrate); writer.WriteInt32Packed(config.MaxReceiveEventsPerTickRate); writer.WriteInt32Packed(config.SendTickrate); writer.WriteInt32Packed(config.EventTickrate); writer.WriteInt32Packed(config.ClientConnectionBufferTimeout); writer.WriteBool(config.ConnectionApproval); writer.WriteInt32Packed(config.SecondsHistory); writer.WriteBool(config.EnableEncryption); writer.WriteBool(config.SignKeyExchange); writer.WriteInt32Packed(config.LoadSceneTimeOut); writer.WriteBool(config.EnableTimeResync); writer.WriteBits((byte)config.RpcHashSize, 3); writer.WriteBool(ForceSamePrefabs); writer.WriteBool(UsePrefabSync); writer.WriteBool(EnableNetworkedVar); stream.PadStream(); return(Convert.ToBase64String(stream.ToArray())); } } }
/// <summary> /// Hides an object from a specific clients. /// Server only. /// </summary> /// <param name="clientIDs">The clients to hide the object from.</param> public void NetworkHide(List <ulong> clientIDs) { //A faster message send bypassing MessageSender completely if (clientIDs == null) { throw new ArgumentNullException(nameof(clientIDs)); } using (PooledBitStream baseStream = PooledBitStream.Get()) { DoVisibleHideWrite(baseStream); baseStream.PadStream(); if (clientIDs.Count == 0) { return; //No one to send to. } using (BitStream stream = MessagePacker.WrapMessage(networkBehaviourManager.unspawnMessageType, 0, baseStream, SecuritySendFlags.None)) { for (int i = 0; i < clientIDs.Count; i++) { if (clientIDs[i] == networkManager.serverID) { continue; } if (!m_PendingObservers.Remove(clientIDs[i]) && !m_Observers.Remove(clientIDs[i])) { Debug.LogError("This Network Behaviour is already not visible to client '" + clientIDs[i] + "'.", this); continue; } networkManager.transport.Send(clientIDs[i], new ArraySegment <byte>(stream.GetBuffer(), 0, (int)stream.Length), networkManager.networkInternalChannel); } } } }
/// <summary> /// Changes the owner of the object. Can only be called from the server or the owner of this Network Behaviour. /// </summary> /// <param name="targetClientID">The new owner clientId</param> public void SetOwner(ulong targetClientID) { if (!networkManager.isRunning) { Debug.LogError("Cannot set ownership. The network is not running."); return; } if (!isServer) { if (isOwner && targetClientID == networkManager.serverID) { RemoveOwnership(); return; } throw new NotServerException("Only the server can call NetworkBehaviour.SetOwner to target anything but the server."); } if (!isNetworkSpawned) { throw new NetworkException("Cannot change ownership. This Network Behaviour is not spawned."); } if (!IsNetworkVisibleTo(targetClientID)) { throw new NetworkException("Cannot change ownership to a client that does not have visibility of this Network Behaviour."); } //Owner does not change if (targetClientID == ownerID) { return; } if (targetClientID == networkManager.serverID) { RemoveOwnership(); return; } if (isOwner) { m_OwnerClientID = targetClientID; OnLostOwnership(); } else //This may seem redundant but we want ownership changes to be set before the OnLostOwnership call { m_OwnerClientID = targetClientID; } //Send to all (not pending)observers using (PooledBitStream baseStream = PooledBitStream.Get()) { DoOwnershipWrite(baseStream, targetClientID); baseStream.PadStream(); using (BitStream stream = MessagePacker.WrapMessage(networkBehaviourManager.ownerChangeMessageType, 0, baseStream, SecuritySendFlags.None)) { using (HashSet <ulong> .Enumerator observers = GetObservers()) { while (observers.MoveNext()) { if (observers.Current == NetworkManager.Get().serverID) { continue; } NetworkManager.Get().transport.Send(observers.Current, new ArraySegment <byte>(stream.GetBuffer(), 0, (int)stream.Length), networkManager.networkInternalChannel); } } } } }