void FireEvent(string eventName, NetConnection onConnection, RemoteFlag flags,
                       NetDeliveryMethod deliveryMethod, NetBuffer data, ushort numArgs)
        {
            // Create the event packet
            NetOutboundPacket firePacket = new NetOutboundPacket(deliveryMethod);

            firePacket.Type = NetPacketType.RemoteEvent;

            // Handle the flags
            firePacket.Encrypt = flags.HasFlag(RemoteFlag.Encrypt);
            if (flags.HasFlag(RemoteFlag.DontCompress))
            {
                firePacket.Compression = NetPacketCompression.None;
            }
            firePacket.SendImmediately = flags.HasFlag(RemoteFlag.SendImmediately);

            // Write the event header
            firePacket.Write((byte)Type);
            firePacket.Write(Id);
            firePacket.Write(eventName);
            firePacket.Write(numArgs);

            // Write the data for the event
            firePacket.WriteBytes(data.data, 0, data.Length);

            // Send the event packet
            onConnection.SendPacket(firePacket);
        }
        bool TrySendMTU(int size)
        {
            NetOutboundPacket msg = new NetOutboundPacket(NetDeliveryMethod.Unreliable);

            msg.Type            = NetPacketType.MTUTest;
            msg.SendImmediately = true;
            msg.WriteBytes(new byte[size]);

            // Have to set the header manually since this isn't technically a legit packet
            msg.SetId(messenger.AllocatePacketId());
            msg.PrependHeader();

            return(messenger.SendDataToSocket(msg.data, EndPoint, true));
        }
        NetOutboundPacket[] SplitPacketIntoPartials(NetOutboundPacket packet)
        {
            packet.position = 0;

            // Calculate the number of packets to split it into,
            // and each of their sizes
            int    numPackets       = (int)Math.Ceiling((double)(packet.Length) / (MTU - 12));
            int    newPacketSize    = MTU - 12;
            int    packetChunkIndex = 0;
            ushort id = nextPartialId++;

            NetOutboundPacket[] partialPackets = new NetOutboundPacket[numPackets];

            for (byte i = 0; i < numPackets; i++)
            {
                int packetSize = Math.Min(newPacketSize, packet.Length - packetChunkIndex);

                // Create the new partial
                NetOutboundPacket partial = packet.Clone(true);
                partial.isPartial   = true;
                partial.Encrypt     = false;
                partial.Compression = NetPacketCompression.None;
                partial.Clear(6 + packetSize);

                // Write the partial header
                partial.Write(id);
                partial.Write(i);
                partial.Write((byte)numPackets);
                partial.Write((ushort)packetSize);

                // Write the data allocated to this partial
                partial.WriteBytes(packet.ReadBytes(packetChunkIndex, packetSize));

                // Add it to the list of partials
                partialPackets[i] = partial;
                packetChunkIndex += packetSize;
            }

            if (NetLogger.LogPartials)
            {
                NetLogger.LogVerbose("[Partial] Split Packet into {0} parts; Size: {1}b, Original Size: {2}b",
                                     numPackets, newPacketSize, packet.Length);
            }
            return(partialPackets);
        }
        bool CallFunc(string functionName, NetConnection onConnection, RemoteFunctionCallback callback,
                      RemoteFlag flags, NetDeliveryMethod deliveryMethod, NetBuffer data, ushort numArgs)
        {
            // Allocate Id
            ushort callbackId = GetNextCallbackId();

            // Create the function packet
            NetOutboundPacket funcPacket = new NetOutboundPacket(deliveryMethod);

            funcPacket.Type = NetPacketType.RemoteFunction;

            // Handle the flags
            funcPacket.Encrypt = flags.HasFlag(RemoteFlag.Encrypt);
            if (flags.HasFlag(RemoteFlag.DontCompress))
            {
                funcPacket.Compression = NetPacketCompression.None;
            }
            funcPacket.SendImmediately = flags.HasFlag(RemoteFlag.SendImmediately);

            // Write the function header
            funcPacket.Write((byte)Type);
            funcPacket.Write(Id);
            funcPacket.Write(functionName);
            funcPacket.Write(callbackId);
            funcPacket.Write(numArgs);

            // Write the data for the function
            funcPacket.WriteBytes(data.data, 0, data.Length);

            // Add the waiting function for the return value callback
            if (WaitingFunctions.TryAdd(callbackId, callback))
            {
                // Send the event packet
                onConnection.SendPacket(funcPacket);
                return(true);
            }
            else
            {
                NetLogger.LogError("Failed to call function {0}, this function is already in the middle of being called!",
                                   functionName);
                return(false);
            }
        }
        void HandleRemoteFunction(NetInboundPacket packet, RemoteChannelBase channel)
        {
            // Attempt to locate the function
            string         funcName = packet.ReadString();
            RemoteFunction func;

            if (channel.Functions.TryGetValue(funcName, out func))
            {
                // Get the callback id
                ushort callbackId = packet.ReadUInt16();

                // Call the event
                ushort    numArgs     = packet.ReadUInt16();
                NetBuffer returnValue = func(packet.Sender, packet, numArgs);

                // Send the response
                NetOutboundPacket funcResponse = new NetOutboundPacket(NetDeliveryMethod.Reliable);
                funcResponse.Type    = NetPacketType.RemoteFunctionResponse;
                funcResponse.Encrypt = packet.isEncrypted;

                // Write the normal remote header
                funcResponse.Write((byte)channel.Type);
                funcResponse.Write(channel.Id);
                funcResponse.Write(funcName);
                funcResponse.Write(callbackId);

                // Write the return value
                funcResponse.WriteBytes(returnValue.data, 0, returnValue.Length);

                // Send the response
                packet.Sender.SendPacket(funcResponse);
            }
            else
            {
                NetLogger.LogError("Remote Function \"{0}\" was invoked on a {1} channel with the id {2}, but it doesn't exist!",
                                   funcName, channel.Type, channel.Id);
            }
        }
        void SendChunk()
        {
            lastChunkSend = NetTime.Now;

            // If theres nothing to send, don't bother!
            if (packetChunkQueue.Count == 0)
            {
                return;
            }

            // Safely grab the packets
            NetOutboundPacket[] packetsToChunk = packetChunkQueue.ToArrayAndClear();
            currentChunkSize = 0; // Reset size
            if (packetsToChunk == null)
            {
                NetLogger.LogError("Failed to convert packetChunkQueue to an array!");
                // Cannot continue
                return;
            }

            // If there is only one packet to send,
            // then don't create a chunk, just send it to
            // save cpu and bandwidth.
            if (packetsToChunk.Length == 1)
            {
                TryMarkReliablePacket(packetsToChunk[0]);
                SendPacketToSocket(packetsToChunk[0]);
            }
            else // Otherwise send it as a chunk
            {
                // Log the sends
                packetsSentInLastSecond += packetsToChunk.Length;
                Stats.PacketsSent       += packetsToChunk.Length;

                // Create the packet
                NetOutboundPacket chunkPacket = new NetOutboundPacket(NetDeliveryMethod.Unreliable,
                                                                      2 + (packetsToChunk.Length * 2) + currentChunkSize);
                chunkPacket.isChunked = true;

                // Write the header, the number of chunked packets
                chunkPacket.Write((ushort)packetsToChunk.Length);

                // Write each packet
                for (int i = 0; i < packetsToChunk.Length; i++)
                {
                    NetOutboundPacket packet = packetsToChunk[i];
                    // If it is reliable we need to mark it as a new send
                    TryMarkReliablePacket(packet);

                    // Write packet
                    chunkPacket.Write((ushort)packet.Length);              // Size
                    chunkPacket.WriteBytes(packet.data, 0, packet.Length); // Packet Data
                }

                // Setup header
                //SetupOutboundPacket(chunkPacket);
                WriteOutboundPacketHeader(chunkPacket);

                // And Send
                SendPacketToSocket(chunkPacket);
            }
        }