package net.minecraft.network.codec; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import net.minecraft.network.VarInt; public class IdDispatchCodec implements StreamCodec { private static final int UNKNOWN_TYPE = -1; private final Function typeGetter; private final List> byId; private final Object2IntMap toId; IdDispatchCodec(Function typeGetter, List> byId, Object2IntMap toId) { this.typeGetter = typeGetter; this.byId = byId; this.toId = toId; } public V decode(B byteBuf) { int i = VarInt.read(byteBuf); if (i >= 0 && i < this.byId.size()) { IdDispatchCodec.Entry entry = (IdDispatchCodec.Entry)this.byId.get(i); try { return (V)entry.serializer.decode(byteBuf); } catch (Exception var5) { throw new DecoderException("Failed to decode packet '" + entry.type + "'", var5); } } else { throw new DecoderException("Received unknown packet id " + i); } } public void encode(B byteBuf, V object) { T object2 = (T)this.typeGetter.apply(object); int i = this.toId.getOrDefault(object2, -1); if (i == -1) { throw new EncoderException("Sending unknown packet '" + object2 + "'"); } else { VarInt.write(byteBuf, i); IdDispatchCodec.Entry entry = (IdDispatchCodec.Entry)this.byId.get(i); try { StreamCodec streamCodec = (StreamCodec)entry.serializer; streamCodec.encode(byteBuf, object); } catch (Exception var7) { throw new EncoderException("Failed to encode packet '" + object2 + "'", var7); } } } public static IdDispatchCodec.Builder builder(Function typeGetter) { return new IdDispatchCodec.Builder<>(typeGetter); } public static class Builder { private final List> entries = new ArrayList(); private final Function typeGetter; Builder(Function typeGetter) { this.typeGetter = typeGetter; } public IdDispatchCodec.Builder add(T type, StreamCodec serializer) { this.entries.add(new IdDispatchCodec.Entry<>(serializer, type)); return this; } public IdDispatchCodec build() { Object2IntOpenHashMap object2IntOpenHashMap = new Object2IntOpenHashMap<>(); object2IntOpenHashMap.defaultReturnValue(-2); for (IdDispatchCodec.Entry entry : this.entries) { int i = object2IntOpenHashMap.size(); int j = object2IntOpenHashMap.putIfAbsent(entry.type, i); if (j != -2) { throw new IllegalStateException("Duplicate registration for type " + entry.type); } } return new IdDispatchCodec<>(this.typeGetter, List.copyOf(this.entries), object2IntOpenHashMap); } } record Entry(StreamCodec serializer, T type) { } }