573 lines
20 KiB
Java
573 lines
20 KiB
Java
package net.minecraft.network.codec;
|
|
|
|
import com.mojang.authlib.GameProfile;
|
|
import com.mojang.authlib.properties.Property;
|
|
import com.mojang.authlib.properties.PropertyMap;
|
|
import com.mojang.datafixers.util.Either;
|
|
import com.mojang.serialization.Codec;
|
|
import io.netty.buffer.ByteBuf;
|
|
import io.netty.handler.codec.DecoderException;
|
|
import io.netty.handler.codec.EncoderException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.OptionalInt;
|
|
import java.util.UUID;
|
|
import java.util.function.Function;
|
|
import java.util.function.IntFunction;
|
|
import java.util.function.Supplier;
|
|
import java.util.function.ToIntFunction;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.HolderSet;
|
|
import net.minecraft.core.IdMap;
|
|
import net.minecraft.core.Registry;
|
|
import net.minecraft.core.UUIDUtil;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.EndTag;
|
|
import net.minecraft.nbt.NbtAccounter;
|
|
import net.minecraft.nbt.NbtOps;
|
|
import net.minecraft.nbt.Tag;
|
|
import net.minecraft.network.FriendlyByteBuf;
|
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
import net.minecraft.network.Utf8String;
|
|
import net.minecraft.network.VarInt;
|
|
import net.minecraft.network.VarLong;
|
|
import net.minecraft.resources.RegistryOps;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.tags.TagKey;
|
|
import net.minecraft.util.Mth;
|
|
import org.joml.Quaternionf;
|
|
import org.joml.Vector3f;
|
|
|
|
public interface ByteBufCodecs {
|
|
int MAX_INITIAL_COLLECTION_SIZE = 65536;
|
|
StreamCodec<ByteBuf, Boolean> BOOL = new StreamCodec<ByteBuf, Boolean>() {
|
|
public Boolean decode(ByteBuf byteBuf) {
|
|
return byteBuf.readBoolean();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Boolean boolean_) {
|
|
byteBuf.writeBoolean(boolean_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Byte> BYTE = new StreamCodec<ByteBuf, Byte>() {
|
|
public Byte decode(ByteBuf byteBuf) {
|
|
return byteBuf.readByte();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Byte byte_) {
|
|
byteBuf.writeByte(byte_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Float> ROTATION_BYTE = BYTE.map(Mth::unpackDegrees, Mth::packDegrees);
|
|
StreamCodec<ByteBuf, Short> SHORT = new StreamCodec<ByteBuf, Short>() {
|
|
public Short decode(ByteBuf byteBuf) {
|
|
return byteBuf.readShort();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Short short_) {
|
|
byteBuf.writeShort(short_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Integer> UNSIGNED_SHORT = new StreamCodec<ByteBuf, Integer>() {
|
|
public Integer decode(ByteBuf byteBuf) {
|
|
return byteBuf.readUnsignedShort();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Integer integer) {
|
|
byteBuf.writeShort(integer);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Integer> INT = new StreamCodec<ByteBuf, Integer>() {
|
|
public Integer decode(ByteBuf byteBuf) {
|
|
return byteBuf.readInt();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Integer integer) {
|
|
byteBuf.writeInt(integer);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Integer> VAR_INT = new StreamCodec<ByteBuf, Integer>() {
|
|
public Integer decode(ByteBuf byteBuf) {
|
|
return VarInt.read(byteBuf);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Integer integer) {
|
|
VarInt.write(byteBuf, integer);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, OptionalInt> OPTIONAL_VAR_INT = VAR_INT.map(
|
|
integer -> integer == 0 ? OptionalInt.empty() : OptionalInt.of(integer - 1), optionalInt -> optionalInt.isPresent() ? optionalInt.getAsInt() + 1 : 0
|
|
);
|
|
StreamCodec<ByteBuf, Long> LONG = new StreamCodec<ByteBuf, Long>() {
|
|
public Long decode(ByteBuf byteBuf) {
|
|
return byteBuf.readLong();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Long long_) {
|
|
byteBuf.writeLong(long_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Long> VAR_LONG = new StreamCodec<ByteBuf, Long>() {
|
|
public Long decode(ByteBuf byteBuf) {
|
|
return VarLong.read(byteBuf);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Long long_) {
|
|
VarLong.write(byteBuf, long_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Float> FLOAT = new StreamCodec<ByteBuf, Float>() {
|
|
public Float decode(ByteBuf byteBuf) {
|
|
return byteBuf.readFloat();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Float float_) {
|
|
byteBuf.writeFloat(float_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Double> DOUBLE = new StreamCodec<ByteBuf, Double>() {
|
|
public Double decode(ByteBuf byteBuf) {
|
|
return byteBuf.readDouble();
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Double double_) {
|
|
byteBuf.writeDouble(double_);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, byte[]> BYTE_ARRAY = new StreamCodec<ByteBuf, byte[]>() {
|
|
public byte[] decode(ByteBuf byteBuf) {
|
|
return FriendlyByteBuf.readByteArray(byteBuf);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, byte[] bs) {
|
|
FriendlyByteBuf.writeByteArray(byteBuf, bs);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, String> STRING_UTF8 = stringUtf8(32767);
|
|
StreamCodec<ByteBuf, Tag> TAG = tagCodec(() -> NbtAccounter.create(2097152L));
|
|
StreamCodec<ByteBuf, Tag> TRUSTED_TAG = tagCodec(NbtAccounter::unlimitedHeap);
|
|
StreamCodec<ByteBuf, CompoundTag> COMPOUND_TAG = compoundTagCodec(() -> NbtAccounter.create(2097152L));
|
|
StreamCodec<ByteBuf, CompoundTag> TRUSTED_COMPOUND_TAG = compoundTagCodec(NbtAccounter::unlimitedHeap);
|
|
StreamCodec<ByteBuf, Optional<CompoundTag>> OPTIONAL_COMPOUND_TAG = new StreamCodec<ByteBuf, Optional<CompoundTag>>() {
|
|
public Optional<CompoundTag> decode(ByteBuf byteBuf) {
|
|
return Optional.ofNullable(FriendlyByteBuf.readNbt(byteBuf));
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Optional<CompoundTag> optional) {
|
|
FriendlyByteBuf.writeNbt(byteBuf, (Tag)optional.orElse(null));
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Vector3f> VECTOR3F = new StreamCodec<ByteBuf, Vector3f>() {
|
|
public Vector3f decode(ByteBuf byteBuf) {
|
|
return FriendlyByteBuf.readVector3f(byteBuf);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Vector3f vector3f) {
|
|
FriendlyByteBuf.writeVector3f(byteBuf, vector3f);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Quaternionf> QUATERNIONF = new StreamCodec<ByteBuf, Quaternionf>() {
|
|
public Quaternionf decode(ByteBuf byteBuf) {
|
|
return FriendlyByteBuf.readQuaternion(byteBuf);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Quaternionf quaternionf) {
|
|
FriendlyByteBuf.writeQuaternion(byteBuf, quaternionf);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, Integer> CONTAINER_ID = new StreamCodec<ByteBuf, Integer>() {
|
|
public Integer decode(ByteBuf byteBuf) {
|
|
return FriendlyByteBuf.readContainerId(byteBuf);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Integer integer) {
|
|
FriendlyByteBuf.writeContainerId(byteBuf, integer);
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, PropertyMap> GAME_PROFILE_PROPERTIES = new StreamCodec<ByteBuf, PropertyMap>() {
|
|
private static final int MAX_PROPERTY_NAME_LENGTH = 64;
|
|
private static final int MAX_PROPERTY_VALUE_LENGTH = 32767;
|
|
private static final int MAX_PROPERTY_SIGNATURE_LENGTH = 1024;
|
|
private static final int MAX_PROPERTIES = 16;
|
|
|
|
public PropertyMap decode(ByteBuf byteBuf) {
|
|
int i = ByteBufCodecs.readCount(byteBuf, 16);
|
|
PropertyMap propertyMap = new PropertyMap();
|
|
|
|
for (int j = 0; j < i; j++) {
|
|
String string = Utf8String.read(byteBuf, 64);
|
|
String string2 = Utf8String.read(byteBuf, 32767);
|
|
String string3 = FriendlyByteBuf.readNullable(byteBuf, byteBufx -> Utf8String.read(byteBufx, 1024));
|
|
Property property = new Property(string, string2, string3);
|
|
propertyMap.put(property.name(), property);
|
|
}
|
|
|
|
return propertyMap;
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, PropertyMap propertyMap) {
|
|
ByteBufCodecs.writeCount(byteBuf, propertyMap.size(), 16);
|
|
|
|
for (Property property : propertyMap.values()) {
|
|
Utf8String.write(byteBuf, property.name(), 64);
|
|
Utf8String.write(byteBuf, property.value(), 32767);
|
|
FriendlyByteBuf.writeNullable(byteBuf, property.signature(), (byteBufx, string) -> Utf8String.write(byteBufx, string, 1024));
|
|
}
|
|
}
|
|
};
|
|
StreamCodec<ByteBuf, GameProfile> GAME_PROFILE = new StreamCodec<ByteBuf, GameProfile>() {
|
|
public GameProfile decode(ByteBuf byteBuf) {
|
|
UUID uUID = UUIDUtil.STREAM_CODEC.decode(byteBuf);
|
|
String string = Utf8String.read(byteBuf, 16);
|
|
GameProfile gameProfile = new GameProfile(uUID, string);
|
|
gameProfile.getProperties().putAll(ByteBufCodecs.GAME_PROFILE_PROPERTIES.decode(byteBuf));
|
|
return gameProfile;
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, GameProfile gameProfile) {
|
|
UUIDUtil.STREAM_CODEC.encode(byteBuf, gameProfile.getId());
|
|
Utf8String.write(byteBuf, gameProfile.getName(), 16);
|
|
ByteBufCodecs.GAME_PROFILE_PROPERTIES.encode(byteBuf, gameProfile.getProperties());
|
|
}
|
|
};
|
|
|
|
static StreamCodec<ByteBuf, byte[]> byteArray(int maxSize) {
|
|
return new StreamCodec<ByteBuf, byte[]>() {
|
|
public byte[] decode(ByteBuf buffer) {
|
|
return FriendlyByteBuf.readByteArray(buffer, maxSize);
|
|
}
|
|
|
|
public void encode(ByteBuf buffer, byte[] value) {
|
|
if (value.length > maxSize) {
|
|
throw new EncoderException("ByteArray with size " + value.length + " is bigger than allowed " + maxSize);
|
|
} else {
|
|
FriendlyByteBuf.writeByteArray(buffer, value);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
static StreamCodec<ByteBuf, String> stringUtf8(int maxLength) {
|
|
return new StreamCodec<ByteBuf, String>() {
|
|
public String decode(ByteBuf byteBuf) {
|
|
return Utf8String.read(byteBuf, maxLength);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, String string) {
|
|
Utf8String.write(byteBuf, string, maxLength);
|
|
}
|
|
};
|
|
}
|
|
|
|
static StreamCodec<ByteBuf, Tag> tagCodec(Supplier<NbtAccounter> accounter) {
|
|
return new StreamCodec<ByteBuf, Tag>() {
|
|
public Tag decode(ByteBuf byteBuf) {
|
|
Tag tag = FriendlyByteBuf.readNbt(byteBuf, (NbtAccounter)accounter.get());
|
|
if (tag == null) {
|
|
throw new DecoderException("Expected non-null compound tag");
|
|
} else {
|
|
return tag;
|
|
}
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, Tag tag) {
|
|
if (tag == EndTag.INSTANCE) {
|
|
throw new EncoderException("Expected non-null compound tag");
|
|
} else {
|
|
FriendlyByteBuf.writeNbt(byteBuf, tag);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
static StreamCodec<ByteBuf, CompoundTag> compoundTagCodec(Supplier<NbtAccounter> accounterSupplier) {
|
|
return tagCodec(accounterSupplier).map(tag -> {
|
|
if (tag instanceof CompoundTag compoundTag) {
|
|
return compoundTag;
|
|
} else {
|
|
throw new DecoderException("Not a compound tag: " + tag);
|
|
}
|
|
}, compoundTag -> compoundTag);
|
|
}
|
|
|
|
static <T> StreamCodec<ByteBuf, T> fromCodecTrusted(Codec<T> codec) {
|
|
return fromCodec(codec, NbtAccounter::unlimitedHeap);
|
|
}
|
|
|
|
static <T> StreamCodec<ByteBuf, T> fromCodec(Codec<T> codec) {
|
|
return fromCodec(codec, () -> NbtAccounter.create(2097152L));
|
|
}
|
|
|
|
static <T> StreamCodec<ByteBuf, T> fromCodec(Codec<T> codec, Supplier<NbtAccounter> accounterSupplier) {
|
|
return tagCodec(accounterSupplier)
|
|
.map(
|
|
tag -> codec.parse(NbtOps.INSTANCE, tag).getOrThrow(string -> new DecoderException("Failed to decode: " + string + " " + tag)),
|
|
object -> codec.encodeStart(NbtOps.INSTANCE, (T)object).getOrThrow(string -> new EncoderException("Failed to encode: " + string + " " + object))
|
|
);
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, T> fromCodecWithRegistriesTrusted(Codec<T> codec) {
|
|
return fromCodecWithRegistries(codec, NbtAccounter::unlimitedHeap);
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, T> fromCodecWithRegistries(Codec<T> codec) {
|
|
return fromCodecWithRegistries(codec, () -> NbtAccounter.create(2097152L));
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, T> fromCodecWithRegistries(Codec<T> codec, Supplier<NbtAccounter> accounterSupplier) {
|
|
final StreamCodec<ByteBuf, Tag> streamCodec = tagCodec(accounterSupplier);
|
|
return new StreamCodec<RegistryFriendlyByteBuf, T>() {
|
|
public T decode(RegistryFriendlyByteBuf registryFriendlyByteBuf) {
|
|
Tag tag = streamCodec.decode(registryFriendlyByteBuf);
|
|
RegistryOps<Tag> registryOps = registryFriendlyByteBuf.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
|
return codec.parse(registryOps, tag).getOrThrow(string -> new DecoderException("Failed to decode: " + string + " " + tag));
|
|
}
|
|
|
|
public void encode(RegistryFriendlyByteBuf registryFriendlyByteBuf, T object) {
|
|
RegistryOps<Tag> registryOps = registryFriendlyByteBuf.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
|
Tag tag = codec.encodeStart(registryOps, object).getOrThrow(string -> new EncoderException("Failed to encode: " + string + " " + object));
|
|
streamCodec.encode(registryFriendlyByteBuf, tag);
|
|
}
|
|
};
|
|
}
|
|
|
|
static <B extends ByteBuf, V> StreamCodec<B, Optional<V>> optional(StreamCodec<B, V> codec) {
|
|
return new StreamCodec<B, Optional<V>>() {
|
|
public Optional<V> decode(B byteBuf) {
|
|
return byteBuf.readBoolean() ? Optional.of(codec.decode(byteBuf)) : Optional.empty();
|
|
}
|
|
|
|
public void encode(B byteBuf, Optional<V> optional) {
|
|
if (optional.isPresent()) {
|
|
byteBuf.writeBoolean(true);
|
|
codec.encode(byteBuf, (V)optional.get());
|
|
} else {
|
|
byteBuf.writeBoolean(false);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
static int readCount(ByteBuf buffer, int maxSize) {
|
|
int i = VarInt.read(buffer);
|
|
if (i > maxSize) {
|
|
throw new DecoderException(i + " elements exceeded max size of: " + maxSize);
|
|
} else {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
static void writeCount(ByteBuf buffer, int count, int maxSize) {
|
|
if (count > maxSize) {
|
|
throw new EncoderException(count + " elements exceeded max size of: " + maxSize);
|
|
} else {
|
|
VarInt.write(buffer, count);
|
|
}
|
|
}
|
|
|
|
static <B extends ByteBuf, V, C extends Collection<V>> StreamCodec<B, C> collection(IntFunction<C> factory, StreamCodec<? super B, V> codec) {
|
|
return collection(factory, codec, Integer.MAX_VALUE);
|
|
}
|
|
|
|
static <B extends ByteBuf, V, C extends Collection<V>> StreamCodec<B, C> collection(IntFunction<C> factory, StreamCodec<? super B, V> codec, int maxSize) {
|
|
return new StreamCodec<B, C>() {
|
|
public C decode(B byteBuf) {
|
|
int i = ByteBufCodecs.readCount(byteBuf, maxSize);
|
|
C collection = (C)factory.apply(Math.min(i, 65536));
|
|
|
|
for (int j = 0; j < i; j++) {
|
|
collection.add(codec.decode(byteBuf));
|
|
}
|
|
|
|
return collection;
|
|
}
|
|
|
|
public void encode(B byteBuf, C collection) {
|
|
ByteBufCodecs.writeCount(byteBuf, collection.size(), maxSize);
|
|
|
|
for (V object : collection) {
|
|
codec.encode(byteBuf, object);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
static <B extends ByteBuf, V, C extends Collection<V>> StreamCodec.CodecOperation<B, V, C> collection(IntFunction<C> factory) {
|
|
return streamCodec -> collection(factory, streamCodec);
|
|
}
|
|
|
|
static <B extends ByteBuf, V> StreamCodec.CodecOperation<B, V, List<V>> list() {
|
|
return streamCodec -> collection(ArrayList::new, streamCodec);
|
|
}
|
|
|
|
static <B extends ByteBuf, V> StreamCodec.CodecOperation<B, V, List<V>> list(int maxSize) {
|
|
return streamCodec -> collection(ArrayList::new, streamCodec, maxSize);
|
|
}
|
|
|
|
static <B extends ByteBuf, K, V, M extends Map<K, V>> StreamCodec<B, M> map(
|
|
IntFunction<? extends M> factory, StreamCodec<? super B, K> keyCodec, StreamCodec<? super B, V> valueCodec
|
|
) {
|
|
return map(factory, keyCodec, valueCodec, Integer.MAX_VALUE);
|
|
}
|
|
|
|
static <B extends ByteBuf, K, V, M extends Map<K, V>> StreamCodec<B, M> map(
|
|
IntFunction<? extends M> factory, StreamCodec<? super B, K> keyCodec, StreamCodec<? super B, V> valueCodec, int maxSize
|
|
) {
|
|
return new StreamCodec<B, M>() {
|
|
public void encode(B byteBuf, M map) {
|
|
ByteBufCodecs.writeCount(byteBuf, map.size(), maxSize);
|
|
map.forEach((object, object2) -> {
|
|
keyCodec.encode(byteBuf, (K)object);
|
|
valueCodec.encode(byteBuf, (V)object2);
|
|
});
|
|
}
|
|
|
|
public M decode(B byteBuf) {
|
|
int i = ByteBufCodecs.readCount(byteBuf, maxSize);
|
|
M map = (M)factory.apply(Math.min(i, 65536));
|
|
|
|
for (int j = 0; j < i; j++) {
|
|
K object = keyCodec.decode(byteBuf);
|
|
V object2 = valueCodec.decode(byteBuf);
|
|
map.put(object, object2);
|
|
}
|
|
|
|
return map;
|
|
}
|
|
};
|
|
}
|
|
|
|
static <B extends ByteBuf, L, R> StreamCodec<B, Either<L, R>> either(StreamCodec<? super B, L> leftCodec, StreamCodec<? super B, R> rightCodec) {
|
|
return new StreamCodec<B, Either<L, R>>() {
|
|
public Either<L, R> decode(B byteBuf) {
|
|
return byteBuf.readBoolean() ? Either.left(leftCodec.decode(byteBuf)) : Either.right(rightCodec.decode(byteBuf));
|
|
}
|
|
|
|
public void encode(B byteBuf, Either<L, R> either) {
|
|
either.ifLeft(object -> {
|
|
byteBuf.writeBoolean(true);
|
|
leftCodec.encode(byteBuf, (L)object);
|
|
}).ifRight(object -> {
|
|
byteBuf.writeBoolean(false);
|
|
rightCodec.encode(byteBuf, (R)object);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
static <T> StreamCodec<ByteBuf, T> idMapper(IntFunction<T> idLookup, ToIntFunction<T> idGetter) {
|
|
return new StreamCodec<ByteBuf, T>() {
|
|
public T decode(ByteBuf byteBuf) {
|
|
int i = VarInt.read(byteBuf);
|
|
return (T)idLookup.apply(i);
|
|
}
|
|
|
|
public void encode(ByteBuf byteBuf, T object) {
|
|
int i = idGetter.applyAsInt(object);
|
|
VarInt.write(byteBuf, i);
|
|
}
|
|
};
|
|
}
|
|
|
|
static <T> StreamCodec<ByteBuf, T> idMapper(IdMap<T> idMap) {
|
|
return idMapper(idMap::byIdOrThrow, idMap::getIdOrThrow);
|
|
}
|
|
|
|
private static <T, R> StreamCodec<RegistryFriendlyByteBuf, R> registry(
|
|
ResourceKey<? extends Registry<T>> registryKey, Function<Registry<T>, IdMap<R>> idGetter
|
|
) {
|
|
return new StreamCodec<RegistryFriendlyByteBuf, R>() {
|
|
private IdMap<R> getRegistryOrThrow(RegistryFriendlyByteBuf registryFriendlyByteBuf) {
|
|
return (IdMap<R>)idGetter.apply(registryFriendlyByteBuf.registryAccess().lookupOrThrow(registryKey));
|
|
}
|
|
|
|
public R decode(RegistryFriendlyByteBuf registryFriendlyByteBuf) {
|
|
int i = VarInt.read(registryFriendlyByteBuf);
|
|
return (R)this.getRegistryOrThrow(registryFriendlyByteBuf).byIdOrThrow(i);
|
|
}
|
|
|
|
public void encode(RegistryFriendlyByteBuf registryFriendlyByteBuf, R object) {
|
|
int i = this.getRegistryOrThrow(registryFriendlyByteBuf).getIdOrThrow(object);
|
|
VarInt.write(registryFriendlyByteBuf, i);
|
|
}
|
|
};
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, T> registry(ResourceKey<? extends Registry<T>> registryKey) {
|
|
return registry(registryKey, registry -> registry);
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, Holder<T>> holderRegistry(ResourceKey<? extends Registry<T>> registryKey) {
|
|
return registry(registryKey, Registry::asHolderIdMap);
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, Holder<T>> holder(
|
|
ResourceKey<? extends Registry<T>> registryKey, StreamCodec<? super RegistryFriendlyByteBuf, T> codec
|
|
) {
|
|
return new StreamCodec<RegistryFriendlyByteBuf, Holder<T>>() {
|
|
private static final int DIRECT_HOLDER_ID = 0;
|
|
|
|
private IdMap<Holder<T>> getRegistryOrThrow(RegistryFriendlyByteBuf registryFriendlyByteBuf) {
|
|
return registryFriendlyByteBuf.registryAccess().lookupOrThrow(registryKey).asHolderIdMap();
|
|
}
|
|
|
|
public Holder<T> decode(RegistryFriendlyByteBuf registryFriendlyByteBuf) {
|
|
int i = VarInt.read(registryFriendlyByteBuf);
|
|
return i == 0 ? Holder.direct(codec.decode(registryFriendlyByteBuf)) : (Holder)this.getRegistryOrThrow(registryFriendlyByteBuf).byIdOrThrow(i - 1);
|
|
}
|
|
|
|
public void encode(RegistryFriendlyByteBuf registryFriendlyByteBuf, Holder<T> holder) {
|
|
switch (holder.kind()) {
|
|
case REFERENCE:
|
|
int i = this.getRegistryOrThrow(registryFriendlyByteBuf).getIdOrThrow(holder);
|
|
VarInt.write(registryFriendlyByteBuf, i + 1);
|
|
break;
|
|
case DIRECT:
|
|
VarInt.write(registryFriendlyByteBuf, 0);
|
|
codec.encode(registryFriendlyByteBuf, holder.value());
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
static <T> StreamCodec<RegistryFriendlyByteBuf, HolderSet<T>> holderSet(ResourceKey<? extends Registry<T>> registryKey) {
|
|
return new StreamCodec<RegistryFriendlyByteBuf, HolderSet<T>>() {
|
|
private static final int NAMED_SET = -1;
|
|
private final StreamCodec<RegistryFriendlyByteBuf, Holder<T>> holderCodec = ByteBufCodecs.holderRegistry(registryKey);
|
|
|
|
public HolderSet<T> decode(RegistryFriendlyByteBuf registryFriendlyByteBuf) {
|
|
int i = VarInt.read(registryFriendlyByteBuf) - 1;
|
|
if (i == -1) {
|
|
Registry<T> registry = registryFriendlyByteBuf.registryAccess().lookupOrThrow(registryKey);
|
|
return (HolderSet<T>)registry.get(TagKey.create(registryKey, ResourceLocation.STREAM_CODEC.decode(registryFriendlyByteBuf))).orElseThrow();
|
|
} else {
|
|
List<Holder<T>> list = new ArrayList(Math.min(i, 65536));
|
|
|
|
for (int j = 0; j < i; j++) {
|
|
list.add(this.holderCodec.decode(registryFriendlyByteBuf));
|
|
}
|
|
|
|
return HolderSet.direct(list);
|
|
}
|
|
}
|
|
|
|
public void encode(RegistryFriendlyByteBuf registryFriendlyByteBuf, HolderSet<T> holderSet) {
|
|
Optional<TagKey<T>> optional = holderSet.unwrapKey();
|
|
if (optional.isPresent()) {
|
|
VarInt.write(registryFriendlyByteBuf, 0);
|
|
ResourceLocation.STREAM_CODEC.encode(registryFriendlyByteBuf, ((TagKey)optional.get()).location());
|
|
} else {
|
|
VarInt.write(registryFriendlyByteBuf, holderSet.size() + 1);
|
|
|
|
for (Holder<T> holder : holderSet) {
|
|
this.holderCodec.encode(registryFriendlyByteBuf, holder);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|