/** Sends an out-of-band datagram */
  public static void Netchan_OutOfBand(
      int net_socket, NetworkAddress adr, int length, byte data[]) {

    // write the packet header
    Buffer send = Buffer.allocate(Constants.MAX_MSGLEN);

    send.putInt(-1); // -1 sequence means out of band
    Buffers.Write(send, data, length);

    // send the datagram
    NET.SendPacket(net_socket, send.cursize, send.data, adr);
  }
  /**
   * tries to send an unreliable message to a connection, and handles the transmition /
   * retransmition of the reliable messages.
   *
   * <p>A 0 length will still generate a packet and deal with the reliable messages.
   */
  public static void Transmit(NetworkChannel chan, int length, byte data[]) {
    int send_reliable;
    int w1, w2;

    // check for message overflow
    if (chan.message.overflowed) {
      chan.fatal_error = true;
      Com.Printf(NET.AdrToString(chan.remote_address) + ":Outgoing message overflow\n");
      return;
    }

    send_reliable = chan.Netchan_NeedReliable() ? 1 : 0;

    if (chan.reliable_length == 0 && chan.message.cursize != 0) {
      System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, chan.message.cursize);
      chan.reliable_length = chan.message.cursize;
      chan.message.cursize = 0;
      chan.reliable_sequence ^= 1;
    }

    // write the packet header
    Buffer send = Buffer.wrap(send_buf).order(ByteOrder.LITTLE_ENDIAN);

    w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31);
    w2 = (chan.incoming_sequence & ~(1 << 31)) | (chan.incoming_reliable_sequence << 31);

    chan.outgoing_sequence++;
    chan.last_sent = (int) Globals.curtime;

    send.putInt(w1);
    send.putInt(w2);

    // send the qport if we are a client
    if (chan.sock == Constants.NS_CLIENT) send.WriteShort((int) consoleQport.value);

    // copy the reliable message to the packet first
    if (send_reliable != 0) {
      Buffers.Write(send, chan.reliable_buf, chan.reliable_length);
      chan.last_reliable_sequence = chan.outgoing_sequence;
    }

    // add the unreliable part if space is available
    if (send.maxsize - send.cursize >= length) Buffers.Write(send, data, length);
    else Com.Printf("Netchan_Transmit: dumped unreliable\n");

    // send the datagram
    NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address);

    if (showpackets.value != 0) {
      if (send_reliable != 0)
        Com.Printf(
            // "send %4i : s=%i reliable=%i ack=%i rack=%i\n"
            "send "
                + send.cursize
                + " : s="
                + (chan.outgoing_sequence - 1)
                + " reliable="
                + chan.reliable_sequence
                + " ack="
                + chan.incoming_sequence
                + " rack="
                + chan.incoming_reliable_sequence
                + "\n");
      else
        Com.Printf(
            // "send %4i : s=%i ack=%i rack=%i\n"
            "send "
                + send.cursize
                + " : s="
                + (chan.outgoing_sequence - 1)
                + " ack="
                + chan.incoming_sequence
                + " rack="
                + chan.incoming_reliable_sequence
                + "\n");
    }
  }
  /**
   * called when the current net_message is from remote_address modifies net_message so that it
   * points to the packet payload =================
   */
  public static boolean Process(NetworkChannel chan, Buffer msg) {
    int sequence, sequence_ack;
    int reliable_ack, reliable_message;
    int qport;

    // get sequence numbers
    msg.reset();
    sequence = msg.getInt();
    sequence_ack = msg.getInt();

    // read the qport if we are a server
    if (chan.sock == Constants.NS_SERVER) qport = msg.getShort();

    // achtung unsigned int
    reliable_message = sequence >>> 31;
    reliable_ack = sequence_ack >>> 31;

    sequence &= ~(1 << 31);
    sequence_ack &= ~(1 << 31);

    if (showpackets.value != 0) {
      if (reliable_message != 0)
        Com.Printf(
            // "recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
            "recv "
                + msg.cursize
                + " : s="
                + sequence
                + " reliable="
                + (chan.incoming_reliable_sequence ^ 1)
                + " ack="
                + sequence_ack
                + " rack="
                + reliable_ack
                + "\n");
      else
        Com.Printf(
            // "recv %4i : s=%i ack=%i rack=%i\n"
            "recv "
                + msg.cursize
                + " : s="
                + sequence
                + " ack="
                + sequence_ack
                + " rack="
                + reliable_ack
                + "\n");
    }

    //
    // discard stale or duplicated packets
    //
    if (sequence <= chan.incoming_sequence) {
      if (showdrop.value != 0)
        Com.Printf(
            NET.AdrToString(chan.remote_address)
                + ":Out of order packet "
                + sequence
                + " at "
                + chan.incoming_sequence
                + "\n");
      return false;
    }

    //
    // dropped packets don't keep the message from being used
    //
    chan.dropped = sequence - (chan.incoming_sequence + 1);
    if (chan.dropped > 0) {
      if (showdrop.value != 0)
        Com.Printf(
            NET.AdrToString(chan.remote_address)
                + ":Dropped "
                + chan.dropped
                + " packets at "
                + sequence
                + "\n");
    }

    //
    // if the current outgoing reliable message has been acknowledged
    // clear the buffer to make way for the next
    //
    if (reliable_ack == chan.reliable_sequence) chan.reliable_length = 0; // it has been received

    //
    // if this message contains a reliable message, bump
    // incoming_reliable_sequence
    //
    chan.incoming_sequence = sequence;
    chan.incoming_acknowledged = sequence_ack;
    chan.incoming_reliable_acknowledged = reliable_ack;
    if (reliable_message != 0) {
      chan.incoming_reliable_sequence ^= 1;
    }

    //
    // the message can now be read from the current message pointer
    //
    chan.last_received = (int) Globals.curtime;

    return true;
  }