Improve cloning tests (#1822)
This commit is contained in:
parent
7fcfcdc365
commit
1beb95115f
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
package com.comphenix.protocol.injector;
|
package com.comphenix.protocol.injector;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
@ -26,13 +31,11 @@ import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
import com.comphenix.protocol.utility.ByteBuddyFactory;
|
||||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
import com.comphenix.protocol.utility.ZeroBuffer;
|
import com.comphenix.protocol.utility.ZeroBuffer;
|
||||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
|
||||||
import net.bytebuddy.implementation.FixedValue;
|
import net.bytebuddy.implementation.FixedValue;
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
import net.bytebuddy.matcher.ElementMatchers;
|
||||||
|
@ -52,33 +55,34 @@ public class StructureCache {
|
||||||
private static boolean TRICK_TRIED = false;
|
private static boolean TRICK_TRIED = false;
|
||||||
private static ConstructorAccessor TRICKED_DATA_SERIALIZER;
|
private static ConstructorAccessor TRICKED_DATA_SERIALIZER;
|
||||||
|
|
||||||
public static Object newPacket(Class<?> clazz) {
|
public static Object newPacket(Class<?> packetClass) {
|
||||||
Object result = DefaultInstances.DEFAULT.create(clazz);
|
Supplier<Object> packetConstructor = PACKET_INSTANCE_CREATORS.computeIfAbsent(packetClass, clazz -> {
|
||||||
|
// prefer construction via PacketDataSerializer constructor on 1.17 and above
|
||||||
if (result == null) {
|
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||||
return PACKET_INSTANCE_CREATORS.computeIfAbsent(clazz, $ -> {
|
ConstructorAccessor serializerAccessor = Accessors.getConstructorAccessorOrNull(
|
||||||
ConstructorAccessor accessor = Accessors.getConstructorAccessorOrNull(clazz,
|
clazz,
|
||||||
MinecraftReflection.getPacketDataSerializerClass());
|
MinecraftReflection.getPacketDataSerializerClass());
|
||||||
if (accessor != null) {
|
if (serializerAccessor != null) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
// the tricked serializer should always be present... If not try using a normal buffer
|
||||||
return accessor.invoke(MinecraftReflection.getPacketDataSerializer(new ZeroBuffer()));
|
Object dataSerializer = getTrickDataSerializerOrNull();
|
||||||
} catch (Exception exception) {
|
if (dataSerializer == null) {
|
||||||
// try trick nms around as they want a non-null compound in the map_chunk packet constructor
|
dataSerializer = MinecraftReflection.getPacketDataSerializer(new ZeroBuffer());
|
||||||
Object trickyDataSerializer = getTrickDataSerializerOrNull();
|
|
||||||
if (trickyDataSerializer != null) {
|
|
||||||
return accessor.invoke(trickyDataSerializer);
|
|
||||||
}
|
|
||||||
// the tricks are over
|
|
||||||
throw new IllegalArgumentException("Unable to create packet " + clazz, exception);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return serializerAccessor.invoke(dataSerializer);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("No matching constructor to create packet in class " + clazz);
|
}
|
||||||
}).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
// try via DefaultInstances as fallback
|
||||||
|
return () -> {
|
||||||
|
Object packetInstance = DefaultInstances.DEFAULT.create(clazz);
|
||||||
|
Objects.requireNonNull(packetInstance, "Unable to create packet instance for class " + clazz);
|
||||||
|
return packetInstance;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return packetConstructor.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,17 +117,15 @@ public class StructureCache {
|
||||||
public static StructureModifier<Object> getStructure(final PacketType packetType) {
|
public static StructureModifier<Object> getStructure(final PacketType packetType) {
|
||||||
Preconditions.checkNotNull(packetType, "type cannot be null");
|
Preconditions.checkNotNull(packetType, "type cannot be null");
|
||||||
|
|
||||||
StructureModifier<Object> modifier = STRUCTURE_MODIFIER_CACHE.computeIfAbsent(packetType, type -> {
|
return STRUCTURE_MODIFIER_CACHE.computeIfAbsent(packetType, type -> {
|
||||||
Class<?> packetClass = PacketRegistry.getPacketClassFromType(type);
|
Class<?> packetClass = PacketRegistry.getPacketClassFromType(type);
|
||||||
return new StructureModifier<>(packetClass, MinecraftReflection.getPacketClass(), true);
|
return new StructureModifier<>(packetClass, MinecraftReflection.getPacketClass(), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
return modifier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a null
|
* Creates a packet data serializer sub-class if needed to allow the fixed read of a NbtTagCompound because of a
|
||||||
* check in the MapChunk packet constructor.
|
* null check in the MapChunk packet constructor.
|
||||||
*
|
*
|
||||||
* @return an accessor to a constructor which creates a data serializer.
|
* @return an accessor to a constructor which creates a data serializer.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -269,13 +269,8 @@ public class StructureModifier<T> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't try to convert null, just return null
|
// get the field value and convert it if needed
|
||||||
Object fieldValue = accessor.get(this.target);
|
Object fieldValue = accessor.get(this.target);
|
||||||
if (fieldValue == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we need to convert the field value and do so if needed
|
|
||||||
return this.needConversion() ? this.converter.getSpecific(fieldValue) : (T) fieldValue;
|
return this.needConversion() ? this.converter.getSpecific(fieldValue) : (T) fieldValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,14 +327,10 @@ public class StructureModifier<T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// just write the value if the specific given one is null or no conversion is needed
|
|
||||||
if (value == null || !this.needConversion()) {
|
|
||||||
accessor.set(this.target, value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert and write
|
// convert and write
|
||||||
accessor.set(this.target, this.converter.getGeneric(value));
|
Object fieldValue = this.needConversion() ? this.converter.getGeneric(value) : value;
|
||||||
|
accessor.set(this.target, fieldValue);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,9 @@ public class ImmutableDetector implements Cloner {
|
||||||
add("world.entity.npc.VillagerProfession", "VillagerProfession");
|
add("world.entity.npc.VillagerProfession", "VillagerProfession");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add("world.entity.animal.CatVariant");
|
||||||
|
add("world.entity.animal.FrogVariant");
|
||||||
|
|
||||||
// TODO automatically detect the technically-not-an-enum enums that Mojang is so fond of
|
// TODO automatically detect the technically-not-an-enum enums that Mojang is so fond of
|
||||||
// Would also probably go in tandem with having the FieldCloner use this
|
// Would also probably go in tandem with having the FieldCloner use this
|
||||||
|
|
||||||
|
|
|
@ -2,55 +2,64 @@
|
||||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||||
* Copyright (C) 2012 Kristian S. Stangeland
|
* Copyright (C) 2012 Kristian S. Stangeland
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||||
* the License, or (at your option) any later version.
|
* the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
* See the GNU General Public License for more details.
|
* See the GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License along with this program;
|
* You should have received a copy of the GNU General Public License along with this program;
|
||||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
* 02111-1307 USA
|
* 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.comphenix.protocol.reflect.instances;
|
package com.comphenix.protocol.reflect.instances;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.google.common.base.Defaults;
|
import com.google.common.base.Defaults;
|
||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides constructors for primtive types, wrappers, arrays and strings.
|
* Provides constructors for primitive java types and wrappers.
|
||||||
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class PrimitiveGenerator implements InstanceProvider {
|
public class PrimitiveGenerator implements InstanceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default value for Strings.
|
* Default value for Strings.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static final String STRING_DEFAULT = "";
|
public static final String STRING_DEFAULT = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared instance of this generator.
|
* Shared instance of this generator.
|
||||||
*/
|
*/
|
||||||
public static PrimitiveGenerator INSTANCE = new PrimitiveGenerator(STRING_DEFAULT);
|
public static PrimitiveGenerator INSTANCE = new PrimitiveGenerator();
|
||||||
|
|
||||||
// Our default string value
|
// Our default string value
|
||||||
private String stringDefault;
|
private final String stringDefault;
|
||||||
|
|
||||||
|
public PrimitiveGenerator() {
|
||||||
|
this.stringDefault = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public PrimitiveGenerator(String stringDefault) {
|
public PrimitiveGenerator(String stringDefault) {
|
||||||
this.stringDefault = stringDefault;
|
this.stringDefault = stringDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the string default.
|
* Retrieve the string default.
|
||||||
|
*
|
||||||
* @return Default instance of a string.
|
* @return Default instance of a string.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getStringDefault() {
|
public String getStringDefault() {
|
||||||
return stringDefault;
|
return stringDefault;
|
||||||
}
|
}
|
||||||
|
@ -68,13 +77,16 @@ public class PrimitiveGenerator implements InstanceProvider {
|
||||||
return Array.newInstance(arrayType, 0);
|
return Array.newInstance(arrayType, 0);
|
||||||
} else if (type.isEnum()) {
|
} else if (type.isEnum()) {
|
||||||
Object[] values = type.getEnumConstants();
|
Object[] values = type.getEnumConstants();
|
||||||
if (values != null && values.length > 0)
|
if (values != null && values.length > 0) {
|
||||||
return values[0];
|
return values[0];
|
||||||
|
}
|
||||||
} else if (type.equals(String.class)) {
|
} else if (type.equals(String.class)) {
|
||||||
return stringDefault;
|
return this.stringDefault;
|
||||||
}
|
} else if (type.equals(Optional.class)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
// Cannot handle this type
|
// Cannot handle this type
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,7 +366,7 @@ public class ZeroBuffer extends ByteBuf {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short readUnsignedByte() {
|
public short readUnsignedByte() {
|
||||||
return 0;
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -35,6 +35,7 @@ import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||||
|
@ -67,6 +68,7 @@ import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||||
import net.minecraft.core.IRegistry;
|
import net.minecraft.core.IRegistry;
|
||||||
|
import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes;
|
||||||
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
import net.minecraft.network.protocol.game.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||||
import net.minecraft.resources.MinecraftKey;
|
import net.minecraft.resources.MinecraftKey;
|
||||||
|
@ -74,9 +76,8 @@ import net.minecraft.world.effect.MobEffect;
|
||||||
import net.minecraft.world.effect.MobEffectList;
|
import net.minecraft.world.effect.MobEffectList;
|
||||||
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
import net.minecraft.world.entity.ai.attributes.AttributeBase;
|
||||||
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
||||||
import net.minecraft.world.entity.npc.VillagerData;
|
import net.minecraft.world.entity.animal.CatVariant;
|
||||||
import net.minecraft.world.entity.npc.VillagerProfession;
|
import net.minecraft.world.entity.animal.FrogVariant;
|
||||||
import net.minecraft.world.entity.npc.VillagerType;
|
|
||||||
import org.apache.commons.lang.SerializationUtils;
|
import org.apache.commons.lang.SerializationUtils;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
@ -794,7 +795,7 @@ public class PacketContainerTest {
|
||||||
assertArrayEquals(signature, read.getSignature());
|
assertArrayEquals(signature, read.getSignature());
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
private void assertPacketsEqual(PacketContainer constructed, PacketContainer cloned) {
|
private void assertPacketsEqualAndSerializable(PacketContainer constructed, PacketContainer cloned) {
|
||||||
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
|
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
|
||||||
assertEquals(firstMod.size(), secondMod.size());
|
assertEquals(firstMod.size(), secondMod.size());
|
||||||
|
|
||||||
|
@ -810,6 +811,9 @@ public class PacketContainerTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object buffer = MinecraftReflection.createPacketDataSerializer(0);
|
||||||
|
MinecraftMethods.getPacketWriteByteBufMethod().invoke(cloned.getHandle(), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -833,32 +837,59 @@ public class PacketContainerTest {
|
||||||
new WrappedWatchableObject(
|
new WrappedWatchableObject(
|
||||||
new WrappedDataWatcherObject(0, Registry.get(Byte.class)),
|
new WrappedDataWatcherObject(0, Registry.get(Byte.class)),
|
||||||
(byte) 1),
|
(byte) 1),
|
||||||
|
new WrappedWatchableObject(
|
||||||
|
new WrappedDataWatcherObject(0, Registry.get(Integer.class)),
|
||||||
|
1),
|
||||||
|
new WrappedWatchableObject(
|
||||||
|
new WrappedDataWatcherObject(0, Registry.get(Float.class)),
|
||||||
|
1F),
|
||||||
new WrappedWatchableObject(
|
new WrappedWatchableObject(
|
||||||
new WrappedDataWatcherObject(0, Registry.get(String.class)),
|
new WrappedDataWatcherObject(0, Registry.get(String.class)),
|
||||||
"String"),
|
"String"),
|
||||||
new WrappedWatchableObject(
|
new WrappedWatchableObject(
|
||||||
new WrappedDataWatcherObject(0, Registry.get(Float.class)),
|
new WrappedDataWatcherObject(0, Registry.get(Boolean.class)),
|
||||||
1.0F),
|
true),
|
||||||
new WrappedWatchableObject(
|
new WrappedWatchableObject(
|
||||||
new WrappedDataWatcherObject(0, Registry.getChatComponentSerializer(true)),
|
new WrappedDataWatcherObject(0, Registry.getChatComponentSerializer(true)),
|
||||||
Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
|
Optional.of(ComponentConverter.fromBaseComponent(TEST_COMPONENT).getHandle())),
|
||||||
new WrappedWatchableObject(
|
new WrappedWatchableObject(
|
||||||
new WrappedDataWatcherObject(0, Registry.get(VillagerData.class)),
|
new WrappedDataWatcherObject(0, Registry.getItemStackSerializer(false)),
|
||||||
new VillagerData(VillagerType.b, VillagerProfession.c, 69))
|
BukkitConverters.getItemStackConverter().getGeneric(new ItemStack(Material.WOODEN_AXE))),
|
||||||
|
new WrappedWatchableObject(
|
||||||
|
new WrappedDataWatcherObject(0, Registry.get(CatVariant.class)),
|
||||||
|
CatVariant.a),
|
||||||
|
new WrappedWatchableObject(
|
||||||
|
new WrappedDataWatcherObject(0, Registry.get(FrogVariant.class)),
|
||||||
|
FrogVariant.c)
|
||||||
));
|
));
|
||||||
} else if (type == PacketType.Play.Server.CHAT) {
|
} else if (type == PacketType.Play.Server.CHAT) {
|
||||||
constructed.getChatComponents().write(0, ComponentConverter.fromBaseComponent(TEST_COMPONENT));
|
constructed.getChatComponents().write(0, ComponentConverter.fromBaseComponent(TEST_COMPONENT));
|
||||||
|
} else if (type == PacketType.Play.Server.REMOVE_ENTITY_EFFECT || type == PacketType.Play.Server.ENTITY_EFFECT) {
|
||||||
|
constructed.getEffectTypes().write(0, PotionEffectType.GLOWING);
|
||||||
|
} else if (type == PacketType.Play.Server.GAME_STATE_CHANGE) {
|
||||||
|
constructed.getStructures().write(
|
||||||
|
0,
|
||||||
|
InternalStructure.getConverter().getSpecific(PacketPlayOutGameStateChange.a));
|
||||||
|
} else if (type == PacketType.Play.Client.USE_ITEM || type == PacketType.Play.Client.BLOCK_PLACE) {
|
||||||
|
constructed.getLongs().write(0, 0L); // timestamp of the packet, not sent over the network
|
||||||
}
|
}
|
||||||
|
|
||||||
// gives some indication which cloning process fails as the checks itself are happening outside this method
|
// gives some indication which cloning process fails as the checks itself are happening outside this method
|
||||||
System.out.println("Cloning " + type);
|
System.out.println("Cloning " + type);
|
||||||
|
|
||||||
// Clone the packet both ways
|
// Clone the packet all three ways
|
||||||
PacketContainer shallowCloned = constructed.shallowClone();
|
PacketContainer shallowCloned = constructed.shallowClone();
|
||||||
this.assertPacketsEqual(constructed, shallowCloned);
|
this.assertPacketsEqualAndSerializable(constructed, shallowCloned);
|
||||||
|
|
||||||
PacketContainer deepCloned = constructed.deepClone();
|
PacketContainer deepCloned = constructed.deepClone();
|
||||||
this.assertPacketsEqual(constructed, deepCloned);
|
this.assertPacketsEqualAndSerializable(constructed, deepCloned);
|
||||||
|
|
||||||
|
PacketContainer serializedCloned = SerializableCloner.clone(constructed);
|
||||||
|
if (type == PacketType.Play.Client.USE_ITEM || type == PacketType.Play.Client.BLOCK_PLACE) {
|
||||||
|
// shit fix - but what are we supposed to do :/
|
||||||
|
serializedCloned.getLongs().write(0, 0L);
|
||||||
|
}
|
||||||
|
this.assertPacketsEqualAndSerializable(constructed, serializedCloned);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Assertions.fail("Unable to clone " + type, ex);
|
Assertions.fail("Unable to clone " + type, ex);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue