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.ProtocolInfo.Details.PacketVisitor; import net.minecraft.network.codec.StreamCodec; import net.minecraft.util.Unit; 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, null)); return this; } public

> ProtocolInfoBuilder addPacket( PacketType

type, StreamCodec serializer, CodecModifier modifier ) { this.codecs.add(new ProtocolInfoBuilder.CodecEntry<>(type, serializer, modifier)); 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, null)); this.bundlerInfo = BundlerInfo.createForPacket(type, bundler, packet); return this; } StreamCodec> buildPacketCodec( Function bufferFactory, List> entries, C context ) { ProtocolCodecBuilder protocolCodecBuilder = new ProtocolCodecBuilder<>(this.flow); for (ProtocolInfoBuilder.CodecEntry codecEntry : entries) { codecEntry.addToBuilder(protocolCodecBuilder, bufferFactory, context); } return protocolCodecBuilder.build(); } private static ProtocolInfo.Details buildDetails( ConnectionProtocol protocol, PacketFlow flow, List> entries ) { return new ProtocolInfo.Details() { @Override public ConnectionProtocol id() { return protocol; } @Override public PacketFlow flow() { return flow; } @Override public void listPackets(PacketVisitor visitor) { for (int i = 0; i < entries.size(); i++) { ProtocolInfoBuilder.CodecEntry codecEntry = (ProtocolInfoBuilder.CodecEntry)entries.get(i); visitor.accept(codecEntry.type, i); } } }; } public SimpleUnboundProtocol buildUnbound(C context) { final List> list = List.copyOf(this.codecs); final BundlerInfo bundlerInfo = this.bundlerInfo; final ProtocolInfo.Details details = buildDetails(this.protocol, this.flow, list); return new SimpleUnboundProtocol() { @Override public ProtocolInfo bind(Function bufferFactory) { return new ProtocolInfoBuilder.Implementation<>( ProtocolInfoBuilder.this.protocol, ProtocolInfoBuilder.this.flow, ProtocolInfoBuilder.this.buildPacketCodec(bufferFactory, list, context), bundlerInfo ); } @Override public ProtocolInfo.Details details() { return details; } }; } public UnboundProtocol buildUnbound() { final List> list = List.copyOf(this.codecs); final BundlerInfo bundlerInfo = this.bundlerInfo; final ProtocolInfo.Details details = buildDetails(this.protocol, this.flow, list); return new UnboundProtocol() { @Override public ProtocolInfo bind(Function bufferFactory, C context) { return new ProtocolInfoBuilder.Implementation<>( ProtocolInfoBuilder.this.protocol, ProtocolInfoBuilder.this.flow, ProtocolInfoBuilder.this.buildPacketCodec(bufferFactory, list, context), bundlerInfo ); } @Override public ProtocolInfo.Details details() { return details; } }; } private static SimpleUnboundProtocol protocol( ConnectionProtocol protocol, PacketFlow flow, Consumer> packetAdder ) { ProtocolInfoBuilder protocolInfoBuilder = new ProtocolInfoBuilder<>(protocol, flow); packetAdder.accept(protocolInfoBuilder); return protocolInfoBuilder.buildUnbound(Unit.INSTANCE); } public static SimpleUnboundProtocol serverboundProtocol( ConnectionProtocol protocol, Consumer> packetAdder ) { return protocol(protocol, PacketFlow.SERVERBOUND, packetAdder); } public static SimpleUnboundProtocol clientboundProtocol( ConnectionProtocol protocol, Consumer> packetAdder ) { return protocol(protocol, PacketFlow.CLIENTBOUND, packetAdder); } private static UnboundProtocol contextProtocol( ConnectionProtocol protocol, PacketFlow flow, Consumer> packetAdder ) { ProtocolInfoBuilder protocolInfoBuilder = new ProtocolInfoBuilder<>(protocol, flow); packetAdder.accept(protocolInfoBuilder); return protocolInfoBuilder.buildUnbound(); } public static UnboundProtocol contextServerboundProtocol( ConnectionProtocol protocol, Consumer> packetAdder ) { return contextProtocol(protocol, PacketFlow.SERVERBOUND, packetAdder); } public static UnboundProtocol contextClientboundProtocol( ConnectionProtocol protocol, Consumer> packetAdder ) { return contextProtocol(protocol, PacketFlow.CLIENTBOUND, packetAdder); } record CodecEntry, B extends ByteBuf, C>( PacketType

type, StreamCodec serializer, @Nullable CodecModifier modifier ) { public void addToBuilder(ProtocolCodecBuilder builder, Function bufferFactory, C context) { StreamCodec streamCodec; if (this.modifier != null) { streamCodec = this.modifier.apply(this.serializer, context); } else { streamCodec = this.serializer; } StreamCodec streamCodec2 = streamCodec.mapStream(bufferFactory); builder.add(this.type, streamCodec2); } } record Implementation( ConnectionProtocol id, PacketFlow flow, StreamCodec> codec, @Nullable BundlerInfo bundlerInfo ) implements ProtocolInfo { } }