Class NeonClient

java.lang.Object
com.quietterminal.neon.core.AbstractLifecycle
com.quietterminal.neon.client.NeonClient
All Implemented Interfaces:
Lifecycle, AutoCloseable

public final class NeonClient extends AbstractLifecycle implements AutoCloseable
Relay-connected UDP client for the Neon multiplayer protocol.

A NeonClient connects to a session hosted by a NeonHost through a NeonRelay. The connection handshake is synchronous; ongoing packet processing is driven either by calling run() in a dedicated thread or by periodically calling processPackets() from the game loop.

Typical usage:

NeonClient client = new NeonClient("player1", NeonConfig.defaults());
client.setSessionConfigCallback(cfg -> System.out.println("tick rate: " + cfg.tickRate()));
if (client.connect(sessionId, "relay.example.com:9000")) {
    Thread.ofVirtual().start(client::run);
}
  • Constructor Details

    • NeonClient

      public NeonClient(String name, NeonConfig config) throws IOException
      Creates a new client with the given display name and configuration. Binds a local UDP socket on an OS-assigned port.
      Parameters:
      name - player display name sent to the host during connection
      config - protocol configuration
      Throws:
      IOException - if the local socket cannot be bound
  • Method Details

    • connect

      public boolean connect(int sessionId, String relayAddress)
      Connects to a session through a relay. Blocks until the relay accepts or denies the connection, or until the connection timeout elapses.
      Parameters:
      sessionId - the session to join
      relayAddress - relay address in "host:port" format
      Returns:
      true if the connection was accepted; false if denied or timed out
    • doStart

      protected void doStart() throws Exception
      Specified by:
      doStart in class AbstractLifecycle
      Throws:
      Exception
    • doStop

      protected void doStop() throws Exception
      Specified by:
      doStop in class AbstractLifecycle
      Throws:
      Exception
    • run

      public void run()
      Drives the client processing loop until AbstractLifecycle.stop() is called or an unrecoverable IO error occurs. Drains inbound packets and fires auto-pings on each iteration. Intended to run in a dedicated virtual thread:
      Thread.ofVirtual().start(client::run); 
    • processPackets

      public void processPackets() throws IOException
      Drains all currently buffered inbound packets and fires the relevant callbacks. Use this instead of run() when integrating with an external game loop.
      Throws:
      IOException - if a socket error occurs while receiving
    • reconnect

      public boolean reconnect()
      Attempts to rejoin the last session using the stored session token. Uses the max reconnect attempts from configuration with exponential backoff. Creates a new socket if the existing one is closed.
      Returns:
      true if reconnection succeeded
    • reconnect

      public boolean reconnect(int maxAttempts)
      Attempts to rejoin the last session using the stored session token, retrying up to maxAttempts times with exponential backoff.
      Parameters:
      maxAttempts - maximum number of reconnect attempts
      Returns:
      true if reconnection succeeded
    • sendPacket

      public void sendPacket(byte[] payload, byte packetType, byte destId) throws IOException
      Sends a game-specific payload through the relay.
      Parameters:
      payload - raw payload bytes
      packetType - application-defined packet type byte registered via GamePacketRegistry
      destId - destination client ID, or 0 to broadcast to all session peers
      Throws:
      IOException - if the send fails
    • setPongCallback

      public void setPongCallback(Consumer<PacketPayload.Pong> cb)
      Callback fired when a PacketPayload.Pong is received in response to an auto-ping.
    • setSessionConfigCallback

      public void setSessionConfigCallback(Consumer<PacketPayload.SessionConfig> cb)
      Callback fired when the host delivers a PacketPayload.SessionConfig. The client ACKs automatically.
    • setPacketTypeRegistryCallback

      public void setPacketTypeRegistryCallback(Consumer<PacketPayload.PacketTypeRegistry> cb)
      Callback fired when the host broadcasts its PacketPayload.PacketTypeRegistry.
    • setUnhandledPacketCallback

      public void setUnhandledPacketCallback(BiConsumer<Byte,Byte> cb)
      Callback fired for packets whose type is not handled internally. Arguments are (packetType, senderId).
    • setDisconnectCallback

      public void setDisconnectCallback(Consumer<Byte> cb)
      Callback fired when a PacketPayload.DisconnectNotice is received for another peer. The argument is the disconnecting client's ID.
    • getClientId

      public Byte getClientId()
      Returns the client ID assigned by the host, or null if not yet connected.
    • getLocalAddress

      public InetSocketAddress getLocalAddress() throws IOException
      Returns the local address of the underlying UDP socket.
      Throws:
      IOException
    • close

      public void close() throws Exception
      Specified by:
      close in interface AutoCloseable
      Throws:
      Exception