Add converter for game state ids

Fixes #1041
This commit is contained in:
Dan Mulloy 2021-02-27 15:38:05 -05:00
parent a0bb11e1bd
commit 97972acee8
No known key found for this signature in database
GPG Key ID: BFACD592A5F0DFD6
4 changed files with 100 additions and 4 deletions

View File

@ -1017,6 +1017,17 @@ public class PacketContainer implements Serializable {
); );
} }
/**
* Retrieve a read/write structure for Game State IDs in 1.16+
* @return The Structure Modifier
*/
public StructureModifier<Integer> getGameStateIDs() {
return structureModifier.withType(
MinecraftReflection.getGameStateClass(),
BukkitConverters.getGameStateConverter()
);
}
/** /**
* Retrieve a read/write structure for the Map class. * Retrieve a read/write structure for the Map class.
* @param keyConverter Converter for map keys * @param keyConverter Converter for map keys

View File

@ -1856,6 +1856,16 @@ public class MinecraftReflection {
return getArrayClass(getMultiBlockChangeInfoClass()); return getArrayClass(getMultiBlockChangeInfoClass());
} }
/**
* Retrieve the PacketPlayOutGameStateChange.a class, aka GameState in 1.16
* @return The GameState class
*/
public static Class<?> getGameStateClass() {
// it's called "a" so there's not a whole lot we can do to identify it
Class<?> packetClass = PacketType.Play.Server.GAME_STATE_CHANGE.getPacketClass();
return packetClass.getClasses()[0];
}
public static boolean signUpdateExists() { public static boolean signUpdateExists() {
try { try {
return getMinecraftClass("PacketPlayOutUpdateSign") != null; return getMinecraftClass("PacketPlayOutUpdateSign") != null;

View File

@ -17,10 +17,7 @@
package com.comphenix.protocol.wrappers; package com.comphenix.protocol.wrappers;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Array; import java.lang.reflect.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -42,6 +39,7 @@ import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
import com.comphenix.protocol.reflect.accessors.FieldAccessor; import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor; import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract; 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.utility.MinecraftVersion;
@ -1461,4 +1459,73 @@ public class BukkitConverters {
} }
}); });
} }
private static Field gameStateMapField;
private static Field gameStateIdField;
public static EquivalentConverter<Integer> getGameStateConverter() {
return new EquivalentConverter<Integer>() {
@Override
public Object getGeneric(Integer specific) {
if (specific == null) {
specific = 0;
}
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
if (gameStateMapField == null) {
Class<?> stateClass = MinecraftReflection.getGameStateClass();
gameStateMapField = FuzzyReflection
.fromClass(stateClass, true)
.getField(FuzzyFieldContract
.newBuilder()
.typeDerivedOf(Map.class)
.build());
gameStateMapField.setAccessible(true);
}
try {
Map<Integer, Object> map = (Map<Integer, Object>) gameStateMapField.get(null);
return map.get(specific);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
} else {
return specific;
}
}
@Override
public Integer getSpecific(Object generic) {
if (generic == null) {
return 0;
}
if (MinecraftVersion.NETHER_UPDATE.atOrAbove()) {
if (gameStateIdField == null) {
Class<?> stateClass = MinecraftReflection.getGameStateClass();
gameStateIdField = FuzzyReflection
.fromClass(stateClass, true)
.getField(FuzzyFieldContract
.newBuilder()
.typeExact(int.class)
.build());
gameStateIdField.setAccessible(true);
}
try {
return (Integer) gameStateIdField.get(generic);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
} else {
return (Integer) generic;
}
}
@Override
public Class<Integer> getSpecificType() {
return Integer.class;
}
};
}
} }

View File

@ -565,6 +565,14 @@ public class PacketContainerTest {
assertNotSame(clone, packet); assertNotSame(clone, packet);
} }
@Test
public void testGameStateChange() {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.GAME_STATE_CHANGE);
assertTrue(packet.getGameStateIDs().read(0) == 0);
packet.getGameStateIDs().write(0, 2);
assertTrue(packet.getGameStateIDs().read(0) == 2);
}
/** /**
* Actions from the outbound Boss packet. Used for testing generic enums. * Actions from the outbound Boss packet. Used for testing generic enums.
* @author dmulloy2 * @author dmulloy2