ushort GetNextCallbackId()
        {
            ushort id;
            ushort start = nextCallbackId;

            do
            {
                id = nextCallbackId++;
                if (nextCallbackId == start)
                {
                    throw new NetException(
                              "Failed to allocate callback id, there are too many! How do you pull that off?!?");
                }
            } while (WaitingFunctions.ContainsKey(id));
            return(id);
        }
        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);
            }
        }