Update to 1.13.1, rework cloning, fix a particle NPE

This commit is contained in:
Dan Mulloy 2018-09-15 14:32:18 -04:00
parent 8ec31d83db
commit 776ec56a2d
25 changed files with 205 additions and 182 deletions

View File

@ -21,20 +21,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.function.Supplier;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.MinecraftKey;
import com.comphenix.protocol.wrappers.WrappedBlockData;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import com.comphenix.protocol.wrappers.*;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.comphenix.protocol.wrappers.nbt.NbtWrapper;
import com.google.common.collect.Maps;
/**
@ -43,62 +37,56 @@ import com.google.common.collect.Maps;
* @author Kristian
*/
public class BukkitCloner implements Cloner {
// List of classes we support
private final Map<Integer, Class<?>> clonableClasses = Maps.newConcurrentMap();
private static final Map<Class<?>, Function<Object, Object>> CLONERS = Maps.newConcurrentMap();
public BukkitCloner() {
addClass(0, MinecraftReflection.getItemStackClass());
addClass(1, MinecraftReflection.getDataWatcherClass());
// Try to add position classes
private static void fromWrapper(Supplier<Class<?>> getClass, Function<Object, ClonableWrapper> fromHandle) {
try {
addClass(2, MinecraftReflection.getBlockPositionClass());
} catch (Throwable ex) {
}
try {
addClass(3, MinecraftReflection.getChunkPositionClass());
} catch (Throwable ex) {
}
if (MinecraftReflection.isUsingNetty()) {
addClass(4, MinecraftReflection.getServerPingClass());
}
if (MinecraftReflection.watcherObjectExists()) {
addClass(5, MinecraftReflection.getDataWatcherSerializerClass());
addClass(6, MinecraftReflection.getMinecraftKeyClass());
}
try {
addClass(7, MinecraftReflection.getIBlockDataClass());
} catch (Throwable ex) {
}
try {
addClass(8, MinecraftReflection.getNonNullListClass());
} catch (Throwable ex) {
}
try {
addClass(9, MinecraftReflection.getNBTBaseClass());
} catch (Throwable ex) { }
Class<?> nmsClass = getClass.get();
if (nmsClass != null) {
CLONERS.put(nmsClass, nmsObject -> fromHandle.apply(nmsObject).deepClone().getHandle());
}
} catch (RuntimeException ignored) { }
}
private void addClass(int id, Class<?> clazz) {
if (clazz != null)
clonableClasses.put(id, clazz);
private static void fromConverter(Supplier<Class<?>> getClass, EquivalentConverter converter) {
try {
Class<?> nmsClass = getClass.get();
if (nmsClass != null) {
CLONERS.put(nmsClass, nmsObject -> converter.getGeneric(converter.getSpecific(nmsObject)));
}
} catch (RuntimeException ignored) { }
}
private int findMatchingClass(Class<?> type) {
// See if is a subclass of any of our supported superclasses
for (Entry<Integer, Class<?>> entry : clonableClasses.entrySet()) {
if (entry.getValue().isAssignableFrom(type)) {
return entry.getKey();
private static void fromManual(Supplier<Class<?>> getClass, Function<Object, Object> cloner) {
try {
Class<?> nmsClass = getClass.get();
if (nmsClass != null) {
CLONERS.put(nmsClass, cloner);
}
} catch (RuntimeException ignored) { }
}
static {
fromManual(MinecraftReflection::getItemStackClass, source ->
MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(source).clone()));
fromWrapper(MinecraftReflection::getDataWatcherClass, WrappedDataWatcher::new);
fromConverter(MinecraftReflection::getBlockPositionClass, BlockPosition.getConverter());
fromConverter(MinecraftReflection::getChunkPositionClass, ChunkPosition.getConverter());
fromWrapper(MinecraftReflection::getServerPingClass, WrappedServerPing::fromHandle);
fromConverter(MinecraftReflection::getMinecraftKeyClass, MinecraftKey.getConverter());
fromWrapper(MinecraftReflection::getIBlockDataClass, WrappedBlockData::fromHandle);
fromManual(MinecraftReflection::getNonNullListClass, source -> nonNullListCloner().clone(source));
fromWrapper(MinecraftReflection::getNBTBaseClass, NbtFactory::fromNMS);
}
private Function<Object, Object> findCloner(Class<?> type) {
for (Entry<Class<?>, Function<Object, Object>> entry : CLONERS.entrySet()) {
if (entry.getKey().isAssignableFrom(type)) {
return entry.getValue();
}
}
return -1;
return null;
}
@Override
@ -106,7 +94,7 @@ public class BukkitCloner implements Cloner {
if (source == null)
return false;
return findMatchingClass(source.getClass()) >= 0;
return findCloner(source.getClass()) != null;
}
@Override
@ -114,43 +102,12 @@ public class BukkitCloner implements Cloner {
if (source == null)
throw new IllegalArgumentException("source cannot be NULL.");
// Convert to a wrapper
switch (findMatchingClass(source.getClass())) {
case 0:
return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(source).clone());
case 1:
EquivalentConverter<WrappedDataWatcher> dataConverter = BukkitConverters.getDataWatcherConverter();
return dataConverter.getGeneric(dataConverter.getSpecific(source).deepClone());
case 2:
EquivalentConverter<BlockPosition> blockConverter = BlockPosition.getConverter();
return blockConverter.getGeneric(blockConverter.getSpecific(source));
case 3:
EquivalentConverter<ChunkPosition> chunkConverter = ChunkPosition.getConverter();
return chunkConverter.getGeneric(chunkConverter.getSpecific(source));
case 4:
EquivalentConverter<WrappedServerPing> serverConverter = BukkitConverters.getWrappedServerPingConverter();
return serverConverter.getGeneric(serverConverter.getSpecific(source).deepClone());
case 5:
return source;
case 6:
EquivalentConverter<MinecraftKey> keyConverter = MinecraftKey.getConverter();
return keyConverter.getGeneric(keyConverter.getSpecific(source));
case 7:
EquivalentConverter<WrappedBlockData> blockDataConverter = BukkitConverters.getWrappedBlockDataConverter();
return blockDataConverter.getGeneric(blockDataConverter.getSpecific(source).deepClone());
case 8:
return nonNullListCloner().clone(source);
case 9:
NbtWrapper<?> clone = (NbtWrapper<?>) NbtFactory.fromNMS(source).deepClone();
return clone.getHandle();
default:
throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass());
}
return findCloner(source.getClass()).apply(source);
}
private static Constructor<?> nonNullList = null;
private static final Cloner nonNullListCloner() {
private static Cloner nonNullListCloner() {
return new Cloner() {
@Override
public boolean canClone(Object source) {

View File

@ -26,11 +26,15 @@ import java.net.URI;
import java.net.URL;
import java.security.PublicKey;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;
import javax.crypto.SecretKey;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.primitives.Primitives;
/**
@ -42,19 +46,41 @@ import com.google.common.primitives.Primitives;
*/
public class ImmutableDetector implements Cloner {
// Notable immutable classes we might encounter
private static final Class<?>[] immutableClasses = {
private static final Set<Class<?>> immutableClasses = ImmutableSet.of(
StackTraceElement.class, BigDecimal.class,
BigInteger.class, Locale.class, UUID.class,
URL.class, URI.class, Inet4Address.class,
Inet6Address.class, InetSocketAddress.class,
SecretKey.class, PublicKey.class
};
);
private static final Set<Class<?>> immutableNMS = Sets.newConcurrentHashSet();
static {
add(MinecraftReflection::getGameProfileClass);
add(MinecraftReflection::getDataWatcherSerializerClass);
add(() -> MinecraftReflection.getMinecraftClass("SoundEffect"));
add(MinecraftReflection::getBlockClass);
add(MinecraftReflection::getItemClass);
add(MinecraftReflection::getFluidTypeClass);
add(MinecraftReflection::getParticleTypeClass);
}
private static void add(Supplier<Class<?>> getClass) {
try {
Class<?> clazz = getClass.get();
if (clazz != null) {
immutableNMS.add(clazz);
}
} catch (RuntimeException ignored) { }
}
@Override
public boolean canClone(Object source) {
// Don't accept NULL
if (source == null)
if (source == null) {
return false;
}
return isImmutable(source.getClass());
}
@ -66,46 +92,35 @@ public class ImmutableDetector implements Cloner {
*/
public static boolean isImmutable(Class<?> type) {
// Cases that are definitely not true
if (type.isArray())
if (type.isArray()) {
return false;
}
// All primitive types
if (Primitives.isWrapperType(type) || String.class.equals(type))
if (Primitives.isWrapperType(type) || String.class.equals(type)) {
return true;
}
// May not be true, but if so, that kind of code is broken anyways
if (isEnumWorkaround(type))
return true;
for (Class<?> clazz : immutableClasses)
if (clazz.equals(type))
return true;
// Check for known immutable classes in 1.7.2
if (MinecraftReflection.isUsingNetty()) {
if (type.equals(MinecraftReflection.getGameProfileClass())) {
return true;
}
}
// Check for known immutable classes in 1.9
if (MinecraftReflection.watcherObjectExists()) {
if (type.equals(MinecraftReflection.getDataWatcherSerializerClass())
|| type.equals(MinecraftReflection.getMinecraftClass("SoundEffect"))) {
return true;
}
}
if (MinecraftReflection.is(MinecraftReflection.getBlockClass(), type)
|| MinecraftReflection.is(MinecraftReflection.getItemClass(), type)
|| MinecraftReflection.is(MinecraftReflection.getFluidTypeClass(), type)) {
if (isEnumWorkaround(type)) {
return true;
}
// No good way to clone lambdas
if (type.getName().contains("$$Lambda$")) {
return true;
}
if (immutableClasses.contains(type)) {
return true;
}
for (Class<?> clazz : immutableNMS) {
if (MinecraftReflection.is(clazz, type)) {
return true;
}
}
// Probably not
return false;
}
@ -113,10 +128,13 @@ public class ImmutableDetector implements Cloner {
// This is just great. Just great.
private static boolean isEnumWorkaround(Class<?> enumClass) {
while (enumClass != null) {
if (enumClass.isEnum())
if (enumClass.isEnum()) {
return true;
}
enumClass = enumClass.getSuperclass();
}
return false;
}

View File

@ -48,6 +48,7 @@ public class MinecraftProtocolVersion {
map.put(new MinecraftVersion(1, 12, 1), 338);
map.put(new MinecraftVersion(1, 12, 2), 340);
map.put(new MinecraftVersion(1, 13, 0), 393);
map.put(new MinecraftVersion(1, 13, 1), 401);
return map;
}

View File

@ -1156,6 +1156,10 @@ public class MinecraftReflection {
return getNullableNMS("FluidType");
}
public static Class<?> getParticleTypeClass() {
return getNullableNMS("ParticleType");
}
/**
* Retrieve the WorldType class.
* @return The WorldType class.
@ -1360,7 +1364,7 @@ public class MinecraftReflection {
public static Class<?> getDataWatcherSerializerClass() {
// TODO Implement a fallback
return getMinecraftClass("DataWatcherSerializer");
return getNullableNMS("DataWatcherSerializer");
}
public static Class<?> getDataWatcherRegistryClass() {

View File

@ -0,0 +1,7 @@
package com.comphenix.protocol.wrappers;
public interface ClonableWrapper {
Object getHandle();
ClonableWrapper deepClone();
}

View File

@ -33,7 +33,7 @@ import org.bukkit.Material;
* @author dmulloy2
*/
public abstract class WrappedBlockData extends AbstractWrapper {
public abstract class WrappedBlockData extends AbstractWrapper implements ClonableWrapper {
private static final Class<?> MAGIC_NUMBERS = MinecraftReflection.getCraftBukkitClass("util.CraftMagicNumbers");
private static final Class<?> IBLOCK_DATA = MinecraftReflection.getIBlockDataClass();
private static final Class<?> BLOCK = MinecraftReflection.getBlockClass();

View File

@ -42,7 +42,7 @@ import org.bukkit.inventory.ItemStack;
* Represents a DataWatcher
* @author dmulloy2
*/
public class WrappedDataWatcher extends AbstractWrapper implements Iterable<WrappedWatchableObject> {
public class WrappedDataWatcher extends AbstractWrapper implements Iterable<WrappedWatchableObject>, ClonableWrapper {
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherClass();
private static MethodAccessor GETTER = null;

View File

@ -91,6 +91,8 @@ public class WrappedParticle<T> {
}
public static WrappedParticle fromHandle(Object handle) {
ensureMethods();
Particle bukkit = (Particle) toBukkit.invoke(null, handle);
Object data = null;

View File

@ -40,7 +40,7 @@ import io.netty.handler.codec.base64.Base64;
* Represents a server ping packet data.
* @author Kristian
*/
public class WrappedServerPing extends AbstractWrapper {
public class WrappedServerPing extends AbstractWrapper implements ClonableWrapper {
private static Class<?> GAME_PROFILE = MinecraftReflection.getGameProfileClass();
private static Class<?> GAME_PROFILE_ARRAY = MinecraftReflection.getArrayClass(GAME_PROFILE);

View File

@ -18,6 +18,8 @@
package com.comphenix.protocol.wrappers.nbt;
import com.comphenix.protocol.wrappers.ClonableWrapper;
/**
* Represents a generic container for an NBT element.
* <p>
@ -26,7 +28,7 @@ package com.comphenix.protocol.wrappers.nbt;
* @author Kristian
* @param <TType> - type of the value that is stored.
*/
public interface NbtBase<TType> {
public interface NbtBase<TType> extends ClonableWrapper {
/**
* Accepts a NBT visitor.
* @param visitor - the hierarchical NBT visitor.
@ -78,10 +80,14 @@ public interface NbtBase<TType> {
* @param newValue - the new value of this tag.
*/
public abstract void setValue(TType newValue);
/**
* Clone the current NBT tag.
* @return The cloned tag.
*/
public abstract NbtBase<TType> deepClone();
default Object getHandle() {
return null;
}
}

View File

@ -19,6 +19,8 @@ package com.comphenix.protocol.wrappers.nbt;
import java.io.DataOutput;
import com.comphenix.protocol.wrappers.ClonableWrapper;
/**
* Indicates that this NBT wraps an underlying net.minecraft.server instance.
* <p>
@ -28,7 +30,7 @@ import java.io.DataOutput;
*
* @param <TType> - type of the value that is stored.
*/
public interface NbtWrapper<TType> extends NbtBase<TType> {
public interface NbtWrapper<TType> extends NbtBase<TType>, ClonableWrapper {
/**
* Retrieve the underlying net.minecraft.server instance.
* @return The NMS instance.

View File

@ -246,7 +246,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.19.1</version>
<version>2.21.0</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -51,11 +51,11 @@ import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.internal.TypeParameterMatcher;
import net.sf.cglib.proxy.Factory;
import org.apache.commons.lang3.Validate;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -478,7 +478,11 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
private void scheduleMainThread(final Object packetCopy) {
// Don't use BukkitExecutors for this - it has a bit of overhead
Bukkit.getScheduler().scheduleSyncDelayedTask(factory.getPlugin(), () -> invokeSendPacket(packetCopy));
Bukkit.getScheduler().scheduleSyncDelayedTask(factory.getPlugin(), () -> {
if (!closed) {
invokeSendPacket(packetCopy);
}
});
}
@Override
@ -644,6 +648,8 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
* @param packet - the packet to send.
*/
private void invokeSendPacket(Object packet) {
Validate.isTrue(!closed, "cannot send packets to a closed channel");
// Attempt to send the packet with NetworkMarker.handle(), or the PlayerConnection if its active
try {
if (player instanceof Factory) {
@ -694,8 +700,14 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
*/
private Object getPlayerConnection() {
if (playerConnection == null) {
playerConnection = MinecraftFields.getPlayerConnection(getPlayer());
Player player = getPlayer();
if (player == null) {
throw new IllegalStateException("cannot send packet to offline player" + (playerName != null ? " " + playerName : ""));
}
playerConnection = MinecraftFields.getPlayerConnection(player);
}
return playerConnection;
}
@ -714,7 +726,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
@Override
public Player getPlayer() {
if (player == null && playerName != null) {
return Bukkit.getPlayer(playerName);
return Bukkit.getPlayerExact(playerName);
}
return player;

View File

@ -4,14 +4,14 @@ import com.comphenix.protocol.utility.Constants;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import net.minecraft.server.v1_13_R1.DispenserRegistry;
import net.minecraft.server.v1_13_R2.DispenserRegistry;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_13_R1.CraftServer;
import org.bukkit.craftbukkit.v1_13_R1.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_13_R1.util.Versioning;
import org.bukkit.craftbukkit.v1_13_R2.CraftServer;
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.v1_13_R2.util.Versioning;
import static org.mockito.Mockito.*;
@ -21,13 +21,27 @@ import static org.mockito.Mockito.*;
* @author Kristian
*/
public class BukkitInitialization {
private static boolean initialized;
private static boolean packaged;
private static final BukkitInitialization instance = new BukkitInitialization();
private BukkitInitialization() {
System.out.println("Created new BukkitInitialization on " + Thread.currentThread().getName());
}
private boolean initialized;
private boolean packaged;
public static synchronized void initializePackage() {
instance.setPackage();
}
public static synchronized void initializeItemMeta() {
instance.initialize();
}
/**
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing
*/
public static void initializeItemMeta() {
private void initialize() {
if (!initialized) {
// Denote that we're done
initialized = true;
@ -62,7 +76,7 @@ public class BukkitInitialization {
/**
* Ensure that package names are correctly set up.
*/
public static void initializePackage() {
private void setPackage() {
if (!packaged) {
packaged = true;

View File

@ -25,9 +25,9 @@ import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import net.minecraft.server.v1_13_R1.EnumProtocol;
import net.minecraft.server.v1_13_R1.EnumProtocolDirection;
import net.minecraft.server.v1_13_R1.PacketLoginInStart;
import net.minecraft.server.v1_13_R2.EnumProtocol;
import net.minecraft.server.v1_13_R2.EnumProtocolDirection;
import net.minecraft.server.v1_13_R2.PacketLoginInStart;
import org.junit.BeforeClass;
import org.junit.Test;

View File

@ -36,8 +36,8 @@ import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.collect.Lists;
import net.minecraft.server.v1_13_R1.*;
import net.minecraft.server.v1_13_R1.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.server.v1_13_R2.*;
import net.minecraft.server.v1_13_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;

View File

@ -6,8 +6,8 @@ import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import net.minecraft.server.v1_13_R1.ItemStack;
import net.minecraft.server.v1_13_R1.NonNullList;
import net.minecraft.server.v1_13_R2.ItemStack;
import net.minecraft.server.v1_13_R2.NonNullList;
import org.junit.BeforeClass;
import org.junit.Test;

View File

@ -6,22 +6,22 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import net.minecraft.server.v1_13_R1.ChatComponentText;
import net.minecraft.server.v1_13_R1.ChunkCoordIntPair;
import net.minecraft.server.v1_13_R1.DataWatcher;
import net.minecraft.server.v1_13_R1.IBlockData;
import net.minecraft.server.v1_13_R1.IChatBaseComponent;
import net.minecraft.server.v1_13_R1.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_13_R1.NBTCompressedStreamTools;
import net.minecraft.server.v1_13_R1.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.server.v1_13_R1.PlayerConnection;
import net.minecraft.server.v1_13_R1.ServerPing;
import net.minecraft.server.v1_13_R1.ServerPing.ServerData;
import net.minecraft.server.v1_13_R1.ServerPing.ServerPingPlayerSample;
import net.minecraft.server.v1_13_R2.ChatComponentText;
import net.minecraft.server.v1_13_R2.ChunkCoordIntPair;
import net.minecraft.server.v1_13_R2.DataWatcher;
import net.minecraft.server.v1_13_R2.IBlockData;
import net.minecraft.server.v1_13_R2.IChatBaseComponent;
import net.minecraft.server.v1_13_R2.IChatBaseComponent.ChatSerializer;
import net.minecraft.server.v1_13_R2.NBTCompressedStreamTools;
import net.minecraft.server.v1_13_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.server.v1_13_R2.PlayerConnection;
import net.minecraft.server.v1_13_R2.ServerPing;
import net.minecraft.server.v1_13_R2.ServerPing.ServerData;
import net.minecraft.server.v1_13_R2.ServerPing.ServerPingPlayerSample;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_13_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_13_R2.inventory.CraftItemStack;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.junit.AfterClass;

View File

@ -6,7 +6,7 @@ import com.comphenix.protocol.BukkitInitialization;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import net.minecraft.server.v1_13_R1.IntHashMap;
import net.minecraft.server.v1_13_R2.IntHashMap;
import org.bukkit.ChatColor;
import org.bukkit.Material;

View File

@ -16,14 +16,14 @@ public class ChunkCoordIntPairTest {
@Test
public void test() {
net.minecraft.server.v1_13_R1.ChunkCoordIntPair pair = new net.minecraft.server.v1_13_R1.ChunkCoordIntPair(1, 2);
net.minecraft.server.v1_13_R2.ChunkCoordIntPair pair = new net.minecraft.server.v1_13_R2.ChunkCoordIntPair(1, 2);
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
assertEquals(1, specific.getChunkX());
assertEquals(2, specific.getChunkZ());
net.minecraft.server.v1_13_R1.ChunkCoordIntPair roundtrip =
(net.minecraft.server.v1_13_R1.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
net.minecraft.server.v1_13_R2.ChunkCoordIntPair roundtrip =
(net.minecraft.server.v1_13_R2.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
getGeneric(specific);
assertEquals(1, roundtrip.x);

View File

@ -2,12 +2,12 @@ package com.comphenix.protocol.wrappers;
import static org.junit.Assert.assertEquals;
import net.minecraft.server.v1_13_R1.EntityHuman.EnumChatVisibility;
import net.minecraft.server.v1_13_R1.EnumDifficulty;
import net.minecraft.server.v1_13_R1.EnumGamemode;
import net.minecraft.server.v1_13_R1.EnumProtocol;
import net.minecraft.server.v1_13_R1.PacketPlayInClientCommand.EnumClientCommand;
import net.minecraft.server.v1_13_R1.PacketPlayInUseEntity.EnumEntityUseAction;
import net.minecraft.server.v1_13_R2.EntityHuman.EnumChatVisibility;
import net.minecraft.server.v1_13_R2.EnumDifficulty;
import net.minecraft.server.v1_13_R2.EnumGamemode;
import net.minecraft.server.v1_13_R2.EnumProtocol;
import net.minecraft.server.v1_13_R2.PacketPlayInClientCommand.EnumClientCommand;
import net.minecraft.server.v1_13_R2.PacketPlayInUseEntity.EnumEntityUseAction;
import org.junit.BeforeClass;
import org.junit.Test;

View File

@ -6,9 +6,9 @@ import static org.junit.Assert.assertTrue;
import java.util.List;
import net.minecraft.server.v1_13_R1.AttributeModifier;
import net.minecraft.server.v1_13_R1.PacketPlayOutUpdateAttributes;
import net.minecraft.server.v1_13_R1.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import net.minecraft.server.v1_13_R2.AttributeModifier;
import net.minecraft.server.v1_13_R2.PacketPlayOutUpdateAttributes;
import net.minecraft.server.v1_13_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot;
import org.junit.Before;
import org.junit.BeforeClass;

View File

@ -23,10 +23,10 @@ import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
import net.minecraft.server.v1_13_R1.EntityEgg;
import net.minecraft.server.v1_13_R2.EntityEgg;
import org.bukkit.craftbukkit.v1_13_R1.entity.CraftEgg;
import org.bukkit.craftbukkit.v1_13_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftEgg;
import org.bukkit.craftbukkit.v1_13_R2.entity.CraftEntity;
import org.junit.BeforeClass;
import org.junit.Test;
@ -87,8 +87,8 @@ public class WrappedDataWatcherTest {
@Test
public void testSerializers() {
Serializer blockPos = Registry.get(net.minecraft.server.v1_13_R1.BlockPosition.class, false);
Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_13_R1.BlockPosition.class, true);
Serializer blockPos = Registry.get(net.minecraft.server.v1_13_R2.BlockPosition.class, false);
Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_13_R2.BlockPosition.class, true);
assertNotSame(blockPos, optionalBlockPos);
// assertNull(Registry.get(ItemStack.class, false));

View File

@ -26,8 +26,8 @@ import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import net.minecraft.server.v1_13_R1.ItemStack;
import net.minecraft.server.v1_13_R1.Items;
import net.minecraft.server.v1_13_R2.ItemStack;
import net.minecraft.server.v1_13_R2.Items;
import org.junit.BeforeClass;
import org.junit.Test;

View File

@ -8,7 +8,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spigotVersion>1.13-R0.1-SNAPSHOT</spigotVersion>
<spigotVersion>1.13.1-R0.1-SNAPSHOT</spigotVersion>
</properties>
<modules>