Fix a few issues with data watchers
Dieser Commit ist enthalten in:
Ursprung
9b838df17d
Commit
c2d028df4f
@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* 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) 2016 dmulloy2
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||||
@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
@ -37,47 +36,76 @@ import com.comphenix.protocol.reflect.FieldUtils;
|
|||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||||
|
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a DataWatcher in 1.9
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
public class WrappedDataWatcher extends AbstractWrapper implements Iterable<WrappedWatchableObject> {
|
public class WrappedDataWatcher extends AbstractWrapper implements Iterable<WrappedWatchableObject> {
|
||||||
private static MethodAccessor getter = null;
|
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherClass();
|
||||||
private static MethodAccessor setter = null;
|
|
||||||
|
|
||||||
private static Field MAP_FIELD = null;
|
private static MethodAccessor GETTER = null;
|
||||||
|
private static MethodAccessor SETTER = null;
|
||||||
|
|
||||||
|
private static FieldAccessor MAP_FIELD = null;
|
||||||
private static Field ENTITY_DATA_FIELD = null;
|
private static Field ENTITY_DATA_FIELD = null;
|
||||||
private static Field ENTITY_FIELD = null;
|
private static Field ENTITY_FIELD = null;
|
||||||
|
|
||||||
/**
|
private static ConstructorAccessor constructor = null;
|
||||||
* Constructs a new Data Watcher. This is currently unsupported in 1.9 and up due to changes in data watcher structure.
|
private static ConstructorAccessor lightningConstructor = null;
|
||||||
* Essentially, Mojang further tied data watchers to their entities.
|
|
||||||
* @deprecated
|
private static Object fakeEntity = null;
|
||||||
*/
|
|
||||||
@Deprecated
|
// ---- Construction
|
||||||
public WrappedDataWatcher() {
|
|
||||||
super(MinecraftReflection.getDataWatcherClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a wrapped data watcher around an existing NMS data watcher.
|
* Constructs a wrapped data watcher around an existing NMS data watcher.
|
||||||
* @param handle NMS data watcher
|
* @param handle NMS data watcher
|
||||||
*/
|
*/
|
||||||
public WrappedDataWatcher(Object handle) {
|
public WrappedDataWatcher(Object handle) {
|
||||||
this();
|
super(HANDLE_TYPE);
|
||||||
setHandle(handle);
|
setHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public Iterator<WrappedWatchableObject> iterator() {
|
* Constructs a new DataWatcher using a fake entity.
|
||||||
return getWatchableObjects().iterator();
|
*/
|
||||||
|
public WrappedDataWatcher() {
|
||||||
|
this(newHandle(fakeEntity()));
|
||||||
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WrappedWatchableObject> getWatchableObjects() {
|
private static Object newHandle(Object entity) {
|
||||||
return new ArrayList<>(asMap().values());
|
if (constructor == null) {
|
||||||
|
constructor = Accessors.getConstructorAccessor(HANDLE_TYPE, MinecraftReflection.getEntityClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
return constructor.invoke(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object fakeEntity() {
|
||||||
|
if (fakeEntity != null) {
|
||||||
|
return fakeEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can create a fake lightning strike without it affecting anything
|
||||||
|
if (lightningConstructor == null) {
|
||||||
|
lightningConstructor = Accessors.getConstructorAccessor(MinecraftReflection.getMinecraftClass("EntityLightning"),
|
||||||
|
MinecraftReflection.getNmsWorldClass(), double.class, double.class, double.class, boolean.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fakeEntity = lightningConstructor.invoke(null, 0, 0, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Collection Methods
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Map<Integer, WrappedWatchableObject> asMap() {
|
private Map<Integer, ?> getMap() {
|
||||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType, true);
|
FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType, true);
|
||||||
List<Field> candidates = fuzzy.getFieldListByType(Map.class);
|
List<Field> candidates = fuzzy.getFieldListByType(Map.class);
|
||||||
|
|
||||||
@ -86,8 +114,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
|||||||
// This is the entity class to current index map, which we really don't have a use for
|
// This is the entity class to current index map, which we really don't have a use for
|
||||||
} else {
|
} else {
|
||||||
// This is the map we're looking for
|
// This is the map we're looking for
|
||||||
MAP_FIELD = candidate;
|
MAP_FIELD = Accessors.getFieldAccessor(candidate);
|
||||||
MAP_FIELD.setAccessible(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,28 +122,69 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
|||||||
throw new FieldAccessException("Could not find index -> object map.");
|
throw new FieldAccessException("Could not find index -> object map.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Integer, ?> map = null;
|
return (Map<Integer, ?>) MAP_FIELD.get(handle);
|
||||||
|
}
|
||||||
try {
|
|
||||||
map = (Map<Integer, ?>) MAP_FIELD.get(handle);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
throw new FieldAccessException("Failed to access index -> object map", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the contents of this DataWatcher as a map.
|
||||||
|
* @return The contents
|
||||||
|
*/
|
||||||
|
public Map<Integer, WrappedWatchableObject> asMap() {
|
||||||
Map<Integer, WrappedWatchableObject> ret = new HashMap<>();
|
Map<Integer, WrappedWatchableObject> ret = new HashMap<>();
|
||||||
for (Entry<Integer, ?> entry : map.entrySet()) {
|
|
||||||
|
for (Entry<Integer, ?> entry : getMap().entrySet()) {
|
||||||
ret.put(entry.getKey(), new WrappedWatchableObject(entry.getValue()));
|
ret.put(entry.getKey(), new WrappedWatchableObject(entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WrappedWatchableObject getWatchableObject(int index) {
|
/**
|
||||||
return asMap().get(index);
|
* Gets a list of the contents of this DataWatcher.
|
||||||
|
* @return The contents
|
||||||
|
*/
|
||||||
|
public List<WrappedWatchableObject> getWatchableObjects() {
|
||||||
|
return new ArrayList<>(asMap().values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<WrappedWatchableObject> iterator() {
|
||||||
|
return getWatchableObjects().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the size of this DataWatcher's contents.
|
||||||
|
* @return The size
|
||||||
|
*/
|
||||||
public int size() {
|
public int size() {
|
||||||
return asMap().size();
|
return getMap().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clear() {
|
||||||
|
getMap().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the watchable object at a given index.
|
||||||
|
* @param index Index
|
||||||
|
* @return The watchable object, or null if none exists
|
||||||
|
*/
|
||||||
|
public WrappedWatchableObject getWatchableObject(int index) {
|
||||||
|
Object handle = getMap().get(index);
|
||||||
|
if (handle != null) {
|
||||||
|
return new WrappedWatchableObject(handle);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this DataWatcher has an object at a given index.
|
||||||
|
* @param index Index
|
||||||
|
* @return True if it does, false if not
|
||||||
|
*/
|
||||||
|
public boolean hasIndex(int index) {
|
||||||
|
return getMap().containsKey(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Object Getters
|
// ---- Object Getters
|
||||||
@ -206,27 +274,39 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Object getWatcherObject(WrappedDataWatcherObject watcherObject) {
|
private Object getWatcherObject(WrappedDataWatcherObject watcherObject) {
|
||||||
if (getter == null) {
|
if (GETTER == null) {
|
||||||
getter = Accessors.getMethodAccessor(handleType, "get", watcherObject.getHandleType());
|
GETTER = Accessors.getMethodAccessor(handleType, "get", watcherObject.getHandleType());
|
||||||
}
|
}
|
||||||
|
|
||||||
return getter.invoke(handle, watcherObject.getHandle());
|
return GETTER.invoke(handle, watcherObject.getHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Object Setters
|
// ---- Object Setters
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the DataWatcher Item at a given index to a new value.
|
||||||
|
* @param index Index
|
||||||
|
* @param value New value
|
||||||
|
*/
|
||||||
public void setObject(int index, Object value) {
|
public void setObject(int index, Object value) {
|
||||||
setObject(new WrappedDataWatcherObject(index, null), value);
|
setObject(new WrappedDataWatcherObject(index, null), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the DataWatcher Item associated with a given watcher object to a new value.
|
||||||
|
* @param watcherObject Associated watcher object
|
||||||
|
* @param value New value
|
||||||
|
*/
|
||||||
public void setObject(WrappedDataWatcherObject watcherObject, Object value) {
|
public void setObject(WrappedDataWatcherObject watcherObject, Object value) {
|
||||||
if (setter == null) {
|
if (SETTER == null) {
|
||||||
setter = Accessors.getMethodAccessor(handleType, "set", watcherObject.getHandleType(), Object.class);
|
SETTER = Accessors.getMethodAccessor(handleType, "set", watcherObject.getHandleType(), Object.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
setter.invoke(handle, watcherObject.getHandle(), WrappedWatchableObject.getUnwrapped(value));
|
SETTER.invoke(handle, watcherObject.getHandle(), WrappedWatchableObject.getUnwrapped(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Add support for setting the dirty state
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone the content of the current DataWatcher.
|
* Clone the content of the current DataWatcher.
|
||||||
*
|
*
|
||||||
@ -299,14 +379,22 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No longer supported in 1.9 due to the removal of a consistent type <-> ID map.
|
||||||
|
* @param clazz
|
||||||
|
* @return Null
|
||||||
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static Integer getTypeID(Class<?> clazz) {
|
public static Integer getTypeID(Class<?> clazz) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No longer supported in 1.9 due to the removal of a consistent type <-> ID map.
|
||||||
|
* @param typeID
|
||||||
|
* @return Null
|
||||||
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public static Class<?> getTypeClass(int typeID) {
|
public static Class<?> getTypeClass(int typeID) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -341,52 +429,75 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
|||||||
return getWatchableObjects().hashCode();
|
return getWatchableObjects().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a DataWatcherObject in 1.9.
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
public static class WrappedDataWatcherObject extends AbstractWrapper {
|
public static class WrappedDataWatcherObject extends AbstractWrapper {
|
||||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherObjectClass();
|
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherObjectClass();
|
||||||
private static Constructor<?> constructor = null;
|
private static ConstructorAccessor constructor = null;
|
||||||
|
|
||||||
private StructureModifier<Object> modifier = new StructureModifier<Object>(HANDLE_TYPE);
|
private final StructureModifier<Object> modifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new watcher object from a NMS handle
|
||||||
|
* @param handle NMS handle
|
||||||
|
*/
|
||||||
public WrappedDataWatcherObject(Object handle) {
|
public WrappedDataWatcherObject(Object handle) {
|
||||||
super(HANDLE_TYPE);
|
super(HANDLE_TYPE);
|
||||||
|
|
||||||
setHandle(handle);
|
setHandle(handle);
|
||||||
modifier.withTarget(handle);
|
this.modifier = new StructureModifier<Object>(HANDLE_TYPE).withTarget(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new watcher object from an index and serializer
|
||||||
|
* @param index Index
|
||||||
|
* @param serializer Serializer, see {@link Registry}
|
||||||
|
*/
|
||||||
public WrappedDataWatcherObject(int index, Serializer serializer) {
|
public WrappedDataWatcherObject(int index, Serializer serializer) {
|
||||||
this(newHandle(index, serializer));
|
this(newHandle(index, serializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object newHandle(int index, Serializer serializer) {
|
private static Object newHandle(int index, Serializer serializer) {
|
||||||
if (constructor == null) {
|
if (constructor == null) {
|
||||||
constructor = HANDLE_TYPE.getConstructors()[0];
|
constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object handle = serializer != null ? serializer.getHandle() : null;
|
Object handle = serializer != null ? serializer.getHandle() : null;
|
||||||
|
return constructor.invoke(index, handle);
|
||||||
try {
|
|
||||||
return constructor.newInstance(index, handle);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
throw new RuntimeException("Failed to create new DataWatcherObject", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this watcher object's index
|
||||||
|
* @return The index
|
||||||
|
*/
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
return (int) modifier.read(0);
|
return (int) modifier.read(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializer getSerializer() {
|
// TODO this
|
||||||
// TODO this
|
/* public Serializer getSerializer() {
|
||||||
return null;
|
return null;
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a DataWatcherSerializer in 1.9.
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
public static class Serializer extends AbstractWrapper {
|
public static class Serializer extends AbstractWrapper {
|
||||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherSerializerClass();
|
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherSerializerClass();
|
||||||
|
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
private final boolean optional;
|
private final boolean optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Serializer
|
||||||
|
* @param type Type it serializes
|
||||||
|
* @param handle NMS handle
|
||||||
|
* @param optional Whether or not it's {@link Optional}
|
||||||
|
*/
|
||||||
public Serializer(Class<?> type, Object handle, boolean optional) {
|
public Serializer(Class<?> type, Object handle, boolean optional) {
|
||||||
super(HANDLE_TYPE);
|
super(HANDLE_TYPE);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@ -395,19 +506,39 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
|||||||
setHandle(handle);
|
setHandle(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type this serializer serializes.
|
||||||
|
* @return The type
|
||||||
|
*/
|
||||||
public Class<?> getType() {
|
public Class<?> getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this serializer is optional, that is whether or not
|
||||||
|
* the return type is wrapped in a {@link Optional}.
|
||||||
|
* @return True if it is, false if not
|
||||||
|
*/
|
||||||
public boolean isOptional() {
|
public boolean isOptional() {
|
||||||
return optional;
|
return optional;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a DataWatcherRegistry containing the supported {@link Serializer}s in 1.9.
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
public static class Registry {
|
public static class Registry {
|
||||||
private static boolean INITIALIZED = false;
|
private static boolean INITIALIZED = false;
|
||||||
private static Map<Class<?>, Serializer> REGISTRY = new HashMap<>();
|
private static Map<Class<?>, Serializer> REGISTRY = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the serializer associated with a given class. </br>
|
||||||
|
* <b>Note</b>: If {@link Serializer#isOptional()}, the values must be wrapped in {@link Optional}
|
||||||
|
*
|
||||||
|
* @param clazz Class to find serializer for
|
||||||
|
* @return The serializer, or null if none exists
|
||||||
|
*/
|
||||||
public static Serializer get(Class<?> clazz) {
|
public static Serializer get(Class<?> clazz) {
|
||||||
if (! INITIALIZED) {
|
if (! INITIALIZED) {
|
||||||
initialize();
|
initialize();
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
* (c) 2016 dmulloy2
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||||
|
* Copyright (C) 2016 dmulloy2
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||||
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program;
|
||||||
|
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
* 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
@ -10,33 +23,38 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
|||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Represents a DataWatcher Item in 1.9.
|
||||||
* @author dmulloy2
|
* @author dmulloy2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class WrappedWatchableObject extends AbstractWrapper {
|
public class WrappedWatchableObject extends AbstractWrapper {
|
||||||
private StructureModifier<Object> modifier;
|
private final StructureModifier<Object> modifier;
|
||||||
|
|
||||||
private WrappedWatchableObject() {
|
|
||||||
super(MinecraftReflection.getDataWatcherItemClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a wrapped watchable object around an existing NMS data watcher item.
|
* Constructs a wrapped watchable object around an existing NMS data watcher item.
|
||||||
* @param handle Data watcher item
|
* @param handle Data watcher item
|
||||||
*/
|
*/
|
||||||
public WrappedWatchableObject(Object handle) {
|
public WrappedWatchableObject(Object handle) {
|
||||||
this();
|
super(MinecraftReflection.getDataWatcherItemClass());
|
||||||
setHandle(handle);
|
|
||||||
|
|
||||||
modifier = new StructureModifier<Object>(handleType).withTarget(handle);
|
setHandle(handle);
|
||||||
|
this.modifier = new StructureModifier<Object>(handleType).withTarget(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Getter methods
|
// ---- Getter methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this Item's watcher object, which contains the index and serializer.
|
||||||
|
* @return The watcher object
|
||||||
|
*/
|
||||||
public WrappedDataWatcherObject getWatcherObject() {
|
public WrappedDataWatcherObject getWatcherObject() {
|
||||||
return new WrappedDataWatcherObject(modifier.read(0));
|
return new WrappedDataWatcherObject(modifier.read(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this Item's index from the watcher object
|
||||||
|
* @return The index
|
||||||
|
*/
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
return getWatcherObject().getIndex();
|
return getWatcherObject().getIndex();
|
||||||
}
|
}
|
||||||
@ -94,6 +112,11 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
|||||||
return unwrapped;
|
return unwrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of this item.
|
||||||
|
* @param value New value
|
||||||
|
* @param updateClient Whether or not to update the client
|
||||||
|
*/
|
||||||
public void setValue(Object value, boolean updateClient) {
|
public void setValue(Object value, boolean updateClient) {
|
||||||
modifier.write(1, getUnwrapped(value));
|
modifier.write(1, getUnwrapped(value));
|
||||||
|
|
||||||
@ -102,6 +125,10 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of this item.
|
||||||
|
* @param value New value
|
||||||
|
*/
|
||||||
public void setValue(Object value) {
|
public void setValue(Object value) {
|
||||||
setValue(value, false);
|
setValue(value, false);
|
||||||
}
|
}
|
||||||
@ -145,10 +172,18 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
|||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the value must be synchronized with the client.
|
||||||
|
* @return True if it must, false if not
|
||||||
|
*/
|
||||||
public boolean getDirtyState() {
|
public boolean getDirtyState() {
|
||||||
return (boolean) modifier.read(2);
|
return (boolean) modifier.read(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets this item's dirty state
|
||||||
|
* @param dirty New state
|
||||||
|
*/
|
||||||
public void setDirtyState(boolean dirty) {
|
public void setDirtyState(boolean dirty) {
|
||||||
modifier.write(2, dirty);
|
modifier.write(2, dirty);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,9 @@ import org.junit.BeforeClass;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.comphenix.protocol.BukkitInitialization;
|
import com.comphenix.protocol.BukkitInitialization;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||||
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author dmulloy2
|
* @author dmulloy2
|
||||||
@ -33,5 +36,11 @@ public class WrappedDataWatcherTest {
|
|||||||
|
|
||||||
wrapper.setObject(0, (byte) 1);
|
wrapper.setObject(0, (byte) 1);
|
||||||
assertTrue(wrapper.getByte(0) == 1);
|
assertTrue(wrapper.getByte(0) == 1);
|
||||||
|
|
||||||
|
Serializer serializer = Registry.get(String.class);
|
||||||
|
WrappedDataWatcherObject watcherObject = new WrappedDataWatcherObject(3, serializer);
|
||||||
|
wrapper.setObject(watcherObject, "Hiya");
|
||||||
|
|
||||||
|
assertTrue(wrapper.getString(3).equals("Hiya"));
|
||||||
}
|
}
|
||||||
}
|
}
|
In neuem Issue referenzieren
Einen Benutzer sperren