Added a couple of useful methods to the wrappers.

This commit is contained in:
Kristian S. Stangeland 2012-11-13 15:11:54 +01:00
parent ad69b0caac
commit fec2734fe2
3 changed files with 76 additions and 6 deletions

View File

@ -19,8 +19,10 @@ import com.comphenix.protocol.reflect.compiler.StructureCompiler;
import com.comphenix.protocol.reflect.instances.CollectionGenerator; import com.comphenix.protocol.reflect.instances.CollectionGenerator;
import com.comphenix.protocol.reflect.instances.DefaultInstances; import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.reflect.instances.PrimitiveGenerator; import com.comphenix.protocol.reflect.instances.PrimitiveGenerator;
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.WrappedWatchableObject;
/** /**
* Used to fix ClassLoader leaks that may lead to filling up the permanent generation. * Used to fix ClassLoader leaks that may lead to filling up the permanent generation.
@ -48,7 +50,8 @@ class CleanupStaticMembers {
PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class, PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class,
BackgroundCompiler.class, StructureCompiler.class, BackgroundCompiler.class, StructureCompiler.class,
ObjectCloner.class, Packets.Server.class, Packets.Client.class, ObjectCloner.class, Packets.Server.class, Packets.Client.class,
ChunkPosition.class, WrappedDataWatcher.class ChunkPosition.class, WrappedDataWatcher.class, WrappedWatchableObject.class,
BukkitConverters.class
}; };
String[] internalClasses = { String[] internalClasses = {
@ -65,8 +68,7 @@ class CleanupStaticMembers {
"com.comphenix.protocol.injector.ReadPacketModifier", "com.comphenix.protocol.injector.ReadPacketModifier",
"com.comphenix.protocol.injector.StructureCache", "com.comphenix.protocol.injector.StructureCache",
"com.comphenix.protocol.reflect.compiler.BoxingHelper", "com.comphenix.protocol.reflect.compiler.BoxingHelper",
"com.comphenix.protocol.reflect.compiler.MethodDescriptor", "com.comphenix.protocol.reflect.compiler.MethodDescriptor"
"com.comphenix.protocol.wrappers.WrappedWatchableObject"
}; };
resetClasses(publicClasses); resetClasses(publicClasses);

View File

@ -3,6 +3,7 @@ package com.comphenix.protocol.wrappers;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -10,6 +11,7 @@ import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FieldAccessException;
@ -42,6 +44,9 @@ public class WrappedDataWatcher {
private static Method updateKeyValueMethod; private static Method updateKeyValueMethod;
private static Method getKeyValueMethod; private static Method getKeyValueMethod;
// Entity methods
private static Field entityDataField;
/** /**
* Whether or not this class has already been initialized. * Whether or not this class has already been initialized.
*/ */
@ -80,6 +85,20 @@ public class WrappedDataWatcher {
} }
} }
/**
* Create a new data watcher from a list of watchable objects.
* @param watchableObjects - list of watchable objects that will be copied.
* @throws FieldAccessException Unable to read watchable objects.
*/
public WrappedDataWatcher(List<WrappedWatchableObject> watchableObjects) throws FieldAccessException {
this();
// Fill the underlying map
for (WrappedWatchableObject watched : watchableObjects) {
setObject(watched.getIndex(), watched.getValue());
}
}
/** /**
* Retrieves the underlying data watcher. * Retrieves the underlying data watcher.
* @return The underlying data watcher. * @return The underlying data watcher.
@ -223,6 +242,32 @@ public class WrappedDataWatcher {
} }
} }
/**
* Retrieve every watchable object in this watcher.
* @return Every watchable object.
* @throws FieldAccessException If reflection failed.
*/
public List<WrappedWatchableObject> getWatchableObjects() throws FieldAccessException {
try {
getReadWriteLock().readLock().lock();
List<WrappedWatchableObject> result = new ArrayList<WrappedWatchableObject>();
// Add each watchable object to the list
for (Object watchable : getWatchableObjectMap().values()) {
if (watchable != null) {
result.add(new WrappedWatchableObject((WatchableObject) watchable));
} else {
result.add(null);
}
}
return result;
} finally {
getReadWriteLock().readLock().unlock();
}
}
/** /**
* Retrieve a copy of every index associated with a watched object. * Retrieve a copy of every index associated with a watched object.
* @return Every watched object index. * @return Every watched object index.
@ -361,6 +406,29 @@ public class WrappedDataWatcher {
return watchableObjects; return watchableObjects;
} }
/**
* Retrieve the data watcher associated with an entity.
* @param entity - the entity to read from.
* @return Associated data watcher.
* @throws FieldAccessException Reflection failed.
*/
public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException {
if (entityDataField == null)
entityDataField = FuzzyReflection.fromClass(Entity.class, true).getFieldByType("datawatcher", DataWatcher.class);
try {
Object nsmWatcher = FieldUtils.readField(entityDataField, entity, true);
if (nsmWatcher != null)
return new WrappedDataWatcher((DataWatcher) nsmWatcher);
else
return null;
} catch (IllegalAccessException e) {
throw new FieldAccessException("Cannot access DataWatcher field.", e);
}
}
/** /**
* Invoked when a data watcher is first used. * Invoked when a data watcher is first used.
*/ */

View File

@ -53,7 +53,7 @@ public class WrappedWatchableObject {
* @return Super type. * @return Super type.
* @throws FieldAccessException Unable to read values. * @throws FieldAccessException Unable to read values.
*/ */
public Class<?> getValueType() throws FieldAccessException { public Class<?> getType() throws FieldAccessException {
if (typeClass == null) { if (typeClass == null) {
typeClass = WrappedDataWatcher.getTypeClass(getTypeID()); typeClass = WrappedDataWatcher.getTypeClass(getTypeID());
@ -120,8 +120,8 @@ public class WrappedWatchableObject {
// Verify a few quick things // Verify a few quick things
if (newValue == null) if (newValue == null)
throw new IllegalArgumentException("Cannot watch a NULL value."); throw new IllegalArgumentException("Cannot watch a NULL value.");
if (!getValueType().isAssignableFrom(newValue.getClass())) if (!getType().isAssignableFrom(newValue.getClass()))
throw new IllegalArgumentException("Object " + newValue + " must be of type " + getValueType().getName()); throw new IllegalArgumentException("Object " + newValue + " must be of type " + getType().getName());
// See if we should update the client to // See if we should update the client to
if (updateClient) if (updateClient)