package net.minecraft.network.protocol; import io.netty.buffer.ByteBuf; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; import net.minecraft.network.ClientboundPacketListener; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.PacketListener; import net.minecraft.network.ProtocolInfo; import net.minecraft.network.ServerboundPacketListener; import net.minecraft.network.codec.StreamCodec; import org.jetbrains.annotations.Nullable; public class ProtocolInfoBuilder { final ConnectionProtocol protocol; final PacketFlow flow; private final List> codecs = new ArrayList(); @Nullable private BundlerInfo bundlerInfo; public ProtocolInfoBuilder(ConnectionProtocol protocol, PacketFlow flow) { this.protocol = protocol; this.flow = flow; } public

> ProtocolInfoBuilder addPacket(PacketType

type, StreamCodec serializer) { this.codecs.add(new ProtocolInfoBuilder.CodecEntry<>(type, serializer)); return this; } public

, D extends BundleDelimiterPacket> ProtocolInfoBuilder withBundlePacket( PacketType

type, Function>, P> bundler, D packet ) { StreamCodec streamCodec = StreamCodec.unit(packet); PacketType packetType = (PacketType)packet.type(); this.codecs.add(new ProtocolInfoBuilder.CodecEntry<>(packetType, streamCodec)); this.bundlerInfo = BundlerInfo.createForPacket(type, bundler, packet); return this; } StreamCodec> buildPacketCodec(Function bufferFactory, List> codecs) { ProtocolCodecBuilder protocolCodecBuilder = new ProtocolCodecBuilder<>(this.flow); for (ProtocolInfoBuilder.CodecEntry codecEntry : codecs) { codecEntry.addToBuilder(protocolCodecBuilder, bufferFactory); } return protocolCodecBuilder.build(); } public ProtocolInfo build(Function bufferFactory) { return new ProtocolInfoBuilder.Implementation<>(this.protocol, this.flow, this.buildPacketCodec(bufferFactory, this.codecs), this.bundlerInfo); } public ProtocolInfo.Unbound buildUnbound() { final List> list = List.copyOf(this.codecs); final BundlerInfo bundlerInfo = this.bundlerInfo; return new ProtocolInfo.Unbound() { @Override public ProtocolInfo bind(Function bufferFactory) { return new ProtocolInfoBuilder.Implementation<>( ProtocolInfoBuilder.this.protocol, ProtocolInfoBuilder.this.flow, ProtocolInfoBuilder.this.buildPacketCodec(bufferFactory, list), bundlerInfo ); } @Override public ConnectionProtocol id() { return ProtocolInfoBuilder.this.protocol; } @Override public PacketFlow flow() { return ProtocolInfoBuilder.this.flow; } @Override public void listPackets(ProtocolInfo.Unbound.PacketVisitor visitor) { for (int i = 0; i < list.size(); i++) { ProtocolInfoBuilder.CodecEntry codecEntry = (ProtocolInfoBuilder.CodecEntry)list.get(i); visitor.accept(codecEntry.type, i); } } }; } private static ProtocolInfo.Unbound protocol( ConnectionProtocol protocol, PacketFlow flow, Consumer> setup ) { ProtocolInfoBuilder protocolInfoBuilder = new ProtocolInfoBuilder<>(protocol, flow); setup.accept(protocolInfoBuilder); return protocolInfoBuilder.buildUnbound(); } public static ProtocolInfo.Unbound serverboundProtocol( ConnectionProtocol protocol, Consumer> setup ) { return protocol(protocol, PacketFlow.SERVERBOUND, setup); } public static ProtocolInfo.Unbound clientboundProtocol( ConnectionProtocol protocol, Consumer> setup ) { return protocol(protocol, PacketFlow.CLIENTBOUND, setup); } record CodecEntry, B extends ByteBuf>(PacketType

type, StreamCodec serializer) { public void addToBuilder(ProtocolCodecBuilder codecBuilder, Function bufferFactory) { StreamCodec streamCodec = this.serializer.mapStream(bufferFactory); codecBuilder.add(this.type, streamCodec); } } record Implementation( ConnectionProtocol id, PacketFlow flow, StreamCodec> codec, @Nullable BundlerInfo bundlerInfo ) implements ProtocolInfo { } }