Ensure that the wrapped watchable object returns wrapped objects.
In addition, made it possible to construct watchable objects directly. Also fixed a bug preventing data watchers from creating new watchable objects.
Dieser Commit ist enthalten in:
Ursprung
f81e3262d0
Commit
2bd06922e0
@ -1,6 +1,7 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
@ -116,8 +117,7 @@ public class WrappedDataWatcher {
|
||||
*/
|
||||
public static Integer getTypeID(Class<?> clazz) throws FieldAccessException {
|
||||
initialize();
|
||||
|
||||
return typeMap.get(clazz);
|
||||
return typeMap.get(WrappedWatchableObject.getUnwrappedType(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,7 +145,7 @@ public class WrappedDataWatcher {
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public Byte getByte(int index) throws FieldAccessException {
|
||||
return (Byte) getObjectRaw(index);
|
||||
return (Byte) getObject(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,7 +155,7 @@ public class WrappedDataWatcher {
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public Short getShort(int index) throws FieldAccessException {
|
||||
return (Short) getObjectRaw(index);
|
||||
return (Short) getObject(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,7 +165,7 @@ public class WrappedDataWatcher {
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public Integer getInteger(int index) throws FieldAccessException {
|
||||
return (Integer) getObjectRaw(index);
|
||||
return (Integer) getObject(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,7 +175,7 @@ public class WrappedDataWatcher {
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public Float getFloat(int index) throws FieldAccessException {
|
||||
return (Float) getObjectRaw(index);
|
||||
return (Float) getObject(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,7 +185,7 @@ public class WrappedDataWatcher {
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public String getString(int index) throws FieldAccessException {
|
||||
return (String) getObjectRaw(index);
|
||||
return (String) getObject(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -215,25 +215,6 @@ public class WrappedDataWatcher {
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public Object getObject(int index) throws FieldAccessException {
|
||||
Object result = getObjectRaw(index);
|
||||
|
||||
// Handle the special cases too
|
||||
if (result instanceof net.minecraft.server.ItemStack) {
|
||||
return BukkitConverters.getItemStackConverter().getSpecific(result);
|
||||
} else if (result instanceof ChunkCoordinates) {
|
||||
return new WrappedChunkCoordinate((ChunkCoordinates) result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a watchable object by index.
|
||||
* @param index - index of the object to retrieve.
|
||||
* @return The watched object.
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
private Object getObjectRaw(int index) throws FieldAccessException {
|
||||
// The get method will take care of concurrency
|
||||
WatchableObject watchable = getWatchedObject(index);
|
||||
|
||||
@ -319,27 +300,7 @@ public class WrappedDataWatcher {
|
||||
* @param update - whether or not to refresh every listening clients.
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
public void setObject(int index, Object newValue, boolean update) throws FieldAccessException {
|
||||
// Convert special cases
|
||||
if (newValue instanceof WrappedChunkCoordinate)
|
||||
newValue = ((WrappedChunkCoordinate) newValue).getHandle();
|
||||
if (newValue instanceof ItemStack)
|
||||
newValue = BukkitConverters.getItemStackConverter().getGeneric(
|
||||
net.minecraft.server.ItemStack.class, (ItemStack) newValue);
|
||||
|
||||
// Next, set the object
|
||||
setObjectRaw(index, newValue, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a watchable object by index.
|
||||
* @param index - index of the object to retrieve.
|
||||
* @param newValue - the new watched value.
|
||||
* @param update - whether or not to refresh every listening clients.
|
||||
* @return The watched object.
|
||||
* @throws FieldAccessException Cannot read underlying field.
|
||||
*/
|
||||
private void setObjectRaw(int index, Object newValue, boolean update) throws FieldAccessException {
|
||||
public void setObject(int index, Object newValue, boolean update) throws FieldAccessException {
|
||||
// Aquire write lock
|
||||
Lock writeLock = getReadWriteLock().writeLock();
|
||||
writeLock.lock();
|
||||
@ -349,12 +310,22 @@ public class WrappedDataWatcher {
|
||||
|
||||
if (watchable != null) {
|
||||
new WrappedWatchableObject(watchable).setValue(newValue, update);
|
||||
} else {
|
||||
createKeyValueMethod.invoke(handle, index, WrappedWatchableObject.getUnwrapped(newValue));
|
||||
}
|
||||
} finally {
|
||||
|
||||
// Handle invoking the method
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new FieldAccessException("Cannot convert arguments.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Illegal access.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new FieldAccessException("Checked exception in Minecraft.", e);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private WatchableObject getWatchedObject(int index) throws FieldAccessException {
|
||||
// We use the get-method first and foremost
|
||||
if (getKeyValueMethod != null) {
|
||||
|
@ -5,6 +5,7 @@ import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
|
||||
import net.minecraft.server.ChunkCoordinates;
|
||||
import net.minecraft.server.ItemStack;
|
||||
import net.minecraft.server.WatchableObject;
|
||||
|
||||
@ -27,7 +28,35 @@ public class WrappedWatchableObject {
|
||||
// Type of the stored value
|
||||
private Class<?> typeClass;
|
||||
|
||||
/**
|
||||
* Wrap a given raw Minecraft watchable object.
|
||||
* @param handle - the raw watchable object to wrap.
|
||||
*/
|
||||
public WrappedWatchableObject(WatchableObject handle) {
|
||||
load(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a watchable object from an index and a given value.
|
||||
* @param index - the index.
|
||||
* @param value - non-null value of specific types.
|
||||
*/
|
||||
public WrappedWatchableObject(int index, Object value) {
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("Value cannot be NULL.");
|
||||
|
||||
// Get the correct type ID
|
||||
Integer typeID = WrappedDataWatcher.getTypeID(value.getClass());
|
||||
|
||||
if (typeID != null) {
|
||||
load(new WatchableObject(typeID, index, getUnwrapped(value)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot watch the type " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap a NMS object
|
||||
private void load(WatchableObject handle) {
|
||||
initialize();
|
||||
this.handle = handle;
|
||||
this.modifier = baseModifier.withTarget(handle);
|
||||
@ -57,6 +86,15 @@ public class WrappedWatchableObject {
|
||||
* @throws FieldAccessException Unable to read values.
|
||||
*/
|
||||
public Class<?> getType() throws FieldAccessException {
|
||||
return getWrappedType(getTypeRaw());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the correct super type of the current value, given the raw NMS object.
|
||||
* @return Super type.
|
||||
* @throws FieldAccessException Unable to read values.
|
||||
*/
|
||||
private Class<?> getTypeRaw() throws FieldAccessException {
|
||||
if (typeClass == null) {
|
||||
typeClass = WrappedDataWatcher.getTypeClass(getTypeID());
|
||||
|
||||
@ -131,7 +169,7 @@ public class WrappedWatchableObject {
|
||||
setDirtyState(true);
|
||||
|
||||
// Use the modifier to set the value
|
||||
modifier.withType(Object.class).write(0, newValue);
|
||||
modifier.withType(Object.class).write(0, getUnwrapped(newValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,7 +178,7 @@ public class WrappedWatchableObject {
|
||||
* @throws FieldAccessException Unable to use reflection.
|
||||
*/
|
||||
public Object getValue() throws FieldAccessException {
|
||||
return modifier.withType(Object.class).read(0);
|
||||
return getWrapped(modifier.withType(Object.class).read(0));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,6 +199,66 @@ public class WrappedWatchableObject {
|
||||
return modifier.<Boolean>withType(boolean.class).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the wrapped object value, if needed.
|
||||
* @param value - the raw NMS object to wrap.
|
||||
* @return The wrapped object.
|
||||
*/
|
||||
static Object getWrapped(Object value) {
|
||||
// Handle the special cases
|
||||
if (value instanceof net.minecraft.server.ItemStack) {
|
||||
return BukkitConverters.getItemStackConverter().getSpecific(value);
|
||||
} else if (value instanceof ChunkCoordinates) {
|
||||
return new WrappedChunkCoordinate((ChunkCoordinates) value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the wrapped type, if needed.
|
||||
* @param wrapped - the wrapped class type.
|
||||
* @return The wrapped class type.
|
||||
*/
|
||||
static Class<?> getWrappedType(Class<?> unwrapped) {
|
||||
if (unwrapped.equals(net.minecraft.server.ChunkPosition.class))
|
||||
return ChunkPosition.class;
|
||||
else if (unwrapped.equals(ChunkCoordinates.class))
|
||||
return WrappedChunkCoordinate.class;
|
||||
else
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw NMS value.
|
||||
* @param wrapped - the wrapped position.
|
||||
* @return The raw NMS object.
|
||||
*/
|
||||
static Object getUnwrapped(Object wrapped) {
|
||||
// Convert special cases
|
||||
if (wrapped instanceof WrappedChunkCoordinate)
|
||||
return ((WrappedChunkCoordinate) wrapped).getHandle();
|
||||
else if (wrapped instanceof ItemStack)
|
||||
return BukkitConverters.getItemStackConverter().getGeneric(
|
||||
net.minecraft.server.ItemStack.class, (org.bukkit.inventory.ItemStack) wrapped);
|
||||
else
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the unwrapped type, if needed.
|
||||
* @param wrapped - the unwrapped class type.
|
||||
* @return The unwrapped class type.
|
||||
*/
|
||||
static Class<?> getUnwrappedType(Class<?> wrapped) {
|
||||
if (wrapped.equals(ChunkPosition.class))
|
||||
return net.minecraft.server.ChunkPosition.class;
|
||||
else if (wrapped.equals(WrappedChunkCoordinate.class))
|
||||
return ChunkCoordinates.class;
|
||||
else
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the current wrapped watchable object, along with any contained objects.
|
||||
* @return A deep clone of the current watchable object.
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren