Support dimensions in 1.16 (#893)

Fixes #893
This commit is contained in:
Dan Mulloy 2020-07-05 23:47:06 -04:00
parent fbe46f7bac
commit 8d991ad5a7
No known key found for this signature in database
GPG Key ID: 2B62F7DACFF133E8
4 changed files with 75 additions and 11 deletions

View File

@ -39,6 +39,7 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.utility.StreamSerializer;
import com.comphenix.protocol.wrappers.*;
import com.comphenix.protocol.wrappers.EnumWrappers.*;
@ -919,13 +920,20 @@ public class PacketContainer implements Serializable {
MinecraftKey.getConverter());
}
private static final boolean NEW_DIMENSIONS = MinecraftVersion.NETHER_UPDATE.atOrAbove();
/**
* Retrive a read/write structure for dimension IDs in 1.13.1+
* @return A modifier for dimension IDs
*/
public StructureModifier<Integer> getDimensions() {
// this isn't technically correct (and is, therefore, an inferior type of correct)
// but the resource keys are parameterized and we might have to modify structure modifier to support it
// or at least come up with a way to reflectively obtain ResourceKey<DimensionManager>
// TODO a more complete solution
return structureModifier.withType(
MinecraftReflection.getMinecraftClass("DimensionManager"),
NEW_DIMENSIONS ? MinecraftReflection.getMinecraftClass("ResourceKey") : MinecraftReflection.getMinecraftClass("DimensionManager"),
BukkitConverters.getDimensionIDConverter()
);
}

View File

@ -42,6 +42,9 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
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.MinecraftVersion;
import com.comphenix.protocol.wrappers.EnumWrappers.Dimension;
import com.comphenix.protocol.wrappers.EnumWrappers.FauxEnumConverter;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.base.Objects;
@ -1131,6 +1134,10 @@ public class BukkitConverters {
});
}
private static final boolean NEW_DIMENSION = MinecraftVersion.NETHER_UPDATE.atOrAbove();
private static Class<?> dimensionManager;
private static FauxEnumConverter<Dimension> dimensionConverter;
private static MethodAccessor dimensionFromId = null;
private static MethodAccessor idFromDimension = null;
@ -1138,14 +1145,26 @@ public class BukkitConverters {
return ignoreNull(new EquivalentConverter<Integer>() {
@Override
public Object getGeneric(Integer specific) {
if (dimensionManager == null) {
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
}
if (NEW_DIMENSION) {
if (dimensionConverter == null) {
dimensionConverter = new FauxEnumConverter<>(Dimension.class, dimensionManager);
}
Dimension dimension = Dimension.fromId(specific);
return dimensionConverter.getGeneric(dimension);
}
if (dimensionFromId == null) {
Class<?> clazz = MinecraftReflection.getMinecraftClass("DimensionManager");
FuzzyReflection reflection = FuzzyReflection.fromClass(clazz, false);
FuzzyReflection reflection = FuzzyReflection.fromClass(dimensionManager, false);
FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder()
.requireModifier(Modifier.STATIC)
.parameterExactType(int.class)
.returnTypeExact(clazz)
.returnTypeExact(dimensionManager)
.build();
dimensionFromId = Accessors.getMethodAccessor(reflection.getMethod(contract));
}
@ -1155,9 +1174,21 @@ public class BukkitConverters {
@Override
public Integer getSpecific(Object generic) {
if (dimensionManager == null) {
dimensionManager = MinecraftReflection.getNullableNMS("DimensionManager");
}
if (NEW_DIMENSION) {
if (dimensionConverter == null) {
dimensionConverter = new FauxEnumConverter<>(Dimension.class, dimensionManager);
}
Dimension dimension = dimensionConverter.getSpecific(generic);
return dimension.getId();
}
if (idFromDimension == null) {
Class<?> clazz = MinecraftReflection.getMinecraftClass("DimensionManager");
FuzzyReflection reflection = FuzzyReflection.fromClass(clazz, false);
FuzzyReflection reflection = FuzzyReflection.fromClass(dimensionManager, false);
FuzzyMethodContract contract = FuzzyMethodContract
.newBuilder()
.banModifier(Modifier.STATIC)

View File

@ -361,6 +361,31 @@ public abstract class EnumWrappers {
}
}
public enum Dimension {
OVERWORLD(0),
THE_NETHER(-1),
THE_END(1);
private final int id;
Dimension(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static Dimension fromId(int id) {
switch (id) {
case 0: return Dimension.OVERWORLD;
case -1: return Dimension.THE_NETHER;
case 1: return Dimension.THE_END;
default: throw new IllegalArgumentException("Invalid dimension ID: " + id);
}
}
}
private static Class<?> PROTOCOL_CLASS = null;
private static Class<?> CLIENT_COMMAND_CLASS = null;
private static Class<?> CHAT_VISIBILITY_CLASS = null;
@ -811,11 +836,11 @@ public abstract class EnumWrappers {
Validate.notNull(generic, "generic object cannot be null");
return lookup.computeIfAbsent(generic, x -> {
for (Field field : genericClass.getFields()) {
for (Field field : genericClass.getDeclaredFields()) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
// if (!field.isAccessible()) {
// field.setAccessible(true);
//}
if (field.get(null) == generic) {
return Enum.valueOf(specificClass, field.getName().toUpperCase());

View File

@ -500,7 +500,7 @@ public class PacketContainerTest {
assertEquals(container.getEnumModifier(Action.class, PacketPlayOutBoss.Action.class).read(0), Action.UPDATE_PCT);
}
// @Test
@Test
public void testDimensionManager() {
PacketContainer container = new PacketContainer(PacketType.Play.Server.RESPAWN);
container.getDimensions().write(0, 1);