Archiviert
13
0

Rewrite BukkitCloner to be more dynamic, fix some NPEs

Fixes #66
Dieser Commit ist enthalten in:
Dan Mulloy 2015-03-30 23:20:13 -04:00
Ursprung 0abe72d72b
Commit 992be51646

Datei anzeigen

@ -1,4 +1,4 @@
/* /**
* 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
* *
@ -14,18 +14,19 @@
* 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.cloning; package com.comphenix.protocol.reflect.cloning;
import java.util.List; import java.util.Map;
import java.util.Map.Entry;
import com.comphenix.protocol.reflect.EquivalentConverter; import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.WrappedDataWatcher; import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedServerPing; import com.comphenix.protocol.wrappers.WrappedServerPing;
import com.google.common.collect.Lists; import com.google.common.collect.Maps;
/** /**
* Represents an object that can clone a specific list of Bukkit- and Minecraft-related objects. * Represents an object that can clone a specific list of Bukkit- and Minecraft-related objects.
@ -34,68 +35,75 @@ import com.google.common.collect.Lists;
*/ */
public class BukkitCloner implements Cloner { public class BukkitCloner implements Cloner {
// List of classes we support // List of classes we support
private Class<?>[] clonableClasses; private final Map<Integer, Class<?>> clonableClasses = Maps.newConcurrentMap();
public BukkitCloner() { public BukkitCloner() {
List<Class<?>> classes = Lists.newArrayList(); addClass(0, MinecraftReflection.getItemStackClass());
addClass(1, MinecraftReflection.getDataWatcherClass());
classes.add(MinecraftReflection.getItemStackClass());
classes.add(MinecraftReflection.getDataWatcherClass());
// Try to add position classes // Try to add position classes
try { try {
classes.add(MinecraftReflection.getBlockPositionClass()); addClass(2, MinecraftReflection.getBlockPositionClass());
} catch (Throwable ex) { } } catch (Throwable ex) {
}
try { try {
classes.add(MinecraftReflection.getChunkPositionClass()); addClass(3, MinecraftReflection.getChunkPositionClass());
} catch (Throwable ex) { } } catch (Throwable ex) {
}
if (MinecraftReflection.isUsingNetty()) { if (MinecraftReflection.isUsingNetty()) {
classes.add(MinecraftReflection.getServerPingClass()); addClass(4, MinecraftReflection.getServerPingClass());
} }
this.clonableClasses = classes.toArray(new Class<?>[0]);
} }
private void addClass(int id, Class<?> clazz) {
if (clazz != null)
clonableClasses.put(id, clazz);
}
private int findMatchingClass(Class<?> type) { private int findMatchingClass(Class<?> type) {
// See if is a subclass of any of our supported superclasses // See if is a subclass of any of our supported superclasses
for (int i = 0; i < clonableClasses.length; i++) { for (Entry<Integer, Class<?>> entry : clonableClasses.entrySet()) {
if (clonableClasses[i].isAssignableFrom(type)) if (entry.getValue().isAssignableFrom(type)) {
return i; return entry.getKey();
}
} }
return -1; return -1;
} }
@Override @Override
public boolean canClone(Object source) { public boolean canClone(Object source) {
if (source == null) if (source == null)
return false; return false;
return findMatchingClass(source.getClass()) >= 0; return findMatchingClass(source.getClass()) >= 0;
} }
@Override @Override
public Object clone(Object source) { public Object clone(Object source) {
if (source == null) if (source == null)
throw new IllegalArgumentException("source cannot be NULL."); throw new IllegalArgumentException("source cannot be NULL.");
// Convert to a wrapper // Convert to a wrapper
switch (findMatchingClass(source.getClass())) { switch (findMatchingClass(source.getClass())) {
case 0: case 0:
return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(source).clone()); return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(source).clone());
case 1: case 1:
EquivalentConverter<ChunkPosition> chunkConverter = ChunkPosition.getConverter();
return chunkConverter.getGeneric(clonableClasses[1], chunkConverter.getSpecific(source));
case 2:
EquivalentConverter<WrappedDataWatcher> dataConverter = BukkitConverters.getDataWatcherConverter(); EquivalentConverter<WrappedDataWatcher> dataConverter = BukkitConverters.getDataWatcherConverter();
return dataConverter.getGeneric(clonableClasses[2], dataConverter.getSpecific(source).deepClone()); return dataConverter.getGeneric(clonableClasses.get(1), dataConverter.getSpecific(source).deepClone());
case 2:
EquivalentConverter<BlockPosition> blockConverter = BlockPosition.getConverter();
return blockConverter.getGeneric(clonableClasses.get(2), blockConverter.getSpecific(source));
case 3: case 3:
EquivalentConverter<ChunkPosition> chunkConverter = ChunkPosition.getConverter();
return chunkConverter.getGeneric(clonableClasses.get(3), chunkConverter.getSpecific(source));
case 4:
EquivalentConverter<WrappedServerPing> serverConverter = BukkitConverters.getWrappedServerPingConverter(); EquivalentConverter<WrappedServerPing> serverConverter = BukkitConverters.getWrappedServerPingConverter();
return serverConverter.getGeneric(clonableClasses[3], serverConverter.getSpecific(source).deepClone()); return serverConverter.getGeneric(clonableClasses.get(4), serverConverter.getSpecific(source).deepClone());
default: default:
throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass()); throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass());
} }
} }
} }