### Configure RakNet Server Settings Source: https://context7.com/cloudburstmc/network/llms.txt Set server-specific options for RakNet, including GUID, connection limits, supported protocols, MTU, ping handling, packet limits, and cookie settings. Ensure the cookie secret is exactly 16 bytes. An advertisement ByteBuf can also be set. ```java import org.cloudburstmc.netty.channel.raknet.config.RakServerChannelConfig; import org.cloudburstmc.netty.channel.raknet.config.RakServerCookieMode; RakServerChannelConfig cfg = rakServerChannel.config(); cfg.setGuid(ThreadLocalRandom.current().nextLong()); cfg.setMaxConnections(1000); cfg.setSupportedProtocols(new int[]{10, 11}); cfg.setMaxMtu(1400); cfg.setMinMtu(576); cfg.setHandlePing(true); // Forward RakPing events to pipeline instead of auto-replying cfg.setPacketLimit(120); // Per-IP rate limit cfg.setGlobalPacketLimit(100_000); cfg.setCookieMode(RakServerCookieMode.ACTIVE); // ACTIVE | OFFLOADED | OFFLOADED_PSK | OFF | INVALID cfg.setCookieSecret(secretKey16Bytes); // Must be exactly 16 bytes ByteBuf advertisement = Unpooled.copiedBuffer("MCPE;Server;748;1.21;5;100;id;world;Survival;1;19132;19133;".getBytes()); cfg.setAdvertisement(advertisement); // Read back long guid = cfg.getGuid(); int maxConn = cfg.getMaxConnections(); RakServerCookieMode mode = cfg.getCookieMode(); ``` -------------------------------- ### Handle RakNet Ping Events Source: https://context7.com/cloudburstmc/network/llms.txt When `RAK_HANDLE_PING` is enabled, handle `RakPing` user events in the pipeline to send custom `RakPong` responses. The handler must construct and write the `RakPong` to the channel, echoing the original ping time and including server GUID and advertisement data. ```java import org.cloudburstmc.netty.channel.raknet.RakPing; import org.cloudburstmc.netty.channel.raknet.RakPong; // Add to RakServerChannel pipeline (server bootstrap handler) serverBootstrap.handler(new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (msg instanceof RakPing) { RakPing ping = (RakPing) msg; // Build dynamic MOTD String motd = "MCPE;Server;748;1.21:" + getOnlinePlayers() + ";100;123456789;World;Survival;1;19132;19133;"; ByteBuf pongData = ctx.alloc().buffer().writeBytes(motd.getBytes()); long serverGuid = ((RakServerChannelConfig) ctx.channel().config()).getGuid(); RakPong pong = ping.reply(serverGuid, pongData); // constructs RakPong ctx.writeAndFlush(pong); } else { ctx.fireChannelRead(msg); } } }); // RakPong accessors // pong.getPingTime() — original timestamp echoed back // pong.getGuid() — server GUID // pong.getPongData() — advertisement ByteBuf (reference-counted) // pong.getSender() — InetSocketAddress of the pinging client ``` -------------------------------- ### Access and Mutate RakChannelConfig Source: https://context7.com/cloudburstmc/network/llms.txt Obtain `RakChannelConfig` from a channel to get and set session-level properties like GUID, MTU, timeouts, and flush behavior. ```java import org.cloudburstmc.netty.channel.raknet.config.RakChannelConfig; // Obtained from a RakChildChannel inside ChannelInitializer or handler RakChannelConfig cfg = ((RakChannel) ctx.channel()).config(); long guid = cfg.getGuid(); // Remote client GUID int mtu = cfg.getMtu(); // Negotiated MTU int proto = cfg.getProtocolVersion(); // RakNet protocol version int channels = cfg.getOrderingChannels();// Ordering channel count long timeout = cfg.getSessionTimeout(); // Inactivity timeout ms boolean autoFlush = cfg.isAutoFlush(); int flushInterval = cfg.getFlushInterval(); int maxQueued = cfg.getMaxQueuedBytes(); // Mutate at runtime cfg.setSessionTimeout(30_000L); cfg.setAutoFlush(false); // Disable auto-flush; call channel.flush() manually cfg.setFlushInterval(5); // 5 ms flush interval when auto-flush is enabled cfg.setMaxQueuedBytes(4 * 1024 * 1024); // Disconnect if outbound queue > 4 MB ``` -------------------------------- ### Configure and Bind RakNet Server Source: https://context7.com/cloudburstmc/network/llms.txt Sets up a Netty ServerBootstrap for RakNet, configuring server-level and child-level options, and binds it to a specific UDP port. Use this to initialize a RakNet server instance. ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; import org.cloudburstmc.netty.channel.raknet.*; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; import org.cloudburstmc.netty.channel.raknet.config.RakServerCookieMode; import org.cloudburstmc.netty.channel.raknet.packet.RakMessage; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; NioEventLoopGroup bossGroup = new NioEventLoopGroup(1); NioEventLoopGroup workerGroup = new NioEventLoopGroup(); byte[] advertisement = "MCPE;My Server;748;1.21.0;0;20;123456789;Bedrock level;Survival;1;19132;19133;".getBytes(); ServerBootstrap bootstrap = new ServerBootstrap() .group(bossGroup, workerGroup) .channelFactory(RakChannelFactory.server(NioDatagramChannel.class)) // Server-level options .option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()) .option(RakChannelOption.RAK_ADVERTISEMENT, Unpooled.wrappedBuffer(advertisement)) .option(RakChannelOption.RAK_MAX_CONNECTIONS, 200) .option(RakChannelOption.RAK_SUPPORTED_PROTOCOLS, new int[]{11}) .option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.ACTIVE) .option(RakChannelOption.RAK_PACKET_LIMIT, 120) .option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, 100_000) // Per-child options (applied to each RakChildChannel) .childOption(RakChannelOption.RAK_SESSION_TIMEOUT, 10_000L) .childOption(RakChannelOption.RAK_AUTO_FLUSH, true) .childOption(RakChannelOption.RAK_FLUSH_INTERVAL, 10) .childHandler(new ChannelInitializer() { @Override protected void initChannel(RakChildChannel ch) { ch.pipeline().addLast(new SimpleChannelInboundHandler() { @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { // received decrypted application payload from client System.out.println("Received " + msg.readableBytes() + " bytes from " + ctx.channel().remoteAddress()); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { if (evt instanceof RakDisconnectReason) { System.out.println("Disconnected: " + evt); } } }); } }); Channel serverChannel = bootstrap.bind(new InetSocketAddress(19132)).sync().channel(); // Block an abusive address for 60 seconds RakServerChannel rak = (RakServerChannel) serverChannel; rak.tryBlockAddress(InetAddress.getByName("1.2.3.4"), 60, TimeUnit.SECONDS); // Lookup an active child channel RakChildChannel child = rak.getChildChannel(new InetSocketAddress("1.2.3.4", 12345)); serverChannel.closeFuture().sync(); ``` -------------------------------- ### Configure RakNet Client Bootstrap Options Source: https://context7.com/cloudburstmc/network/llms.txt Set client-level RakNet options using `Bootstrap.option()`. These options configure connection parameters, MTU probing, and compatibility. ```java clientBootstrap .option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()) .option(RakChannelOption.RAK_PROTOCOL_VERSION, 11) .option(RakChannelOption.RAK_CONNECT_TIMEOUT, 10_000L) .option(RakChannelOption.RAK_MTU, 1400) // Initial MTU hint .option(RakChannelOption.RAK_MTU_SIZES, new Integer[]{1400, 1200, 576}) // MTU probing sequence .option(RakChannelOption.RAK_COMPATIBILITY_MODE, false) // true for vanilla client behaviour .option(RakChannelOption.RAK_IP_DONT_FRAGMENT, false) .option(RakChannelOption.RAK_CLIENT_INTERNAL_ADDRESSES, 10) .option(RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS, 1000); ``` -------------------------------- ### Configure RakNet Server Bootstrap Options Source: https://context7.com/cloudburstmc/network/llms.txt Set server-level RakNet options using `Bootstrap.option()`. These options control server behavior, advertisement, and connection limits. ```java import io.netty.buffer.Unpooled; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; import org.cloudburstmc.netty.channel.raknet.config.RakServerCookieMode; // --- Server bootstrap options --- serverBootstrap .option(RakChannelOption.RAK_GUID, 123456789L) // Unique server GUID .option(RakChannelOption.RAK_ADVERTISEMENT, Unpooled.copiedBuffer("MCPE;Server;748;1.21;0;100;12345678;world;Survival;1;19132;19133;".getBytes())) .option(RakChannelOption.RAK_MAX_CONNECTIONS, 500) // Max simultaneous connections .option(RakChannelOption.RAK_SUPPORTED_PROTOCOLS, new int[]{11}) // Allowed RakNet versions .option(RakChannelOption.RAK_MAX_MTU, 1400) // Negotiated MTU upper bound .option(RakChannelOption.RAK_MIN_MTU, 576) // Negotiated MTU lower bound .option(RakChannelOption.RAK_PACKET_LIMIT, 120) // Max packets/address/tick (10ms) .option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, 100_000) // Max packets across all addresses/tick .option(RakChannelOption.RAK_HANDLE_PING, false) // false = auto-reply with advertisement .option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.ACTIVE) // Anti-spoofing .option(RakChannelOption.RAK_SERVER_COOKIE_SECRET, new byte[16]); // 16-byte cookie secret ``` -------------------------------- ### RakChannelOption - Client Bootstrap Options Source: https://context7.com/cloudburstmc/network/llms.txt Configures client-level RakNet options using Bootstrap.option(). These options affect how the client connects and behaves. ```APIDOC ## `RakChannelOption` — Client Bootstrap Options ### Description Configures client-level RakNet options using `Bootstrap.option()`. These options affect how the client connects and behaves. ### Method `Bootstrap.option(RakChannelOption., value)` ### Parameters - **RAK_GUID** (Long) - Unique client GUID. - **RAK_PROTOCOL_VERSION** (Integer) - The RakNet protocol version to use. - **RAK_CONNECT_TIMEOUT** (Long) - Connection timeout in milliseconds. - **RAK_MTU** (Integer) - Initial MTU hint. - **RAK_MTU_SIZES** (Integer[]) - Array of MTU sizes for probing sequence. - **RAK_COMPATIBILITY_MODE** (Boolean) - If true, enables vanilla client behavior. - **RAK_IP_DONT_FRAGMENT** (Boolean) - Controls IP fragmentation. - **RAK_CLIENT_INTERNAL_ADDRESSES** (Integer) - Number of internal addresses to use. - **RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS** (Integer) - Time in milliseconds between connection attempt retries. ### Request Example ```java clientBootstrap .option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()) .option(RakChannelOption.RAK_PROTOCOL_VERSION, 11) .option(RakChannelOption.RAK_CONNECT_TIMEOUT, 10_000L) .option(RakChannelOption.RAK_MTU, 1400) .option(RakChannelOption.RAK_MTU_SIZES, new Integer[]{1400, 1200, 576}) .option(RakChannelOption.RAK_COMPATIBILITY_MODE, false) .option(RakChannelOption.RAK_IP_DONT_FRAGMENT, false) .option(RakChannelOption.RAK_CLIENT_INTERNAL_ADDRESSES, 10) .option(RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS, 1000); ``` ``` -------------------------------- ### RakChannelOption - Server Bootstrap Options Source: https://context7.com/cloudburstmc/network/llms.txt Configures server-level RakNet options using Bootstrap.option(). These options affect the server's behavior and how it handles incoming connections. ```APIDOC ## `RakChannelOption` — Server Bootstrap Options ### Description Configures server-level RakNet options using `Bootstrap.option()`. These options affect the server's behavior and how it handles incoming connections. ### Method `Bootstrap.option(RakChannelOption., value)` ### Parameters - **RAK_GUID** (Long) - Unique server GUID. - **RAK_ADVERTISEMENT** (ByteBuf) - MOTD / ping response data. - **RAK_MAX_CONNECTIONS** (Integer) - Maximum simultaneous connections allowed. - **RAK_SUPPORTED_PROTOCOLS** (int[]) - Array of supported RakNet protocol versions. - **RAK_MAX_MTU** (Integer) - Negotiated MTU upper bound. - **RAK_MIN_MTU** (Integer) - Negotiated MTU lower bound. - **RAK_PACKET_LIMIT** (Integer) - Maximum packets allowed per address per tick (10ms). - **RAK_GLOBAL_PACKET_LIMIT** (Integer) - Maximum packets allowed across all addresses per tick. - **RAK_HANDLE_PING** (Boolean) - If false, the server auto-replies with the advertisement. - **RAK_SERVER_COOKIE_MODE** (RakServerCookieMode) - Configures the anti-spoofing cookie mode. - **RAK_SERVER_COOKIE_SECRET** (byte[]) - A 16-byte secret for cookie generation. ### Request Example ```java serverBootstrap .option(RakChannelOption.RAK_GUID, 123456789L) .option(RakChannelOption.RAK_ADVERTISEMENT, Unpooled.copiedBuffer("MCPE;Server;748;1.21;0;100;12345678;world;Survival;1;19132;19133;".getBytes())) .option(RakChannelOption.RAK_MAX_CONNECTIONS, 500) .option(RakChannelOption.RAK_SUPPORTED_PROTOCOLS, new int[]{11}) .option(RakChannelOption.RAK_MAX_MTU, 1400) .option(RakChannelOption.RAK_MIN_MTU, 576) .option(RakChannelOption.RAK_PACKET_LIMIT, 120) .option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, 100_000) .option(RakChannelOption.RAK_HANDLE_PING, false) .option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.ACTIVE) .option(RakChannelOption.RAK_SERVER_COOKIE_SECRET, new byte[16]); ``` ``` -------------------------------- ### Initialize RakNet Server and Client Channels Source: https://context7.com/cloudburstmc/network/llms.txt Use `RakChannelFactory` with Netty's `ServerBootstrap` or `Bootstrap` to create RakNet channels. Customize the underlying datagram channel or child channels as needed. ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; import org.cloudburstmc.netty.channel.raknet.RakChannelFactory; import org.cloudburstmc.netty.channel.raknet.RakServerChannel; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; NioEventLoopGroup group = new NioEventLoopGroup(); // Server factory — basic ChannelFactory serverFactory = RakChannelFactory.server(NioDatagramChannel.class); // Server factory — with parent DatagramChannel customisation and per-child customisation ChannelFactory serverFactoryAdvanced = RakChannelFactory.server( NioDatagramChannel.class, datagramChannel -> datagramChannel.config().setReceiveBufferSize(1 << 24), // 16 MB recv buffer rakChild -> rakChild.config().setOption(RakChannelOption.RAK_SESSION_TIMEOUT, 30_000L) ); // Client factory ChannelFactory clientFactory = RakChannelFactory.client(NioDatagramChannel.class); ``` -------------------------------- ### Configure RakNet Child/Session Options Source: https://context7.com/cloudburstmc/network/llms.txt Set per-channel RakNet options using `Bootstrap.childOption()`. These options control individual session behavior like timeouts and queue limits. ```java serverBootstrap .childOption(RakChannelOption.RAK_SESSION_TIMEOUT, 10_000L) // Inactivity timeout (ms) .childOption(RakChannelOption.RAK_AUTO_FLUSH, true) // Auto-flush every tick .childOption(RakChannelOption.RAK_FLUSH_INTERVAL, 10) // Flush interval (ms) .childOption(RakChannelOption.RAK_ORDERING_CHANNELS, 16) // Ordering channel count (1–256) .childOption(RakChannelOption.RAK_MAX_QUEUED_BYTES, 8 * 1024 * 1024); // 8 MB queue limit ``` -------------------------------- ### Construct RakMessage Source: https://context7.com/cloudburstmc/network/llms.txt Demonstrates creating RakMessages with different reliability, priority, and ordering channel settings. Also shows how to inspect received RakMessages. ```java import io.netty.buffer.ByteBuf; import org.cloudburstmc.netty.channel.raknet.RakPriority; import org.cloudburstmc.netty.channel.raknet.RakReliability; import org.cloudburstmc.netty.channel.raknet.packet.RakMessage; // Reliable ordered on ordering channel 0 (default) ByteBuf gamePacket = ctx.alloc().buffer(32); gamePacket.writeBytes(new byte[]{0x01, 0x02, 0x03}); ctx.writeAndFlush(new RakMessage(gamePacket, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL, 0)); // Unreliable immediate — fire-and-forget, bypasses the send queue ByteBuf ping = ctx.alloc().buffer(1); ping.writeByte(0x00); ctx.writeAndFlush(new RakMessage(ping, RakReliability.UNRELIABLE, RakPriority.IMMEDIATE)); // Reliable ordered on a separate ordering channel (e.g., channel 1 for audio) ByteBuf audio = ctx.alloc().buffer(64).writeBytes(audioData); ctx.writeAndFlush(new RakMessage(audio, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL, 1)); // Inspect a received RakMessage (if your handler receives RakMessage instead of ByteBuf) // RakMessage msg = ...; // System.out.println(msg.reliability()); // RELIABLE_ORDERED // System.out.println(msg.priority()); // NORMAL // System.out.println(msg.channel()); // 0 // ByteBuf content = msg.content(); ``` -------------------------------- ### RakChannelOption - Child/Session Options Source: https://context7.com/cloudburstmc/network/llms.txt Configures per-channel RakNet options using Bootstrap.childOption(). These options are applied to each individual client session. ```APIDOC ## `RakChannelOption` — Child/Session Options ### Description Configures per-channel RakNet options using `Bootstrap.childOption()`. These options are applied to each individual client session. ### Method `Bootstrap.childOption(RakChannelOption., value)` ### Parameters - **RAK_SESSION_TIMEOUT** (Long) - Inactivity timeout in milliseconds. - **RAK_AUTO_FLUSH** (Boolean) - If true, automatically flushes data every tick. - **RAK_FLUSH_INTERVAL** (Integer) - Flush interval in milliseconds when auto-flush is enabled. - **RAK_ORDERING_CHANNELS** (Integer) - Number of ordering channels (1–256). - **RAK_MAX_QUEUED_BYTES** (Integer) - Maximum outbound queue size in bytes (e.g., 8 * 1024 * 1024 for 8 MB). ### Request Example ```java serverBootstrap .childOption(RakChannelOption.RAK_SESSION_TIMEOUT, 10_000L) .childOption(RakChannelOption.RAK_AUTO_FLUSH, true) .childOption(RakChannelOption.RAK_FLUSH_INTERVAL, 10) .childOption(RakChannelOption.RAK_ORDERING_CHANNELS, 16) .childOption(RakChannelOption.RAK_MAX_QUEUED_BYTES, 8 * 1024 * 1024); ``` ``` -------------------------------- ### Add netty-transport-raknet Dependency (Maven) Source: https://context7.com/cloudburstmc/network/llms.txt Add the library to your project's pom.xml file. Include the snapshot repository if needed. ```xml org.cloudburstmc.netty netty-transport-raknet 1.0.0.CR3-SNAPSHOT opencollab-snapshots https://repo.opencollab.dev/maven-snapshots/ ``` -------------------------------- ### Add netty-transport-raknet Dependency (Gradle) Source: https://context7.com/cloudburstmc/network/llms.txt Add the library to your project's build.gradle.kts file. Use the snapshot repository for development versions. ```kotlin // build.gradle.kts repositories { mavenCentral() // For snapshots: maven("https://repo.opencollab.dev/maven-snapshots/") } dependencies { implementation("org.cloudburstmc.netty:netty-transport-raknet:1.0.0.CR3-SNAPSHOT") } ``` -------------------------------- ### Connect to RakNet Server Source: https://context7.com/cloudburstmc/network/llms.txt Establishes a RakNet client connection, handling the handshake and sending initial data. Handles disconnections via user events. ```java import io.netty.bootstrap.Bootstrap; import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioDatagramChannel; import org.cloudburstmc.netty.channel.raknet.*; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; import org.cloudburstmc.netty.channel.raknet.packet.RakMessage; import java.net.InetSocketAddress; import java.util.concurrent.ThreadLocalRandom; NioEventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap() .group(group) .channelFactory(RakChannelFactory.client(NioDatagramChannel.class)) .option(RakChannelOption.RAK_GUID, ThreadLocalRandom.current().nextLong()) .option(RakChannelOption.RAK_PROTOCOL_VERSION, 11) .option(RakChannelOption.RAK_CONNECT_TIMEOUT, 10_000L) .option(RakChannelOption.RAK_SESSION_TIMEOUT, 10_000L) .option(RakChannelOption.RAK_AUTO_FLUSH, true) .handler(new ChannelInitializer() { @Override protected void initChannel(RakClientChannel ch) { ch.pipeline().addLast(new SimpleChannelInboundHandler() { @Override public void channelActive(ChannelHandlerContext ctx) { System.out.println("Connected to " + ctx.channel().remoteAddress()); // Send a reliable ordered message on channel 0 ByteBuf payload = ctx.alloc().buffer().writeBytes("Hello RakNet".getBytes()); ctx.writeAndFlush(new RakMessage(payload, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL, 0)); } @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) { byte[] bytes = new byte[msg.readableBytes()]; msg.readBytes(bytes); System.out.println("Server said: " + new String(bytes)); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { if (evt instanceof RakDisconnectReason) { System.err.println("Disconnected: " + evt); // e.g. TIMED_OUT } } }); } }); Channel ch = bootstrap.connect(new InetSocketAddress("play.example.com", 19132)).sync().channel(); ch.closeFuture().sync(); ``` -------------------------------- ### Add Snapshot Repository to Gradle (Kotlin DSL) Source: https://github.com/cloudburstmc/network/blob/develop/README.md Configure your Gradle build to include the snapshot repository for fetching development versions. ```kotlin repositories { maven("https://repo.opencollab.dev/maven-snapshots/") } ``` -------------------------------- ### Implement RakChannelMetrics and RakServerMetrics Source: https://context7.com/cloudburstmc/network/llms.txt Implement RakChannelMetrics and RakServerMetrics interfaces to hook into internal protocol counters. Register them via RakChannelOption.RAK_METRICS (session) or RakChannelOption.RAK_SERVER_METRICS (server). These interfaces provide default methods that can be overridden to report metrics. ```java import org.cloudburstmc.netty.channel.raknet.config.RakChannelMetrics; import org.cloudburstmc.netty.channel.raknet.config.RakServerMetrics; import org.cloudburstmc.netty.channel.raknet.RakState; import io.micrometer.core.instrument.MeterRegistry; // Session-level metrics (per RakChildChannel / RakClientChannel) RakChannelMetrics sessionMetrics = new RakChannelMetrics() { @Override public void bytesIn(int count) { meterRegistry.counter("rak.bytes.in").increment(count); } @Override public void bytesOut(int count) { meterRegistry.counter("rak.bytes.out").increment(count); } @Override public void rakDatagramsIn(int count) { meterRegistry.counter("rak.datagrams.in").increment(count); } @Override public void rakDatagramsOut(int count) { meterRegistry.counter("rak.datagrams.out").increment(count); } @Override public void ackOut(int count) { meterRegistry.counter("rak.ack.out").increment(count); } @Override public void nackOut(int count) { meterRegistry.counter("rak.nack.out").increment(count); } @Override public void rakStaleDatagrams(int count) { meterRegistry.counter("rak.stale").increment(count); } @Override public void queuedPacketBytes(int count) { meterRegistry.gauge("rak.queue.bytes", count); } @Override public void stateChange(RakState state) { System.out.println("State → " + state); } }; // Server-level metrics (across all sessions) RakServerMetrics serverMetrics = new RakServerMetrics() { @Override public void channelOpen(InetSocketAddress address) { System.out.println("+ " + address); } @Override public void channelClose(InetSocketAddress address) { System.out.println("- " + address); } @Override public void unconnectedPing(InetSocketAddress addr) { pingsCounter.increment(); } @Override public void addressBlocked(InetAddress address) { System.out.println("Blocked: " + address); } @Override public void invalidCookie(InetSocketAddress address) { System.out.println("Bad cookie: " + address); } }; serverBootstrap .option(RakChannelOption.RAK_SERVER_METRICS, serverMetrics) .childOption(RakChannelOption.RAK_METRICS, sessionMetrics); ``` -------------------------------- ### Add Snapshot Repository to Gradle (Groovy) Source: https://github.com/cloudburstmc/network/blob/develop/README.md Configure your Gradle build to include the snapshot repository for fetching development versions. ```groovy repositories { maven { url 'https://repo.opencollab.dev/maven-snapshots/' } } ``` -------------------------------- ### RakServerChannelConfig Source: https://context7.com/cloudburstmc/network/llms.txt Configure server-specific options for RakNet channels. Obtain the configuration object from `rakServerChannel.config()`. ```APIDOC ## `RakServerChannelConfig` — Server Configuration Interface `RakServerChannelConfig` extends `ChannelConfig` with server-specific options. Obtained from `rakServerChannel.config()`. ```java import org.cloudburstmc.netty.channel.raknet.config.RakServerChannelConfig; import org.cloudburstmc.netty.channel.raknet.config.RakServerCookieMode; RakServerChannelConfig cfg = rakServerChannel.config(); cfg.setGuid(ThreadLocalRandom.current().nextLong()); cfg.setMaxConnections(1000); cfg.setSupportedProtocols(new int[]{10, 11}); cfg.setMaxMtu(1400); cfg.setMinMtu(576); cfg.setHandlePing(true); // Forward RakPing events to pipeline instead of auto-replying cfg.setPacketLimit(120); // Per-IP rate limit cfg.setGlobalPacketLimit(100_000); cfg.setCookieMode(RakServerCookieMode.ACTIVE); // ACTIVE | OFFLOADED | OFFLOADED_PSK | OFF | INVALID cfg.setCookieSecret(secretKey16Bytes); // Must be exactly 16 bytes ByteBuf advertisement = Unpooled.copiedBuffer("MCPE;Server;748;1.21;5;100;id;world;Survival;1;19132;19133;".getBytes()); cfg.setAdvertisement(advertisement); // Read back long guid = cfg.getGuid(); int maxConn = cfg.getMaxConnections(); RakServerCookieMode mode = cfg.getCookieMode(); ``` ``` -------------------------------- ### RakChannelMetrics / RakServerMetrics Source: https://context7.com/cloudburstmc/network/llms.txt Interfaces with all-default methods that can be implemented to hook into internal protocol counters. Register them via RakChannelOption.RAK_METRICS (session) or RakChannelOption.RAK_SERVER_METRICS (server). ```APIDOC ## `RakChannelMetrics` / `RakServerMetrics` — Observability `RakChannelMetrics` and `RakServerMetrics` are interfaces with all-default methods that can be implemented to hook into internal protocol counters. Register them via `RakChannelOption.RAK_METRICS` (session) or `RakChannelOption.RAK_SERVER_METRICS` (server). ```java import org.cloudburstmc.netty.channel.raknet.config.RakChannelMetrics; import org.cloudburstmc.netty.channel.raknet.config.RakServerMetrics; import org.cloudburstmc.netty.channel.raknet.RakState; import io.micrometer.core.instrument.MeterRegistry; // Session-level metrics (per RakChildChannel / RakClientChannel) RakChannelMetrics sessionMetrics = new RakChannelMetrics() { @Override public void bytesIn(int count) { meterRegistry.counter("rak.bytes.in").increment(count); } @Override public void bytesOut(int count) { meterRegistry.counter("rak.bytes.out").increment(count); } @Override public void rakDatagramsIn(int count) { meterRegistry.counter("rak.datagrams.in").increment(count); } @Override public void rakDatagramsOut(int count) { meterRegistry.counter("rak.datagrams.out").increment(count); } @Override public void ackOut(int count) { meterRegistry.counter("rak.ack.out").increment(count); } @Override public void nackOut(int count) { meterRegistry.counter("rak.nack.out").increment(count); } @Override public void rakStaleDatagrams(int count) { meterRegistry.counter("rak.stale").increment(count); } @Override public void queuedPacketBytes(int count) { meterRegistry.gauge("rak.queue.bytes", count); } @Override public void stateChange(RakState state) { System.out.println("State → " + state); } }; // Server-level metrics (across all sessions) RakServerMetrics serverMetrics = new RakServerMetrics() { @Override public void channelOpen(InetSocketAddress address) { System.out.println("+ " + address); } @Override public void channelClose(InetSocketAddress address) { System.out.println("- " + address); } @Override public void unconnectedPing(InetSocketAddress addr) { pingsCounter.increment(); } @Override public void addressBlocked(InetAddress address) { System.out.println("Blocked: " + address); } @Override public void invalidCookie(InetSocketAddress address) { System.out.println("Bad cookie: " + address); } }; serverBootstrap .option(RakChannelOption.RAK_SERVER_METRICS, serverMetrics) .childOption(RakChannelOption.RAK_METRICS, sessionMetrics); ``` ``` -------------------------------- ### Add Snapshot Repository to Maven Source: https://github.com/cloudburstmc/network/blob/develop/README.md Configure your Maven project to include the snapshot repository for fetching development versions. ```xml opencollab-snapshots https://repo.opencollab.dev/maven-snapshots/ ``` -------------------------------- ### Configure RakServerCookieMode for Anti-Spoofing Source: https://context7.com/cloudburstmc/network/llms.txt Control how the server handles stateless SipHash cookies during the open-connection handshake to prevent IP spoofing and amplification attacks. Different modes like ACTIVE, OFFLOADED, OFFLOADED_PSK, OFF, and INVALID offer varying levels of security and proxy compatibility. ```java import org.cloudburstmc.netty.channel.raknet.config.RakServerCookieMode; // ACTIVE: server generates and validates cookies using its own key serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.ACTIVE); // Optional: supply a fixed 16-byte key (a random key is generated if not set) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_SECRET, mySecretKey); ``` ```java // OFFLOADED: a proxy/load-balancer handles OCR1; server only checks timestamp freshness serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.OFFLOADED); ``` ```java // OFFLOADED_PSK: offloaded + server verifies cookie signature with a known pre-shared key serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.OFFLOADED_PSK) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_SECRET, sharedKey); ``` ```java // OFF: accept any cookie value (legacy/no anti-spoofing) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.OFF); ``` ```java // INVALID: reject any client that sends a cookie (reserved use) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.INVALID); ``` -------------------------------- ### RakDisconnectReason Source: https://context7.com/cloudburstmc/network/llms.txt Handle `RakDisconnectReason` user events to distinguish different types of session closures. ```APIDOC ## `RakDisconnectReason` — Disconnection Events `RakDisconnectReason` is fired as a Netty user event on the `RakChannel` pipeline when a session ends. Handle it in `userEventTriggered` to distinguish clean closes from timeouts and protocol errors. ```java import org.cloudburstmc.netty.channel.raknet.RakDisconnectReason; public class GameSessionHandler extends ChannelInboundHandlerAdapter { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof RakDisconnectReason) { switch ((RakDisconnectReason) evt) { case CLOSED_BY_REMOTE_PEER: System.out.println("Client disconnected cleanly"); break; case TIMED_OUT: System.out.println("Connection timed out"); break; case DISCONNECTED: System.out.println("Disconnected locally"); break; case QUEUE_TOO_LONG: System.out.println("Send queue overflow"); break; case INCOMPATIBLE_PROTOCOL_VERSION: System.out.println("Wrong RakNet version"); break; case NO_FREE_INCOMING_CONNECTIONS: System.out.println("Server full"); break; case BAD_PACKET: System.out.println("Malformed packet"); break; // Other: SHUTTING_DOWN, CONNECTION_REQUEST_FAILED, ALREADY_CONNECTED, // IP_RECENTLY_CONNECTED default: System.out.println("Disconnect reason: " + evt); } ctx.channel().close(); } else { super.userEventTriggered(ctx, evt); } } } ``` ``` -------------------------------- ### RakPing / RakPong Source: https://context7.com/cloudburstmc/network/llms.txt Handle custom ping requests by forwarding `RakPing` user events and responding with `RakPong`. ```APIDOC ## `RakPing` / `RakPong` — Custom Ping Handling When `RAK_HANDLE_PING` is `true`, the server fires `RakPing` user events up the pipeline instead of auto-responding. The handler must reply by writing a `RakPong` to the channel. ```java import org.cloudburstmc.netty.channel.raknet.RakPing; import org.cloudburstmc.netty.channel.raknet.RakPong; // Add to RakServerChannel pipeline (server bootstrap handler) serverBootstrap.handler(new ChannelInboundHandlerAdapter() { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { if (msg instanceof RakPing) { RakPing ping = (RakPing) msg; // Build dynamic MOTD String motd = "MCPE;Server;748;1.21:" + getOnlinePlayers() + ";100;123456789;World;Survival;1;19132;19133;"; ByteBuf pongData = ctx.alloc().buffer().writeBytes(motd.getBytes()); long serverGuid = ((RakServerChannelConfig) ctx.channel().config()).getGuid(); RakPong pong = ping.reply(serverGuid, pongData); // constructs RakPong ctx.writeAndFlush(pong); } else { ctx.fireChannelRead(msg); } } }); // RakPong accessors // pong.getPingTime() — original timestamp echoed back // pong.getGuid() — server GUID // pong.getPongData() — advertisement ByteBuf (reference-counted) // pong.getSender() — InetSocketAddress of the pinging client ``` ``` -------------------------------- ### RakChannelConfig - Getters and Setters Source: https://context7.com/cloudburstmc/network/llms.txt Provides a typed interface for accessing and modifying session-level RakNet properties. ```APIDOC ## `RakChannelConfig` — Session Configuration Interface ### Description `RakChannelConfig` is the typed config interface for `RakChildChannel` and `RakClientChannel`. It exposes strongly-typed getters/setters for all session-level properties and is obtained from `channel.config()`. ### Method `((RakChannel) ctx.channel()).config()` ### Getters - **getGuid()** (Long) - Retrieves the remote client GUID. - **getMtu()** (Integer) - Retrieves the negotiated MTU. - **getProtocolVersion()** (Integer) - Retrieves the RakNet protocol version. - **getOrderingChannels()** (Integer) - Retrieves the number of ordering channels. - **getSessionTimeout()** (Long) - Retrieves the inactivity timeout in milliseconds. - **isAutoFlush()** (Boolean) - Checks if auto-flush is enabled. - **getFlushInterval()** (Integer) - Retrieves the flush interval in milliseconds. - **getMaxQueuedBytes()** (Integer) - Retrieves the maximum outbound queue size in bytes. ### Setters - **setSessionTimeout(long timeout)** - Sets the inactivity timeout in milliseconds. - **setAutoFlush(boolean autoFlush)** - Enables or disables auto-flush. - **setFlushInterval(int interval)** - Sets the flush interval in milliseconds when auto-flush is enabled. - **setMaxQueuedBytes(int maxBytes)** - Sets the maximum outbound queue size in bytes. ### Request Example (Getters) ```java RakChannelConfig cfg = ((RakChannel) ctx.channel()).config(); long guid = cfg.getGuid(); int mtu = cfg.getMtu(); int proto = cfg.getProtocolVersion(); int channels = cfg.getOrderingChannels(); long timeout = cfg.getSessionTimeout(); boolean autoFlush = cfg.isAutoFlush(); int flushInterval = cfg.getFlushInterval(); int maxQueued = cfg.getMaxQueuedBytes(); ``` ### Request Example (Setters) ```java cfg.setSessionTimeout(30_000L); cfg.setAutoFlush(false); cfg.setFlushInterval(5); cfg.setMaxQueuedBytes(4 * 1024 * 1024); ``` ``` -------------------------------- ### Manage RakSessionCodec for Session Lifecycle and Diagnostics Source: https://context7.com/cloudburstmc/network/llms.txt Access and manage the core RakNet session handler for sequencing, acknowledgements, and retransmission. Retrieve diagnostic information like ping, RTT, MTU, and session status, or perform graceful disconnects and immediate closes. ```java import org.cloudburstmc.netty.handler.codec.raknet.common.RakSessionCodec; // Retrieve from a child channel's rak pipeline RakSessionCodec codec = channel.rakPipeline().get(RakSessionCodec.class); if (codec != null) { long ping = codec.getPing(); // Round-trip time estimate (ms) double rtt = codec.getRTT(); // RTT from sliding window int mtu = codec.getMtu(); // Effective MTU (minus IP/UDP headers) boolean stale = codec.isStale(); // True if inactive > SESSION_STALE_MS (5 s) boolean timedOut = codec.isTimedOut(); // True if inactive > RAK_SESSION_TIMEOUT (default 10 s) boolean closed = codec.isClosed(); // True if state == UNCONNECTED // Graceful disconnect (sends ID_DISCONNECTION_NOTIFICATION then fires user event) codec.disconnect(); codec.disconnect(RakDisconnectReason.SHUTTING_DOWN); // Immediate close without sending disconnect notification codec.close(RakDisconnectReason.BAD_PACKET); } ``` -------------------------------- ### RakConstants Reference Source: https://context7.com/cloudburstmc/network/llms.txt Exposes all RakNet protocol values used internally, useful when writing custom pipeline handlers or logging. ```APIDOC ## `RakConstants` — Protocol Constants `RakConstants` exposes all RakNet protocol values used internally, useful when writing custom pipeline handlers or logging. ```java import org.cloudburstmc.netty.channel.raknet.RakConstants; // Protocol / MTU int version = RakConstants.RAKNET_PROTOCOL_VERSION; // 11 (Mojang) int minMtu = RakConstants.MINIMUM_MTU_SIZE; // 576 int maxMtu = RakConstants.MAXIMUM_MTU_SIZE; // 1400 Integer[] mtuProbes = RakConstants.MTU_SIZES; // [1400, 1200, 576] // Timing int sessionTimeout = RakConstants.SESSION_TIMEOUT_MS; // 10 000 ms int staleMs = RakConstants.SESSION_STALE_MS; // 5 000 ms int tick = (int) RakConstants.CC_SYN; // 10 ms (RakNet tick) // Packet IDs short ocr1 = RakConstants.ID_OPEN_CONNECTION_REQUEST_1; // 0x05 short ocr2 = RakConstants.ID_OPEN_CONNECTION_REQUEST_2; // 0x07 short ping = RakConstants.ID_UNCONNECTED_PING; // 0x01 short pong = RakConstants.ID_UNCONNECTED_PONG; // 0x1c short disconn = RakConstants.ID_DISCONNECTION_NOTIFICATION; // 0x15 short userBase = RakConstants.ID_USER_PACKET_ENUM; // 0x80 // Default unconnected magic (16 bytes) byte[] magic = RakConstants.DEFAULT_UNCONNECTED_MAGIC; ``` ``` -------------------------------- ### RakServerCookieMode Configuration Source: https://context7.com/cloudburstmc/network/llms.txt Controls how the server handles stateless SipHash cookies during the open-connection handshake to protect against IP spoofing and amplification attacks. ```APIDOC ## `RakServerCookieMode` — Anti-Spoofing Cookie Mode `RakServerCookieMode` controls how the server handles stateless SipHash cookies during the open-connection handshake to protect against IP spoofing and amplification attacks. ```java import org.cloudburstmc.netty.channel.raknet.config.RakServerCookieMode; // ACTIVE: server generates and validates cookies using its own key serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.ACTIVE); // Optional: supply a fixed 16-byte key (a random key is generated if not set) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_SECRET, mySecretKey); // OFFLOADED: a proxy/load-balancer handles OCR1; server only checks timestamp freshness serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.OFFLOADED); // OFFLOADED_PSK: offloaded + server verifies cookie signature with a known pre-shared key serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.OFFLOADED_PSK); serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_SECRET, sharedKey); // OFF: accept any cookie value (legacy/no anti-spoofing) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.OFF); // INVALID: reject any client that sends a cookie (reserved use) serverBootstrap.option(RakChannelOption.RAK_SERVER_COOKIE_MODE, RakServerCookieMode.INVALID); ``` ``` -------------------------------- ### RakPriority for Packet Sending Source: https://context7.com/cloudburstmc/network/llms.txt Use RakPriority to control the queue placement of outbound packets. IMMEDIATE bypasses the queue for synchronous flushing, while HIGH, NORMAL, and LOW are scheduled via a weighted binary heap. ```java import org.cloudburstmc.netty.channel.raknet.RakPriority; import org.cloudburstmc.netty.channel.raknet.packet.RakMessage; // Time-critical: disconnect notification, ping, etc. ctx.writeAndFlush(new RakMessage(buf, RakReliability.RELIABLE, RakPriority.IMMEDIATE)); // High-priority game logic (movement, attacks) ctx.writeAndFlush(new RakMessage(buf, RakReliability.RELIABLE_ORDERED, RakPriority.HIGH)); // Normal game packets (chat, inventory) ctx.writeAndFlush(new RakMessage(buf, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL)); // Background bulk transfer ctx.writeAndFlush(new RakMessage(buf, RakReliability.RELIABLE_ORDERED, RakPriority.LOW)); ```