All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.minestom.server.network.packet.PacketWriting Maven / Gradle / Ivy

There is a newer version: 7320437640
Show newest version
package net.minestom.server.network.packet;

import net.minestom.server.ServerFlag;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

import java.util.Queue;
import java.util.function.BiPredicate;

/**
 * Tools to write packets into a {@link NetworkBuffer} for network processing.
 * 

* Fairly internal and performance sensitive. */ @ApiStatus.Internal public final class PacketWriting { public static void writeFramedPacket(@NotNull NetworkBuffer buffer, @NotNull ConnectionState state, @NotNull ClientPacket packet, int compressionThreshold) throws IndexOutOfBoundsException { writeFramedPacket(buffer, PacketVanilla.CLIENT_PACKET_PARSER, state, packet, compressionThreshold); } public static void writeFramedPacket(@NotNull NetworkBuffer buffer, @NotNull ConnectionState state, @NotNull ServerPacket packet, int compressionThreshold) throws IndexOutOfBoundsException { writeFramedPacket(buffer, PacketVanilla.SERVER_PACKET_PARSER, state, packet, compressionThreshold); } public static void writeFramedPacket(@NotNull NetworkBuffer buffer, @NotNull PacketParser parser, @NotNull ConnectionState state, @NotNull T packet, int compressionThreshold) throws IndexOutOfBoundsException { final PacketRegistry registry = parser.stateRegistry(state); writeFramedPacket(buffer, registry, packet, compressionThreshold); } public static void writeFramedPacket(@NotNull NetworkBuffer buffer, @NotNull PacketRegistry registry, @NotNull T packet, int compressionThreshold) throws IndexOutOfBoundsException { final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet); writeFramedPacket( buffer, packetInfo, packet, compressionThreshold ); } public static void writeFramedPacket(@NotNull NetworkBuffer buffer, @NotNull PacketRegistry.PacketInfo packetInfo, @NotNull T packet, int compressionThreshold) throws IndexOutOfBoundsException { final int id = packetInfo.id(); final NetworkBuffer.Type serializer = packetInfo.serializer(); writeFramedPacket( buffer, serializer, id, packet, compressionThreshold ); } public static void writeFramedPacket(@NotNull NetworkBuffer buffer, @NotNull NetworkBuffer.Type type, int id, @NotNull T packet, int compressionThreshold) throws IndexOutOfBoundsException { if (compressionThreshold <= 0) writeUncompressedFormat(buffer, type, id, packet); else writeCompressedFormat(buffer, type, id, packet, compressionThreshold); } private static void writeUncompressedFormat(NetworkBuffer buffer, NetworkBuffer.Type type, int id, T packet) throws IndexOutOfBoundsException { // Uncompressed format https://wiki.vg/Protocol#Without_compression final long lengthIndex = buffer.advanceWrite(3); buffer.write(NetworkBuffer.VAR_INT, id); buffer.write(type, packet); final long finalSize = buffer.writeIndex() - (lengthIndex + 3); buffer.writeAt(lengthIndex, NetworkBuffer.VAR_INT_3, (int) finalSize); } private static void writeCompressedFormat(NetworkBuffer buffer, NetworkBuffer.Type type, int id, T packet, int compressionThreshold) throws IndexOutOfBoundsException { // Compressed format https://wiki.vg/Protocol#With_compression final long compressedIndex = buffer.advanceWrite(3); final long uncompressedIndex = buffer.advanceWrite(3); final long contentStart = buffer.writeIndex(); buffer.write(NetworkBuffer.VAR_INT, id); buffer.write(type, packet); final long packetSize = buffer.writeIndex() - contentStart; final boolean compressed = packetSize >= compressionThreshold; if (compressed) { // Write the compressed content into the pooled buffer // and compress it into the current buffer NetworkBuffer input = PacketVanilla.PACKET_POOL.get(); try { if (input.capacity() < packetSize) input.resize(packetSize); NetworkBuffer.copy(buffer, contentStart, input, 0, packetSize); buffer.writeIndex(contentStart); input.compress(0, packetSize, buffer); } finally { PacketVanilla.PACKET_POOL.add(input); } } // Packet header (Packet + Data Length) buffer.writeAt(compressedIndex, NetworkBuffer.VAR_INT_3, (int) (buffer.writeIndex() - uncompressedIndex)); buffer.writeAt(uncompressedIndex, NetworkBuffer.VAR_INT_3, compressed ? (int) packetSize : 0); } public static NetworkBuffer allocateTrimmedPacket(@NotNull ConnectionState state, @NotNull ClientPacket packet, int compressionThreshold) { return allocateTrimmedPacket(PacketVanilla.CLIENT_PACKET_PARSER, state, packet, compressionThreshold); } public static NetworkBuffer allocateTrimmedPacket(@NotNull ConnectionState state, @NotNull ServerPacket packet, int compressionThreshold) { return allocateTrimmedPacket(PacketVanilla.SERVER_PACKET_PARSER, state, packet, compressionThreshold); } public static NetworkBuffer allocateTrimmedPacket( @NotNull PacketParser parser, @NotNull ConnectionState state, @NotNull T packet, int compressionThreshold) { NetworkBuffer buffer = PacketVanilla.PACKET_POOL.get(); try { return allocateTrimmedPacket(buffer, parser, state, packet, compressionThreshold); } finally { PacketVanilla.PACKET_POOL.add(buffer); } } public static NetworkBuffer allocateTrimmedPacket( @NotNull NetworkBuffer tmpBuffer, @NotNull PacketParser parser, @NotNull ConnectionState state, @NotNull T packet, int compressionThreshold) { final PacketRegistry registry = parser.stateRegistry(state); return allocateTrimmedPacket(tmpBuffer, registry, packet, compressionThreshold); } public static NetworkBuffer allocateTrimmedPacket( @NotNull NetworkBuffer tmpBuffer, @NotNull PacketRegistry registry, @NotNull T packet, int compressionThreshold) { final PacketRegistry.PacketInfo packetInfo = registry.packetInfo(packet); final int id = packetInfo.id(); final NetworkBuffer.Type serializer = packetInfo.serializer(); try { writeFramedPacket(tmpBuffer, serializer, id, packet, compressionThreshold); return tmpBuffer.copy(0, tmpBuffer.writeIndex()); } catch (IndexOutOfBoundsException e) { final long sizeOf = serializer.sizeOf(packet, tmpBuffer.registries()); if (sizeOf > ServerFlag.MAX_PACKET_SIZE) { throw new IllegalStateException("Packet too large: " + sizeOf); } // Add 15 bytes to account for the 3 potential varints in the packet header // Packet Length - Data Length - Packet ID tmpBuffer.resize(sizeOf + 15); tmpBuffer.writeIndex(0); writeFramedPacket(tmpBuffer, serializer, id, packet, compressionThreshold); return tmpBuffer.copy(0, tmpBuffer.writeIndex()); } } public static void writeQueue(NetworkBuffer buffer, Queue queue, int minWrite, BiPredicate writer) { // The goal of this method is to write at the very least `minWrite` packets if the queue permits it. // The buffer is resized if it cannot hold this minimum. final int size = queue.size(); minWrite = Math.min(minWrite, size); T packet; int written = 0; while ((packet = queue.peek()) != null) { final long index = buffer.writeIndex(); boolean success; try { success = writer.test(buffer, packet); } catch (IndexOutOfBoundsException e) { success = false; } assert !success || buffer.writeIndex() > 0; // Poll the packet only if fully written if (success) { // Packet fully written queue.poll(); written++; } else { buffer.writeIndex(index); if (written < minWrite) { // Try again with a bigger buffer final long newSize = Math.min(buffer.capacity() * 2, ServerFlag.MAX_PACKET_SIZE); buffer.resize(newSize); } else { // At least one packet has been written // Not worth resizing to fit more, we'll try again next flush break; } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy