Add mechanism to clone NonNullLists
Dieser Commit ist enthalten in:
Ursprung
684b687e42
Commit
7b61796506
@ -16,10 +16,14 @@
|
||||
*/
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
@ -67,6 +71,11 @@ public class BukkitCloner implements Cloner {
|
||||
addClass(7, MinecraftReflection.getIBlockDataClass());
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
addClass(8, MinecraftReflection.getNonNullListClass());
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
|
||||
private void addClass(int id, Class<?> clazz) {
|
||||
@ -122,8 +131,43 @@ public class BukkitCloner implements Cloner {
|
||||
case 7:
|
||||
EquivalentConverter<WrappedBlockData> blockDataConverter = BukkitConverters.getWrappedBlockDataConverter();
|
||||
return blockDataConverter.getGeneric(clonableClasses.get(7), blockDataConverter.getSpecific(source).deepClone());
|
||||
case 8:
|
||||
return nonNullListCloner().clone(source);
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private static Constructor<?> nonNullList = null;
|
||||
|
||||
private static final Cloner nonNullListCloner() {
|
||||
return new Cloner() {
|
||||
@Override
|
||||
public boolean canClone(Object source) {
|
||||
return MinecraftReflection.is(MinecraftReflection.getNonNullListClass(), source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone(Object source) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(source.getClass(), true).withTarget(source);
|
||||
List<?> list = (List<?>) modifier.read(0);
|
||||
Object empty = modifier.read(1);
|
||||
|
||||
if (nonNullList == null) {
|
||||
try {
|
||||
nonNullList = source.getClass().getDeclaredConstructor(List.class, Object.class);
|
||||
nonNullList.setAccessible(true);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Could not find NonNullList constructor", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return nonNullList.newInstance(new ArrayList<>(list), empty);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Could not create new NonNullList", ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1836,6 +1836,10 @@ public class MinecraftReflection {
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getNonNullListClass() {
|
||||
return getMinecraftClass("NonNullList");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a CraftItemStack from a given ItemStack.
|
||||
* @param bukkitItemStack - the Bukkit ItemStack to convert.
|
||||
|
@ -1,14 +1,20 @@
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.server.v1_11_R1.ItemStack;
|
||||
import net.minecraft.server.v1_11_R1.NonNullList;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
|
||||
public class AggregateClonerTest {
|
||||
|
||||
@ -22,4 +28,20 @@ public class AggregateClonerTest {
|
||||
List<Integer> input = Arrays.asList(1, 2, 3);
|
||||
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonNullList() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||
|
||||
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.a);
|
||||
packet.getModifier().write(1, list);
|
||||
|
||||
PacketContainer cloned = packet.deepClone();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
|
||||
|
||||
assertEquals(list.size(), list1.size());
|
||||
assertArrayEquals(list.toArray(), list1.toArray());
|
||||
}
|
||||
}
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren