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.
* @param keyConverter Converter for map keys

View File

@ -1856,6 +1856,16 @@ public class MinecraftReflection {
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() {
try {
return getMinecraftClass("PacketPlayOutUpdateSign") != null;

View File

@ -17,10 +17,7 @@
package com.comphenix.protocol.wrappers;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.*;
import java.util.*;
import java.util.Map.Entry;
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.FieldAccessor;
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.utility.MinecraftReflection;
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);
}
@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.
* @author dmulloy2