fix nbt stuff - it compiles 🎉

This commit is contained in:
Pasqual Koschmieder 2023-09-22 20:12:43 +02:00 committed by Dan Mulloy
parent 75b678b921
commit 9ae751071e
2 changed files with 91 additions and 27 deletions

View File

@ -4,6 +4,7 @@ import com.comphenix.protocol.injector.netty.NettyByteBufAdapter;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.comphenix.protocol.wrappers.nbt.NbtType; import com.comphenix.protocol.wrappers.nbt.NbtType;
@ -93,13 +94,24 @@ public class StreamSerializer {
*/ */
public void serializeCompound(DataOutputStream output, NbtCompound compound) { public void serializeCompound(DataOutputStream output, NbtCompound compound) {
if (WRITE_NBT_METHOD == null) { if (WRITE_NBT_METHOD == null) {
WRITE_NBT_METHOD = Accessors.getMethodAccessor(FuzzyReflection FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true);
.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true) if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
.getMethodByParameters("writeNbtCompound", MinecraftReflection.getNBTCompoundClass())); FuzzyMethodContract writeNbtContract = FuzzyMethodContract.newBuilder()
.returnTypeExact(MinecraftReflection.getPacketDataSerializerClass())
.parameterExactArray(MinecraftReflection.getNBTBaseClass())
.build();
WRITE_NBT_METHOD = Accessors.getMethodAccessor(fuzzy.getMethod(writeNbtContract));
} else {
WRITE_NBT_METHOD = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("writeNbtCompound", MinecraftReflection.getNBTCompoundClass()));
}
} }
ByteBuf buf = NettyByteBufAdapter.packetWriter(output); ByteBuf buf = NettyByteBufAdapter.packetWriter(output);
buf.writeByte(NbtType.TAG_COMPOUND.getRawID());
// 1.20.2+ will write the id automatically
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
buf.writeByte(NbtType.TAG_COMPOUND.getRawID());
}
// Get the NMS version of the compound // Get the NMS version of the compound
Object handle = compound != null ? NbtFactory.fromBase(compound).getHandle() : null; Object handle = compound != null ? NbtFactory.fromBase(compound).getHandle() : null;

View File

