/// <summary> /// Send the specified packet. Marks the buffer as used. /// </summary> public void SendTcpPacket(Buffer buffer) { buffer.MarkAsUsed(); if (mSocket != null && mSocket.Connected) { buffer.BeginReading(); lock (mOut) { mOut.Enqueue(buffer); if (mOut.Count == 1) { try { // If it's the first packet, let's begin the send process mSocket.BeginSend(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, OnSend, buffer); } catch (System.Exception ex) { Error(ex.Message); Close(false); Release(); } } } } else { buffer.Recycle(); } }
/// <summary> /// Send the specified datagram. /// </summary> public void Send(Buffer buffer, IPEndPoint ip) { if (ip.Address.Equals(IPAddress.Broadcast)) { Broadcast(buffer, ip.Port); return; } buffer.MarkAsUsed(); if (mSocket != null) { buffer.BeginReading(); lock (mOut) { Datagram dg = new Datagram(); dg.buffer = buffer; dg.ip = ip; mOut.Enqueue(dg); if (mOut.Count == 1) { // If it's the first datagram, begin the sending process mSocket.BeginSendTo(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, ip, OnSend, null); } } } else { buffer.Recycle(); throw new InvalidOperationException("The socket is null. Did you forget to call UdpProtocol.Start()?"); } }
/// <summary> /// Create a new buffered remote function call. /// </summary> public void CreateRFC(uint inID, string funcName, Buffer buffer) { if (closed || buffer == null) { return; } buffer.MarkAsUsed(); for (int i = 0; i < rfcs.size; ++i) { RFC r = rfcs[i]; if (r.id == inID && r.funcName == funcName) { if (r.buffer != null) { r.buffer.Recycle(); } r.buffer = buffer; return; } } RFC rfc = new RFC(); rfc.id = inID; rfc.buffer = buffer; rfc.funcName = funcName; rfcs.Add(rfc); }
/// <summary> /// Send the outgoing buffer to all players in the specified channel. /// </summary> void SendToChannel(bool reliable, Channel channel, Buffer buffer) { mBuffer.MarkAsUsed(); if (mBuffer.size > 1024) { reliable = true; } for (int i = 0; i < channel.players.size; ++i) { TcpPlayer player = channel.players[i]; if (player.stage == TcpProtocol.Stage.Connected) { if (reliable || player.udpEndPoint == null || !mAllowUdp) { player.SendTcpPacket(mBuffer); } else { mUdp.Send(mBuffer, player.udpEndPoint); } } } mBuffer.Recycle(); }
/// <summary> /// Send the specified buffer to the entire LAN. /// </summary> public void Broadcast(Buffer buffer, int port) { if (buffer != null) { buffer.MarkAsUsed(); #if UNITY_WEBPLAYER || UNITY_FLASH #if UNITY_EDITOR UnityEngine.Debug.LogError("[TNet] Sending broadcasts doesn't work in the Unity Web Player or Flash"); #endif #else IPEndPoint endPoint = mMulticast ? mMulticastEndPoint : mBroadcastEndPoint; endPoint.Port = port; try { mSocket.SendTo(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, endPoint); } catch (System.Exception ex) { Error(null, ex.Message); } #endif buffer.Recycle(); } }
/// <summary> /// Send the specified datagram. /// </summary> public void Send(Buffer buffer, IPEndPoint ip) { #if !MODDING if (ip.Address.Equals(IPAddress.Broadcast)) { Broadcast(buffer, ip.Port); } else if (mSocket != null) { if (mSocket.AddressFamily != ip.AddressFamily) { #if UNITY_EDITOR UnityEngine.Debug.LogError("UDP socket " + name + " (" + mSocket.AddressFamily + ") and the desired address " + ip.Address + " (" + ip.AddressFamily + ") were started with different address families"); #else Tools.LogError("UDP socket " + name + " (" + mSocket.AddressFamily + ") and the desired address " + ip.Address + " (" + ip.AddressFamily + ") were started with different address families"); #endif return; } buffer.MarkAsUsed(); buffer.BeginReading(); lock (mOut) { Datagram dg = new Datagram(); dg.buffer = buffer; dg.ip = ip; mOut.Enqueue(dg); if (mOut.Count == 1) { try { // If it's the first datagram, begin the sending process mSocket.BeginSendTo(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, ip, OnSend, null); } catch (Exception ex) { Tools.LogError(ex.Message + "\n" + ex.StackTrace); buffer.Recycle(); } } } } else { Tools.LogError("The socket is null. Did you forget to call UdpProtocol.Start()?"); } #endif }
/// <summary> /// Send the specified datagram. /// </summary> public void Send(Buffer buffer, IPEndPoint ip) { if (ip.Address.Equals(IPAddress.Broadcast)) { Broadcast(buffer, ip.Port); } else if (mSocket != null) { buffer.MarkAsUsed(); buffer.BeginReading(); lock (mOut) { Datagram dg = new Datagram(); dg.buffer = buffer; dg.ip = ip; mOut.Enqueue(dg); if (mOut.Count == 1) { try { // If it's the first datagram, begin the sending process mSocket.BeginSendTo(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, ip, OnSend, null); } catch (Exception ex) { Tools.LogError(ex.Message + "\n" + ex.StackTrace); buffer.Recycle(); } } } } else { Tools.LogError("The socket is null. Did you forget to call UdpProtocol.Start()?"); } }
/// <summary> /// Create a new buffered remote function call. /// </summary> public void CreateRFC(uint inID, string funcName, Buffer buffer) { if (closed || buffer == null) return; buffer.MarkAsUsed(); for (int i = 0; i < rfcs.size; ++i) { RFC r = rfcs[i]; if (r.id == inID && r.funcName == funcName) { if (r.buffer != null) r.buffer.Recycle(); r.buffer = buffer; return; } } RFC rfc = new RFC(); rfc.id = inID; rfc.buffer = buffer; rfc.funcName = funcName; rfcs.Add(rfc); }
/// <summary> /// Send the specified packet. Marks the buffer as used. /// </summary> public void SendTcpPacket(Buffer buffer) { buffer.MarkAsUsed(); if (mSocket != null && mSocket.Connected) { buffer.BeginReading(); lock (mOut) { mOut.Enqueue(buffer); if (mOut.Count == 1) { // If it's the first packet, let's begin the send process mSocket.BeginSend(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, OnSend, buffer); } } } else { buffer.Recycle(); } }
/// <summary> /// Send the specified buffer to the entire LAN. /// </summary> public void Broadcast(Buffer buffer, int port) { if (buffer != null) { buffer.MarkAsUsed(); #if UNITY_WEBPLAYER || UNITY_FLASH #if UNITY_EDITOR UnityEngine.Debug.LogError("Sending broadcasts doesn't work in the Unity Web Player or Flash"); #endif #else mBroadcastIP.Port = port; try { mSocket.SendTo(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, mBroadcastIP); } catch (System.Exception ex) { Error(null, ex.Message); } #endif buffer.Recycle(); } }
/// <summary> /// Send the specified packet. Marks the buffer as used. /// </summary> public void SendTcpPacket(Buffer buffer) { buffer.MarkAsUsed(); BinaryReader reader = buffer.BeginReading(); #if DEBUG_PACKETS && !STANDALONE Packet packet = (Packet)buffer.PeekByte(4); if (packet != Packet.RequestPing && packet != Packet.ResponsePing) { UnityEngine.Debug.Log("Sending: " + packet + " to " + name + " (" + (buffer.size - 5).ToString("N0") + " bytes)"); } #endif if (mSocket != null && mSocket.Connected) { lock (mOut) { mOut.Enqueue(buffer); // If it's the first packet, let's begin the send process if (mOut.Count == 1) { try { #if !UNITY_WINRT mSocket.BeginSend(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, OnSend, buffer); #endif } catch (System.Exception ex) { mOut.Clear(); buffer.Recycle(); RespondWithError(ex); CloseNotThreadSafe(false); } } } return; } if (sendQueue != null) { if (buffer.position != 0) { // Offline mode sends packets individually and they should not be reused #if UNITY_EDITOR Debug.LogWarning("Packet's position is " + buffer.position + " instead of 0. Potentially sending the same packet more than once. Ignoring..."); #endif return; } // Skip the packet's size int size = reader.ReadInt32(); if (size == buffer.size) { // Note that after this the buffer can no longer be used again as its offset is +4 lock (sendQueue) sendQueue.Enqueue(buffer); return; } // Multi-part packet -- split it up into separate ones lock (sendQueue) { for (;;) { byte[] bytes = reader.ReadBytes(size); Buffer temp = Buffer.Create(); BinaryWriter writer = temp.BeginWriting(); writer.Write(size); writer.Write(bytes); temp.BeginReading(4); temp.EndWriting(); sendQueue.Enqueue(temp); if (buffer.size > 0) { size = reader.ReadInt32(); } else { break; } } } } buffer.Recycle(); }
/// <summary> /// Send the specified packet. Marks the buffer as used. /// </summary> public void SendTcpPacket(Buffer buffer, bool instant = false) { #if !MODDING buffer.MarkAsUsed(); var reader = buffer.BeginReading(); if (buffer.size == 0) { #if UNITY_EDITOR Debug.LogError("Trying to send a zero packet! " + buffer.position + " " + buffer.isWriting + " " + id); #endif buffer.Recycle(); return; } #if DEBUG_PACKETS && !STANDALONE var packet = (Packet)buffer.PeekByte(4); if (packet != Packet.RequestPing && packet != Packet.ResponsePing) { UnityEngine.Debug.Log("Sending: " + packet + " to " + name + " (" + (buffer.size - 5).ToString("N0") + " bytes)"); } #endif if (custom != null) { if (!custom.SendPacket(buffer)) { buffer.Recycle(); Disconnect(); } else { buffer.Recycle(); } return; } if (mSocket != null && mSocket.Connected) { lock (mOut) { #if UNITY_WINRT mSocket.Send(buffer.buffer, buffer.size, SocketFlags.None); #else if (instant) { try { var before = mSocket.NoDelay; if (!before) { mSocket.NoDelay = true; } mSocket.Send(buffer.buffer, buffer.position, buffer.size, SocketFlags.None); if (!before) { mSocket.NoDelay = false; } buffer.Recycle(); return; } catch { } } if (mSending) { // Simply add this packet to the outgoing queue mOut.Enqueue(buffer); } else { // If it's the first packet, let's begin the send process mSending = true; try { mSocket.BeginSend(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, OnSend, buffer); } catch (System.Exception ex) { mOut.Clear(); buffer.Recycle(); AddError(ex); CloseNotThreadSafe(false); mSending = false; } } #endif } return; } if (sendQueue != null) { if (buffer.position != 0) { // Offline mode sends packets individually and they should not be reused #if UNITY_EDITOR Debug.LogWarning("Packet's position is " + buffer.position + " instead of 0. Potentially sending the same packet more than once. Ignoring..."); #endif return; } // Skip the packet's size int size = reader.ReadInt32(); if (size == buffer.size) { lock (sendQueue) sendQueue.Enqueue(buffer); return; } // Multi-part packet -- split it up into separate ones lock (sendQueue) { for (;;) { var bytes = reader.ReadBytes(size); var temp = Buffer.Create(); var writer = temp.BeginWriting(); writer.Write(size); writer.Write(bytes); temp.BeginReading(4); sendQueue.Enqueue(temp); if (buffer.size > 0) { size = reader.ReadInt32(); } else { break; } } } } #endif buffer.Recycle(); }
/// <summary> /// Send the specified packet. Marks the buffer as used. /// </summary> public void SendTcpPacket(Buffer buffer) { buffer.MarkAsUsed(); if (mSocket != null && mSocket.Connected) { buffer.BeginReading(); lock (mOut) { mOut.Enqueue(buffer); if (mOut.Count == 1) { try { // If it's the first packet, let's begin the send process mSocket.BeginSend(buffer.buffer, buffer.position, buffer.size, SocketFlags.None, OnSend, buffer); } catch (System.Exception ex) { Error(ex.Message); Close(false); Release(); } } } } else buffer.Recycle(); }
/// <summary> /// Process a packet from the player. /// </summary> void ProcessChannelPacket(TcpPlayer player, Buffer buffer, BinaryReader reader, Packet request) { switch (request) { case Packet.RequestCreate: { // Create a new object ushort objectIndex = reader.ReadUInt16(); byte type = reader.ReadByte(); uint uniqueID = 0; if (type != 0) { uniqueID = --player.channel.objectCounter; // 1-32767 is reserved for existing scene objects. // 32768 - 16777215 is for dynamically created objects. if (uniqueID < 32768) { player.channel.objectCounter = 0xFFFFFF; uniqueID = 0xFFFFFF; } Channel.CreatedObject obj = new Channel.CreatedObject(); obj.playerID = player.id; obj.objectID = objectIndex; obj.uniqueID = uniqueID; obj.type = type; if (buffer.size > 0) { obj.buffer = buffer; buffer.MarkAsUsed(); } player.channel.created.Add(obj); } // Inform the channel BinaryWriter writer = BeginSend(Packet.ResponseCreate); writer.Write(player.id); writer.Write(objectIndex); writer.Write(uniqueID); if (buffer.size > 0) { writer.Write(buffer.buffer, buffer.position, buffer.size); } EndSend(true, player.channel, null); break; } case Packet.RequestDestroy: { // Destroy the specified network object uint uniqueID = reader.ReadUInt32(); // Remove this object if (player.channel.DestroyObject(uniqueID)) { // Inform all players in the channel that the object should be destroyed BinaryWriter writer = BeginSend(Packet.ResponseDestroy); writer.Write((ushort)1); writer.Write(uniqueID); EndSend(true, player.channel, null); } break; } case Packet.RequestLoadLevel: { // Change the currently loaded level if (player.channel.host == player) { player.channel.Reset(); player.channel.level = reader.ReadString(); BinaryWriter writer = BeginSend(Packet.ResponseLoadLevel); writer.Write(string.IsNullOrEmpty(player.channel.level) ? "" : player.channel.level); EndSend(true, player.channel, null); } break; } case Packet.RequestSetHost: { // Transfer the host state from one player to another if (player.channel.host == player) { TcpPlayer newHost = GetPlayer(reader.ReadInt32()); if (newHost != null && newHost.channel == player.channel) { SendSetHost(newHost); } } break; } case Packet.RequestLeaveChannel: { SendLeaveChannel(player, true); break; } case Packet.RequestCloseChannel: { player.channel.persistent = false; player.channel.closed = true; break; } case Packet.RequestSetPlayerLimit: { player.channel.playerLimit = reader.ReadUInt16(); break; } case Packet.RequestRemoveRFC: { uint id = reader.ReadUInt32(); string funcName = ((id & 0xFF) == 0) ? reader.ReadString() : null; player.channel.DeleteRFC(id, funcName); break; } case Packet.RequestSetChannelData: { player.channel.data = reader.ReadString(); BinaryWriter writer = BeginSend(Packet.ResponseSetChannelData); writer.Write(player.channel.data); EndSend(true, player.channel, null); break; } } }
/// <summary> /// Process a packet from the player. /// </summary> void ProcessChannelPacket(TcpPlayer player, Buffer buffer, BinaryReader reader, Packet request) { switch (request) { case Packet.RequestCreate: { // Create a new object ushort objectIndex = reader.ReadUInt16(); byte type = reader.ReadByte(); uint uniqueID = 0; if (type != 0) { uniqueID = --player.channel.objectCounter; // 1-32767 is reserved for existing scene objects. // 32768 - 16777215 is for dynamically created objects. if (uniqueID < 32768) { player.channel.objectCounter = 0xFFFFFF; uniqueID = 0xFFFFFF; } Channel.CreatedObject obj = new Channel.CreatedObject(); obj.playerID = player.id; obj.objectID = objectIndex; obj.uniqueID = uniqueID; obj.type = type; if (buffer.size > 0) { obj.buffer = buffer; buffer.MarkAsUsed(); } player.channel.created.Add(obj); } // Inform the channel BinaryWriter writer = BeginSend(Packet.ResponseCreate); writer.Write(player.id); writer.Write(objectIndex); writer.Write(uniqueID); if (buffer.size > 0) writer.Write(buffer.buffer, buffer.position, buffer.size); EndSend(true, player.channel, null); break; } case Packet.RequestDestroy: { // Destroy the specified network object uint uniqueID = reader.ReadUInt32(); // Remove this object if (player.channel.DestroyObject(uniqueID)) { // Inform all players in the channel that the object should be destroyed BinaryWriter writer = BeginSend(Packet.ResponseDestroy); writer.Write((ushort)1); writer.Write(uniqueID); EndSend(true, player.channel, null); } break; } case Packet.RequestLoadLevel: { // Change the currently loaded level if (player.channel.host == player) { player.channel.Reset(); player.channel.level = reader.ReadString(); BinaryWriter writer = BeginSend(Packet.ResponseLoadLevel); writer.Write(string.IsNullOrEmpty(player.channel.level) ? "" : player.channel.level); EndSend(true, player.channel, null); } break; } case Packet.RequestSetHost: { // Transfer the host state from one player to another if (player.channel.host == player) { TcpPlayer newHost = GetPlayer(reader.ReadInt32()); if (newHost != null && newHost.channel == player.channel) SendSetHost(newHost); } break; } case Packet.RequestLeaveChannel: { SendLeaveChannel(player, true); break; } case Packet.RequestCloseChannel: { player.channel.persistent = false; player.channel.closed = true; break; } case Packet.RequestSetPlayerLimit: { player.channel.playerLimit = reader.ReadUInt16(); break; } case Packet.RequestRemoveRFC: { uint id = reader.ReadUInt32(); string funcName = ((id & 0xFF) == 0) ? reader.ReadString() : null; player.channel.DeleteRFC(id, funcName); break; } case Packet.RequestSetChannelData: { player.channel.data = reader.ReadString(); BinaryWriter writer = BeginSend(Packet.ResponseSetChannelData); writer.Write(player.channel.data); EndSend(true, player.channel, null); break; } } }