From 992be51646f1dd8d5d4038ba38e0f8568d786757 Mon Sep 17 00:00:00 2001 From: Dan Mulloy Date: Mon, 30 Mar 2015 23:20:13 -0400 Subject: [PATCH] Rewrite BukkitCloner to be more dynamic, fix some NPEs Fixes #66 --- .../reflect/cloning/BukkitCloner.java | 72 ++++++++++--------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java index 3098a60d..4a7372e7 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/cloning/BukkitCloner.java @@ -1,4 +1,4 @@ -/* +/** * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. * 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 * 02111-1307 USA */ - 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.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.BlockPosition; import com.comphenix.protocol.wrappers.BukkitConverters; import com.comphenix.protocol.wrappers.ChunkPosition; import com.comphenix.protocol.wrappers.WrappedDataWatcher; 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. @@ -34,68 +35,75 @@ import com.google.common.collect.Lists; */ public class BukkitCloner implements Cloner { // List of classes we support - private Class[] clonableClasses; - + private final Map> clonableClasses = Maps.newConcurrentMap(); + public BukkitCloner() { - List> classes = Lists.newArrayList(); - - classes.add(MinecraftReflection.getItemStackClass()); - classes.add(MinecraftReflection.getDataWatcherClass()); + addClass(0, MinecraftReflection.getItemStackClass()); + addClass(1, MinecraftReflection.getDataWatcherClass()); // Try to add position classes try { - classes.add(MinecraftReflection.getBlockPositionClass()); - } catch (Throwable ex) { } + addClass(2, MinecraftReflection.getBlockPositionClass()); + } catch (Throwable ex) { + } try { - classes.add(MinecraftReflection.getChunkPositionClass()); - } catch (Throwable ex) { } + addClass(3, MinecraftReflection.getChunkPositionClass()); + } catch (Throwable ex) { + } 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) { // See if is a subclass of any of our supported superclasses - for (int i = 0; i < clonableClasses.length; i++) { - if (clonableClasses[i].isAssignableFrom(type)) - return i; + for (Entry> entry : clonableClasses.entrySet()) { + if (entry.getValue().isAssignableFrom(type)) { + return entry.getKey(); + } } - + return -1; } - + @Override public boolean canClone(Object source) { if (source == null) return false; - + return findMatchingClass(source.getClass()) >= 0; } - + @Override public Object clone(Object source) { 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 chunkConverter = ChunkPosition.getConverter(); - return chunkConverter.getGeneric(clonableClasses[1], chunkConverter.getSpecific(source)); - case 2: EquivalentConverter 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 blockConverter = BlockPosition.getConverter(); + return blockConverter.getGeneric(clonableClasses.get(2), blockConverter.getSpecific(source)); case 3: + EquivalentConverter chunkConverter = ChunkPosition.getConverter(); + return chunkConverter.getGeneric(clonableClasses.get(3), chunkConverter.getSpecific(source)); + case 4: EquivalentConverter serverConverter = BukkitConverters.getWrappedServerPingConverter(); - return serverConverter.getGeneric(clonableClasses[3], serverConverter.getSpecific(source).deepClone()); + return serverConverter.getGeneric(clonableClasses.get(4), serverConverter.getSpecific(source).deepClone()); default: throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass()); } } -} +} \ No newline at end of file