@ -4,7 +4,9 @@ import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.accessors.Accessors; import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.nbt.NbtBase; import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.comphenix.protocol.wrappers.nbt.NbtFactory;
@ -22,13 +24,10 @@ public class NbtBinarySerializer {
public static final NbtBinarySerializer DEFAULT = new NbtBinarySerializer(); public static final NbtBinarySerializer DEFAULT = new NbtBinarySerializer();
private static final Class<?> NBT_BASE_CLASS = MinecraftReflection.getNBTBaseClass(); private static final Class<?> NBT_BASE_CLASS = MinecraftReflection.getNBTBaseClass();
// Used to read and write NBT
private static MethodAccessor methodWrite;
/** /**
* Method selected for loading NBT compounds. * Method selected for loading/writing NBT compounds.
*/ */
private static LoadMethod loadMethod; private static CodecMethod codecMethod;
private static MethodAccessor getNbtLoadMethod(Class<?>... parameters) { private static MethodAccessor getNbtLoadMethod(Class<?>... parameters) {
Method method = getUtilityClass().getMethodByReturnTypeAndParameters("load", NBT_BASE_CLASS, parameters); Method method = getUtilityClass().getMethodByReturnTypeAndParameters("load", NBT_BASE_CLASS, parameters);
@ -39,6 +38,18 @@ public class NbtBinarySerializer {
return FuzzyReflection.fromClass(MinecraftReflection.getNbtCompressedStreamToolsClass(), true); return FuzzyReflection.fromClass(MinecraftReflection.getNbtCompressedStreamToolsClass(), true);
} }
private static CodecMethod getCodecMethod() {
if (codecMethod == null) {
// Save the selected method
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
codecMethod = new LoadMethodConfigPhaseUpdate();
} else {
codecMethod = new LoadMethodSkinUpdate();
}
}
return codecMethod;
}
/** /**
* Write the content of a wrapped NBT tag to a stream. * Write the content of a wrapped NBT tag to a stream.
* *
@ -47,14 +58,7 @@ public class NbtBinarySerializer {
* @param destination - the destination stream. * @param destination - the destination stream.
*/ */
public <T> void serialize(NbtBase<T> value, DataOutput destination) { public <T> void serialize(NbtBase<T> value, DataOutput destination) {
if (methodWrite == null) { getCodecMethod().writeNbt(NbtFactory.fromBase(value).getHandle(), destination);
Class<?> base = MinecraftReflection.getNBTBaseClass();
Method writeNBT = getUtilityClass().getMethodByParameters("writeNBT", base, DataOutput.class);
methodWrite = Accessors.getMethodAccessor(writeNBT);
}
methodWrite.invoke(null, NbtFactory.fromBase(value).getHandle(), destination);
} }
/** /**
@ -65,13 +69,8 @@ public class NbtBinarySerializer {
* @return An NBT tag. * @return An NBT tag.
*/ */
public <TType> NbtWrapper<TType> deserialize(DataInput source) { public <TType> NbtWrapper<TType> deserialize(DataInput source) {
if (loadMethod == null) {
// Save the selected method
loadMethod = new LoadMethodSkinUpdate();
}
try { try {
return NbtFactory.fromNMS(loadMethod.loadNbt(source), null); return NbtFactory.fromNMS(getCodecMethod().loadNbt(source), null);
} catch (Exception e) { } catch (Exception e) {
throw new FieldAccessException("Unable to read NBT from " + source, e); throw new FieldAccessException("Unable to read NBT from " + source, e);
} }
@ -100,7 +99,7 @@ public class NbtBinarySerializer {
return (NbtList<T>) (NbtBase<?>) this.deserialize(source); return (NbtList<T>) (NbtBase<?>) this.deserialize(source);
} }
private interface LoadMethod { private interface CodecMethod {
/** /**
* Load an NBT compound from a given stream. * Load an NBT compound from a given stream.
@ -109,20 +108,73 @@ public class NbtBinarySerializer {
* @return The loaded NBT compound. * @return The loaded NBT compound.
*/ */
Object loadNbt(DataInput input); Object loadNbt(DataInput input);
/**
* Write an NBT compound to the given stream.
*
* @param nbt the nbt to write.
* @param target the target to write the compound to.
*/
void writeNbt(Object nbt, DataOutput target);
} }
/** /**
* Load an NBT compound from the NBTCompressedStreamTools static method since 1.7. * Load an NBT compound from the NBTCompressedStreamTools static method since 1.7.
*/ */
private static class LoadMethodSkinUpdate implements LoadMethod { private static class LoadMethodSkinUpdate implements CodecMethod {
private final Class<?> readLimitClass = MinecraftReflection.getNBTReadLimiterClass(); private final Class<?> readLimitClass = MinecraftReflection.getNBTReadLimiterClass();
private final Object readLimiter = FuzzyReflection.fromClass(this.readLimitClass).getSingleton(); private final Object readLimiter = FuzzyReflection.fromClass(this.readLimitClass).getSingleton();
private final MethodAccessor accessor = getNbtLoadMethod(DataInput.class, int.class, this.readLimitClass); private final MethodAccessor readNbt = getNbtLoadMethod(DataInput.class, int.class, this.readLimitClass);
private final MethodAccessor writeNBT = Accessors.getMethodAccessor(getUtilityClass().getMethodByParameters("writeNBT", MinecraftReflection.getNBTBaseClass(), DataOutput.class));
@Override @Override
public Object loadNbt(DataInput input) { public Object loadNbt(DataInput input) {
return this.accessor.invoke(null, input, 0, this.readLimiter); return this.readNbt.invoke(null, input, 0, this.readLimiter);
}
@Override
public void writeNbt(Object nbt, DataOutput target) {
this.writeNBT.invoke(null, nbt, target);
}
}
/**
* Load an NBT compound from the NBTCompressedStreamTools static method since 1.20.2.
*/
private static class LoadMethodConfigPhaseUpdate implements CodecMethod {
private final Class<?> readLimitClass = MinecraftReflection.getNBTReadLimiterClass();
private final Object readLimiter = FuzzyReflection.fromClass(this.readLimitClass).getSingleton();
private final MethodAccessor readNbt;
private final MethodAccessor writeNbt;
public LoadMethodConfigPhaseUpdate() {
// there are now two methods with the same signature: readAnyTag/readUnnamedTag & writeAnyTag/writeUnnamedTag
// we can only find the correct method here by using the method name... thanks Mojang
Method readNbtMethod = getUtilityClass().getMethod(FuzzyMethodContract.newBuilder()
.nameExact("b")
.returnTypeExact(MinecraftReflection.getNBTBaseClass())
.parameterExactArray(DataInput.class, this.readLimitClass)
.build());
this.readNbt = Accessors.getMethodAccessor(readNbtMethod);
Method writeNbtMethod = getUtilityClass().getMethod(FuzzyMethodContract.newBuilder()
.nameExact("a")
.parameterExactArray(MinecraftReflection.getNBTBaseClass(), DataOutput.class)
.build());
this.writeNbt = Accessors.getMethodAccessor(writeNbtMethod);
}
@Override
public Object loadNbt(DataInput input) {
return this.readNbt.invoke(null, input, this.readLimiter);
}
@Override
public void writeNbt(Object nbt, DataOutput target) {
this.writeNbt.invoke(null, nbt, target);
} }
} }
} }