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 p_330610_, List> p_334834_, Object2IntMap p_327784_) { this.typeGetter = p_330610_; this.byId = p_334834_; this.toId = p_327784_; } public V decode(B p_327793_) { int i = VarInt.read(p_327793_); if (i >= 0 && i < this.byId.size()) { IdDispatchCodec.Entry entry = this.byId.get(i); try { return (V)entry.serializer.decode(p_327793_); } catch (Exception exception) { if (exception instanceof IdDispatchCodec.DontDecorateException) { throw exception; } else { throw new DecoderException("Failed to decode packet '" + entry.type + "'", exception); } } } else { throw new DecoderException("Received unknown packet id " + i); } } public void encode(B p_336072_, V p_327912_) { T t = (T)this.typeGetter.apply(p_327912_); int i = this.toId.getOrDefault(t, -1); if (i == -1) { throw new EncoderException("Sending unknown packet '" + t + "'"); } else { VarInt.write(p_336072_, i); IdDispatchCodec.Entry entry = this.byId.get(i); try { StreamCodec streamcodec = (StreamCodec)entry.serializer; streamcodec.encode(p_336072_, p_327912_); } catch (Exception exception) { if (exception instanceof IdDispatchCodec.DontDecorateException) { throw exception; } else { throw new EncoderException("Failed to encode packet '" + t + "'", exception); } } } } public static IdDispatchCodec.Builder builder(Function p_331962_) { return new IdDispatchCodec.Builder<>(p_331962_); } public static class Builder { private final List> entries = new ArrayList<>(); private final Function typeGetter; Builder(Function p_330341_) { this.typeGetter = p_330341_; } public IdDispatchCodec.Builder add(T p_333313_, StreamCodec p_330239_) { this.entries.add(new IdDispatchCodec.Entry<>(p_330239_, p_333313_)); 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); } } public interface DontDecorateException { } record Entry(StreamCodec serializer, T type) { } }