private void GetHostsRequestToServer(NetworkingPlayer sender, NetworkingStream stream) { ushort pageNumber = ObjectMapper.Map <ushort>(stream); List <HostInfo> subList = new List <HostInfo>(); for (int i = pageNumber * COUNT_PER_PAGE; i < COUNT_PER_PAGE; i++) { if (hosts.Count <= i) { break; } subList.Add(hosts[i]); } BMSByte data = new BMSByte(); ObjectMapper.MapBytes(data, subList.Count); foreach (HostInfo host in hosts) { ObjectMapper.MapBytes(data, host.IpAddress, host.port, host.maxPlayers, host.name, host.password, host.gameType, host.connectedPlayers, host.comment, host.sceneName); } Networking.WriteCustom(WriteCustomMapping.MASTER_SERVER_GET_HOSTS, socket, data, sender, true); }
/// <summary> /// Disconnect from the server /// </summary> public override void Disconnect() { BMSByte tmp = new BMSByte(); ObjectMapper.MapBytes(tmp, "disconnect"); lock (writeMutex) { writeStream.SetProtocolType(Networking.ProtocolType.TCP); writeStream.Prepare(this, NetworkingStream.IdentifierType.Disconnect, 0, tmp, NetworkReceivers.Server, noBehavior: true); Write(writeStream); } if (readWorker != null) #if UNITY_IOS { readWorker.Interrupt(); } #else { readWorker.Abort(); } #endif if (netStream != null) { netStream.Close(); } if (client != null) { client.Close(); } OnDisconnected(); }
private async void ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args) { BMSByte tmp = new BMSByte(); if (Connections >= MaxConnections) { ObjectMapper.MapBytes(tmp, "Max Players Reached On Server"); WriteAndClose(args.Socket, new NetworkingStream(Networking.ProtocolType.TCP).Prepare(this, NetworkingStream.IdentifierType.Disconnect, null, tmp)); return; } // TODO: Setup name string name = string.Empty; NetworkingPlayer player = new NetworkingPlayer(ServerPlayerCounter, args.Socket.Information.RemoteAddress.CanonicalName, args.Socket, name); Players.Add(player); OnPlayerConnected(player); tmp.Clear(); ObjectMapper.MapBytes(tmp, player.NetworkId); Write(player, new NetworkingStream(Networking.ProtocolType.TCP).Prepare(this, NetworkingStream.IdentifierType.Player, null, tmp)); }
private void TellServerLevelLoaded(int level) { if (OwningNetWorker == null || OwningNetWorker.IsServer) { return; } loadLevelPing.Clear(); ObjectMapper.MapBytes(loadLevelPing, level); Networking.WriteCustom(WriteCustomMapping.NETWORKING_MANAGER_PLAYER_LOADED_LEVEL, OwningNetWorker, loadLevelPing, true, NetworkReceivers.Server); }
// TODO: Support updating the master server on scene change to "Application.loadedLevelName" /// <summary> /// This method is used to update the current player count on the master server for this server /// </summary> /// <param name="host">The host of the master server</param> /// <param name="port">The port number that this server is running on</param> /// <param name="playerCount">The current player count for this server</param> public static void UpdateServer(string host, ushort port, int playerCount) { Action <NetWorker> call = delegate(NetWorker socket) { BMSByte data = new BMSByte(); ObjectMapper.MapBytes(data, port, playerCount); Networking.WriteCustom(WriteCustomMapping.MASTER_SERVER_UPDATE_SERVER, socket, data, true, NetworkReceivers.Server); }; Request(host, call); }
/// <summary> /// This method is used to register a server to the master server to be retreived by clients /// </summary> /// <param name="host">The master server host address</param> /// <param name="port">The port that this server will be running on</param> /// <param name="maxPlayers">The maximum amount of players allowed on this server</param> /// <param name="name">The name for this server</param> /// <param name="gameType">The type of game for this server (ie. deathmatch, capture the flag, etc.)</param> /// <param name="comment">The comment for this server (usually user populated for loading screens)</param> /// <param name="password">The password for this server</param> /// <param name="sceneName">The scene name that this server is currently on</param> public static void RegisterServer(string host, ushort port, int maxPlayers, string name, string gameType = "", string comment = "", string password = "", string sceneName = "") { Action <NetWorker> call = delegate(NetWorker socket) { BMSByte data = new BMSByte(); ObjectMapper.MapBytes(data, port, maxPlayers, name, gameType, comment, password, sceneName); Networking.WriteCustom(WriteCustomMapping.MASTER_SERVER_REGISTER_SERVER, socket, data, true, NetworkReceivers.Server); }; Request(host, call); }
/// <summary> /// This method requests all of the hosts from the master server /// </summary> /// <param name="host">The host of the master server</param> /// <param name="pageNumber">This is the page number (starting from 0). So if you want to get entries 0-n then you will pass 0, if you want n-n+n then pass 1</param> /// <param name="callback">This is the method that will be called once the master server responds with the host list</param> public static void GetHosts(string host, ushort pageNumber, Action <HostInfo[]> callback) { requestHostsCallback = callback; Action <NetWorker> call = delegate(NetWorker socket) { BMSByte data = new BMSByte(); ObjectMapper.MapBytes(data, pageNumber); Networking.WriteCustom(WriteCustomMapping.MASTER_SERVER_GET_HOSTS, socket, data, true, NetworkReceivers.Server); }; Request(host, call); }
private void listenWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { lock (writeMutex) { writeBuffer.Clear(); ObjectMapper.MapBytes(writeBuffer, ((NetworkingPlayer)e.UserState).NetworkId); writeStream.SetProtocolType(Networking.ProtocolType.TCP); Write((NetworkingPlayer)e.UserState, writeStream.Prepare(this, NetworkingStream.IdentifierType.Player, 0, writeBuffer, noBehavior: true)); OnPlayerConnected((NetworkingPlayer)e.UserState); } }
/// <summary> /// Sends the forge transport object /// </summary> /// <param name="receivers">who will receive the transport object</param> /// <param name="reliable">send the packet reliably/unreliably</param> /// <remarks> /// Serializes the forge transport object, then sends it to all clients specified by the receivers. /// Subscribe a method to ForgeTransportObject.transportObject.transportFinished to decide what method should /// be executed when the object is received. /// </remarks> public void Send(NetworkReceivers receivers = NetworkReceivers.Others, bool reliable = true) { lock (serializerMutex) { serializer.Clear(); ObjectMapper.MapBytes(serializer, id); foreach (FieldInfo field in fields) { ObjectMapper.MapBytes(serializer, field.GetValue(this)); } Networking.WriteCustom(WriteCustomMapping.TRANSPORT_OBJECT, Networking.PrimarySocket, serializer, reliable, receivers); } }
/// <summary> /// Get all the new player updates /// </summary> public override void GetNewPlayerUpdates() { Me = new NetworkingPlayer(Uniqueidentifier, "127.0.0.1", null, string.Empty); BMSByte tmp = new BMSByte(); ObjectMapper.MapBytes(tmp, "update"); lock (writeMutex) { writeStream.SetProtocolType(Networking.ProtocolType.TCP); writeStream.Prepare(this, NetworkingStream.IdentifierType.None, 0, tmp, NetworkReceivers.Server, noBehavior: true); Write(writeStream); } }
public BMSByte Serialized() { serializeBuffer.Clear(); foreach (var property in Properties) { object val = property.GetValue(this, null); if (property.PropertyType == typeof(string)) { serializeBuffer.Append(BitConverter.GetBytes(((string)val).Length)); } ObjectMapper.MapBytes(serializeBuffer, val); } return(serializeBuffer); }
/// <summary> /// Creates a network stream for the method with the specified string name and returns the method info /// </summary> /// <param name="methodName">The name of the method to call from this class</param> /// <param name="receivers">The players on the network that will be receiving RPC</param> /// <param name="arguments">The list of arguments that will be sent for the RPC</param> /// <returns></returns> private int GetStreamRPC(string methodName, NetworkReceivers receivers, params object[] arguments) { foreach (KeyValuePair <int, KeyValuePair <MethodInfo, List <IBRPCIntercept> > > rpc in RPCs) { if (rpc.Value.Key.Name == methodName) { if (!NetworkingManager.IsOnline) { return(rpc.Key); } getStreamBuffer.Clear(); ObjectMapper.MapBytes(getStreamBuffer, rpc.Key); #if UNITY_EDITOR int argCount = 0; foreach (var param in rpc.Value.Key.GetParameters()) { if (param.ParameterType != typeof(MessageInfo)) { argCount++; } } if (arguments.Length != argCount) { throw new NetworkException("The number of arguments [" + arguments.Length + "] provided for the " + methodName + " RPC call do not match the method signature argument count [" + rpc.Value.Key.GetParameters().Length + "]"); } #endif if (arguments != null && arguments.Length > 0) { ObjectMapper.MapBytes(getStreamBuffer, arguments); } bool buffered = receivers == NetworkReceivers.AllBuffered || receivers == NetworkReceivers.OthersBuffered; rpcNetworkingStream.SetProtocolType(OwningNetWorker is CrossPlatformUDP ? Networking.ProtocolType.UDP : Networking.ProtocolType.TCP); rpcNetworkingStream.Prepare(OwningNetWorker, NetworkingStream.IdentifierType.RPC, this, getStreamBuffer, receivers, buffered); return(rpc.Key); } } throw new NetworkException(14, "No method marked with [BRPC] was found by the name " + methodName); }
private void ConnectionLoop(object server) { while (true) { try { TcpClient client = ((TcpListener)server).AcceptTcpClient(); if (Connections >= MaxConnections) { lock (writeMutex) { writeBuffer.Clear(); ObjectMapper.MapBytes(writeBuffer, "Max Players Reached On Server"); staticWriteStream.SetProtocolType(Networking.ProtocolType.TCP); WriteAndClose(client, staticWriteStream.Prepare( this, NetworkingStream.IdentifierType.Disconnect, 0, writeBuffer, noBehavior: true)); } return; } // TODO: Set the name string name = string.Empty; NetworkingPlayer player = new NetworkingPlayer(ServerPlayerCounter++, client.Client.RemoteEndPoint.ToString(), client, name); lock (clientMutex) { Players.Add(player); } } catch (Exception exception) { #if !BARE_METAL UnityEngine.Debug.LogException(exception); #endif Disconnect(); } } }
/// <summary> /// Called when the Network as interpreted that a cache message has been sent from the client /// </summary> /// <param name="player">The player that requested data from the cache</param> /// <param name="stream">The data that was received</param> public static void NetworkReadServer(NetworkingPlayer player, NetworkingStream stream) { byte type = ObjectMapper.Map <byte>(stream); int responseHookId = ObjectMapper.Map <int>(stream); string key = ObjectMapper.Map <string>(stream); object obj = Get(key); // TODO: Let the client know it is null if (obj == null) { return; } BMSByte data = new BMSByte(); ObjectMapper.MapBytes(data, type, responseHookId, obj); Networking.WriteCustom(WriteCustomMapping.CACHE_READ_CLIENT, Socket, data, player, true); }
private void PollPlayers() { playerPollData.Clear(); if (!OwningNetWorker.IsServer) { return; } ObjectMapper.MapBytes(playerPollData, OwningNetWorker.Players.Count + 1); // Send the server first ObjectMapper.MapBytes(playerPollData, OwningNetWorker.Me.NetworkId, OwningNetWorker.Me.Name); foreach (NetworkingPlayer player in OwningNetWorker.Players) { ObjectMapper.MapBytes(playerPollData, player.NetworkId, player.Name); } Networking.WriteCustom(WriteCustomMapping.NETWORKING_MANAGER_POLL_PLAYERS, OwningNetWorker, playerPollData, OwningNetWorker.CurrentStreamOwner, true); }
/// <summary> /// Get an object from cache /// </summary> /// <param name="key">The name variable used for storing the desired object</param> /// <returns>The string data at the desired key or null</returns> /// <remarks> /// Allows a client (or the server) to get a value from the Cache, the value is read directly from the server. /// A callback must be specified, this is because the code has to be executed after a moment when the response from the server /// is received. Request can be done like this: /// <code> /// void getServerDescription(){ /// Cache.Request<string>("server_description", delegate (object response){ /// Debug.Log(((string) response)); /// }); /// } /// </code> /// The Cache only supports Forge's supported data Types, you can find a list of supported data Types in the NetSync documentation... /// </remarks> public static void Request <T>(string key, Action <object> callback) { CheckSetup(); if (callback == null) { throw new NetworkException("A callback is needed when requesting data from the server"); } if (Socket.IsServer) { callback(Get <T>(key)); return; } responseHooks.Add(responseHookIncrementer, callback); BMSByte data = new BMSByte(); byte targetType = byte.MaxValue; foreach (KeyValuePair <byte, Type> kv in typeMap) { if (typeof(T) == kv.Value) { targetType = kv.Key; break; } } if (targetType == byte.MaxValue) { throw new NetworkException("Invalid type specified"); } ObjectMapper.MapBytes(data, targetType, responseHookIncrementer, key); Networking.WriteCustom(WriteCustomMapping.CACHE_READ_SERVER, Socket, data, true, NetworkReceivers.Server); responseHookIncrementer++; }
private void ReadClients() { while (true) { try { if (readThreadCancel) { return; } try { lock (clientMutex) { for (int i = 0; i < Players.Count; i++) { if (readThreadCancel) { return; } TcpClient playerClient = (TcpClient)Players[i].SocketEndpoint; NetworkStream playerStream = playerClient.GetStream(); if (!playerClient.Connected) { Disconnect(Players[i--]); continue; } if (!playerStream.DataAvailable) { continue; } if (!Players[i].Connected) { if (!Players[i].WebsocketHeaderPrepared) { byte[] bytes = new byte[playerClient.Available]; playerStream.Read(bytes, 0, bytes.Length); string data = Encoding.UTF8.GetString(bytes); if (new Regex("^GET").IsMatch(data)) { byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + Environment.NewLine + "Connection: Upgrade" + Environment.NewLine + "Upgrade: websocket" + Environment.NewLine + "Sec-WebSocket-Accept: " + Convert.ToBase64String((new SHA1CryptoServiceProvider()).ComputeHash(Encoding.UTF8.GetBytes( new Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ))) + Environment.NewLine + Environment.NewLine); playerStream.Write(response, 0, response.Length); } Players[i].WebsocketHeaderPrepared = true; } else { int length = 0; byte[] bytes = DecodeMessage(GetNextBytes(playerClient, playerStream, out length)); lock (writeMutex) { writeBuffer.Clear(); ObjectMapper.MapBytes(writeBuffer, Players[i].NetworkId); writeStream.SetProtocolType(Networking.ProtocolType.TCP); Write(Players[i], writeStream.Prepare(this, NetworkingStream.IdentifierType.Player, 0, writeBuffer, noBehavior: true)); OnPlayerConnected(Players[i]); } } } else { int length = 0; byte[] bytes = DecodeMessage(GetNextBytes(playerClient, playerStream, out length)); if (bytes[0] == 136) { Disconnect(Players[i--]); continue; } readBuffer.Clear(); readBuffer.Clone(bytes); StreamReceived(Players[i], readBuffer); } } } } catch (Exception ex) { #if !BARE_METAL UnityEngine.Debug.LogException(ex); #endif } Thread.Sleep(ThreadSpeed); } catch (Exception ex) { #if !BARE_METAL UnityEngine.Debug.LogException(ex); #endif } } }
private void Listen(object sender, DoWorkEventArgs e) { while (true) { if (listenWorker.CancellationPending) { e.Cancel = true; break; } TcpListener tcpListener = (TcpListener)e.Argument; try { for (int i = 0; i < Players.Count; i++) { if (!((TcpClient)Players[i].SocketEndpoint).Connected) { Players.RemoveAt(i--); } } // Create a TCP socket. // If you ran this server on the desktop, you could use // Socket socket = tcpListener.AcceptSocket() // for greater flexibility. TcpClient tcpClient = tcpListener.AcceptTcpClient(); if (Connections >= MaxConnections) { lock (writeMutex) { writeBuffer.Clear(); ObjectMapper.MapBytes(writeBuffer, "Max Players Reached On Server"); staticWriteStream.SetProtocolType(Networking.ProtocolType.TCP); WriteAndClose(tcpClient, staticWriteStream.Prepare( this, NetworkingStream.IdentifierType.Disconnect, 0, writeBuffer, noBehavior: true)); } return; } // TODO: Set the name string name = string.Empty; NetworkingPlayer player = new NetworkingPlayer(ServerPlayerCounter++, tcpClient.Client.RemoteEndPoint.ToString(), tcpClient, name); lock (Players) { Players.Add(player); } listenWorker.ReportProgress(0, player); } catch (NetworkException exception) { #if !BARE_METAL UnityEngine.Debug.LogException(exception); #endif Disconnect(); } } }
/// <summary> /// The final steps for preparing the NetworkingStream /// </summary> /// <param name="socket">The NetWorker socket to be used</param> /// <param name="identifierType">The type of Identifier it is going to prepare</param> /// <param name="behaviorNetworkId">NetworkedBehavior to use</param> /// <param name="extra">Extra parameters to prepare</param> /// <param name="receivers">Who shall be receiving this NetworkingStream</param> /// <param name="bufferedRPC">To know if this is a Buffered RPC</param> /// <param name="customidentifier">A custom Identifier to be passed through</param> /// <returns></returns> public NetworkingStream PrepareFinal(NetWorker socket, IdentifierType identifierType, ulong behaviorNetworkId, BMSByte extra = null, NetworkReceivers receivers = NetworkReceivers.All, bool bufferedRPC = false, uint customidentifier = 0, ulong senderId = 0) { lock (networkedObjectMutex) { if (senderId == 0) { senderId = socket.Me != null ? socket.Me.NetworkId : 0; } NetworkedBehaviorId = behaviorNetworkId; RealSenderId = senderId; Receivers = receivers; Customidentifier = customidentifier; BufferedRPC = Receivers == NetworkReceivers.AllBuffered || Receivers == NetworkReceivers.OthersBuffered; Bytes.Clear(); ObjectMapper.MapBytes(bytes, (int)ProtocolType); ObjectMapper.MapBytes(bytes, (int)receivers); ObjectMapper.MapBytes(bytes, socket.Uniqueidentifier); if (ProtocolType != Networking.ProtocolType.HTTP && ProtocolType != Networking.ProtocolType.QuickUDP && ProtocolType != Networking.ProtocolType.QuickTCP) { this.identifierType = identifierType; if (identifierType == IdentifierType.None) { Bytes.BlockCopy <byte>(((byte)identifier_NONE), 1); } else if (identifierType == IdentifierType.RPC) { Bytes.BlockCopy <byte>(((byte)identifier_RPC), 1); Bytes.BlockCopy <byte>(((byte)(bufferedRPC ? 1 : 0)), 1); } else if (identifierType == IdentifierType.Player) { Bytes.BlockCopy <byte>(((byte)identifier_PLAYER), 1); } else if (identifierType == IdentifierType.NetworkedBehavior) { Bytes.BlockCopy <byte>(((byte)identifier_NETWORKED_BEHAVIOR), 1); } else if (identifierType == IdentifierType.Disconnect) { Bytes.BlockCopy <byte>(((byte)identifier_DISCONNECT), 1); } else if (identifierType == IdentifierType.Custom) { Bytes.BlockCopy <byte>(((byte)identifier_CUSTOM), 1); } ObjectMapper.MapBytes(bytes, behaviorNetworkId); } if (identifierType == IdentifierType.Custom) { ObjectMapper.MapBytes(bytes, Customidentifier); } if (extra != null) { Bytes.BlockCopy(extra.byteArr, extra.StartIndex(), extra.Size); } if (!ReferenceEquals(NetworkingManager.Instance, null)) { ObjectMapper.MapBytes(Bytes, NetworkingManager.Instance.CurrentFrame); } else { ObjectMapper.MapBytes(Bytes, (byte)0); } if (ProtocolType == Networking.ProtocolType.TCP) { List <byte> head = new List <byte>(BitConverter.GetBytes(Bytes.Size + 1)); head.Add(0); Bytes.InsertRange(0, head.ToArray()); } Ready = true; return(this); } }