Finalize the operation to make the NBT wrappers into interfaces.

This commit is contained in:
Kristian S. Stangeland 2013-01-08 22:24:07 +01:00
parent c2ea92ab37
commit 3426306805
16 changed files with 150 additions and 79 deletions

View File

@ -56,7 +56,7 @@ import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.comphenix.protocol.wrappers.nbt.NbtWrapper;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
@ -369,7 +369,7 @@ public class PacketContainer implements Serializable {
* Retrieves a read/write structure for NBT classes.
* @return A modifier for NBT classes.
*/
public StructureModifier<NbtWrapper<?>> getNbtModifier() {
public StructureModifier<NbtBase<?>> getNbtModifier() {
// Allow access to the NBT class in packet 130
return structureModifier.withType(
MinecraftReflection.getNBTBaseClass(),

View File

@ -34,8 +34,8 @@ import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.comphenix.protocol.wrappers.nbt.NbtWrapper;
/**
* Contains several useful equivalent converters for normal Bukkit types.
@ -214,24 +214,24 @@ public class BukkitConverters {
* Retrieve an equivalent converter for net.minecraft.server NBT classes and their wrappers.
* @return An equivalent converter for NBT.
*/
public static EquivalentConverter<NbtWrapper<?>> getNbtConverter() {
return getIgnoreNull(new EquivalentConverter<NbtWrapper<?>>() {
public static EquivalentConverter<NbtBase<?>> getNbtConverter() {
return getIgnoreNull(new EquivalentConverter<NbtBase<?>>() {
@Override
public Object getGeneric(Class<?> genericType, NbtWrapper<?> specific) {
return specific.getHandle();
public Object getGeneric(Class<?> genericType, NbtBase<?> specific) {
return NbtFactory.fromBase(specific).getHandle();
}
@Override
public NbtWrapper<?> getSpecific(Object generic) {
public NbtBase<?> getSpecific(Object generic) {
return NbtFactory.fromNMS(generic);
}
@Override
@SuppressWarnings("unchecked")
public Class<NbtWrapper<?>> getSpecificType() {
public Class<NbtBase<?>> getSpecificType() {
// Damn you Java AGAIN
Class<?> dummy = NbtWrapper.class;
return (Class<NbtWrapper<?>>) dummy;
Class<?> dummy = NbtBase.class;
return (Class<NbtBase<?>>) dummy;
}
});
}

View File

@ -21,6 +21,14 @@ import javax.annotation.Nullable;
import com.google.common.base.Function;
/**
* Represents an object that transform elements of type VInner to type VOuter and back again.
*
* @author Kristian
*
* @param <VInner> - the first type.
* @param <VOuter> - the second type.
*/
abstract class AbstractConverted<VInner, VOuter> {
/**
* Convert a value from the inner map to the outer visible map.

View File

@ -25,6 +25,14 @@ import java.util.List;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
/**
* Represents a collection that wraps another collection by transforming the elements going in and out.
*
* @author Kristian
*
* @param <VInner> - type of the element in the inner invisible collection.
* @param <VOuter> - type of the elements publically accessible in the outer collection.
*/
abstract class ConvertedCollection<VInner, VOuter> extends AbstractConverted<VInner, VOuter> implements Collection<VOuter> {
// Inner collection
private Collection<VInner> inner;

View File

@ -21,6 +21,14 @@ import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
/**
* Represents a list that wraps another list by transforming the items going in and out.
*
* @author Kristian
*
* @param <VInner> - type of the items in the inner invisible list.
* @param <VOuter> - type of the items publically accessible in the outer list.
*/
abstract class ConvertedList<VInner, VOuter> extends ConvertedCollection<VInner, VOuter> implements List<VOuter> {
private List<VInner> inner;

View File

@ -21,6 +21,14 @@ import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Represents a map that wraps another map by transforming the entries going in and out.
*
* @author Kristian
*
* @param <VInner> - type of the value in the entries in the inner invisible map.
* @param <VOuter> - type of the value in the entries publically accessible in the outer map.
*/
abstract class ConvertedMap<Key, VInner, VOuter> extends AbstractConverted<VInner, VOuter> implements Map<Key, VOuter> {
// Inner map
private Map<Key, VInner> inner;

View File

@ -20,6 +20,14 @@ package com.comphenix.protocol.wrappers.nbt;
import java.util.Collection;
import java.util.Set;
/**
* Represents a set that wraps another set by transforming the items going in and out.
*
* @author Kristian
*
* @param <VInner> - type of the element in the inner invisible set.
* @param <VOuter> - type of the elements publically accessible in the outer set.
*/
abstract class ConvertedSet<VInner, VOuter> extends ConvertedCollection<VInner, VOuter> implements Set<VOuter> {
public ConvertedSet(Collection<VInner> inner) {
super(inner);

View File

@ -22,8 +22,10 @@ import com.comphenix.protocol.wrappers.nbt.NbtType;
/**
* Represents a generic container for an NBT element.
* @author Kristian
* <p>
* Use {@link NbtFactory} to load or create an instance.
*
* @author Kristian
* @param <TType> - type of the value that is stored.
*/
public interface NbtBase<TType> {
@ -52,7 +54,13 @@ public interface NbtBase<TType> {
/**
* Retrieve the value of this NBT tag.
* <p>
* Is either a primitive wrapper, a list or a map.
* Is either a primitive {@link java.lang.Number wrapper}, {@link java.lang.String String},
* {@link java.util.List List} or a {@link java.util.Map Map}.
* <p>
* All operations that modify collections directly, such as {@link java.util.List#add(Object) List.add(Object)} or
* {@link java.util.Map#clear() Map.clear()}, are considered optional. This also include members in {@link java.util.Iterator Iterator} and
* {@link java.util.ListIterator ListIterator}. Operations that are not implemented throw a
* {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.
* @return Value of this tag.
*/
public abstract TType getValue();

View File

@ -9,6 +9,9 @@ import java.util.Set;
* Represents a mapping of arbitrary NBT elements and their unique names.
* <p>
* Use {@link NbtFactory} to load or create an instance.
* <p>
* The {@link NbtBase#getValue()} method returns a {@link java.util.Map} that will correctly return the content
* of this NBT compound, but may throw an {@link UnsupportedOperationException} for any of the write operations.
*
* @author Kristian
*/

View File

@ -49,47 +49,47 @@ public class NbtFactory {
private static StructureModifier<Object> itemStackModifier;
/**
* Attempt to cast this wrapper as a compund.
* Attempt to cast this NBT tag as a compund.
* @param tag - the NBT tag to cast.
* @return This instance as a compound.
* @throws UnsupportedOperationException If this is not a compound.
*/
public static NbtCompound asCompound(NbtWrapper<?> wrapper) {
if (wrapper instanceof NbtCompound)
return (NbtCompound) wrapper;
else if (wrapper != null)
public static NbtCompound asCompound(NbtBase<?> tag) {
if (tag instanceof NbtCompound)
return (NbtCompound) tag;
else if (tag != null)
throw new UnsupportedOperationException(
"Cannot cast a " + wrapper.getClass() + "( " + wrapper.getType() + ") to TAG_COMPUND.");
"Cannot cast a " + tag.getClass() + "( " + tag.getType() + ") to TAG_COMPUND.");
else
throw new IllegalArgumentException("Wrapper cannot be NULL.");
throw new IllegalArgumentException("Tag cannot be NULL.");
}
/**
* Attempt to cast this wrapper as a list.
* Attempt to cast this NBT tag as a list.
* @param tag - the NBT tag to cast.
* @return This instance as a list.
* @throws UnsupportedOperationException If this is not a list.
*/
public static NbtList<?> asList(NbtWrapper<?> wrapper) {
if (wrapper instanceof NbtList)
return (NbtList<?>) wrapper;
else if (wrapper != null)
public static NbtList<?> asList(NbtBase<?> tag) {
if (tag instanceof NbtList)
return (NbtList<?>) tag;
else if (tag != null)
throw new UnsupportedOperationException(
"Cannot cast a " + wrapper.getClass() + "( " + wrapper.getType() + ") to TAG_LIST.");
"Cannot cast a " + tag.getClass() + "( " + tag.getType() + ") to TAG_LIST.");
else
throw new IllegalArgumentException("Wrapper cannot be NULL.");
throw new IllegalArgumentException("Tag cannot be NULL.");
}
/**
* Get a NBT wrapper from a NBT base.
* <p>
* This may clone the content if the NbtBase is not a NbtWrapper.
* @param base - the base class.
* @return A NBT wrapper.
*/
@SuppressWarnings("unchecked")
public static <T> NbtWrapper<T> fromBase(NbtBase<T> base) {
if (base instanceof WrappedElement) {
return (WrappedElement<T>) base;
} else if (base instanceof WrappedCompound) {
return (NbtWrapper<T>) base;
} else if (base instanceof WrappedList) {
if (base instanceof NbtWrapper) {
return (NbtWrapper<T>) base;
} else {
if (base.getType() == NbtType.TAG_COMPOUND) {
@ -109,7 +109,7 @@ public class NbtFactory {
} else {
// Copy directly
NbtWrapper<T> copy = ofType(base.getType(), base.getName());
NbtWrapper<T> copy = ofWrapper(base.getType(), base.getName());
copy.setValue(base.getValue());
return copy;
@ -136,17 +136,17 @@ public class NbtFactory {
}
// Use the first and best NBT tag
StructureModifier<NbtWrapper<?>> modifier = itemStackModifier.
StructureModifier<NbtBase<?>> modifier = itemStackModifier.
withTarget(nmsStack).
withType(MinecraftReflection.getNBTBaseClass(), BukkitConverters.getNbtConverter());
NbtWrapper<?> result = modifier.read(0);
NbtBase<?> result = modifier.read(0);
// Create the tag if it doesn't exist
if (result == null) {
result = NbtFactory.ofCompound("tag");
modifier.write(0, result);
}
return result;
return fromBase(result);
}
/**
@ -215,8 +215,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<String> of(String name, String value) {
return ofType(NbtType.TAG_STRING, name, value);
public static NbtBase<String> of(String name, String value) {
return ofWrapper(NbtType.TAG_STRING, name, value);
}
/**
@ -225,8 +225,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<Byte> of(String name, byte value) {
return ofType(NbtType.TAG_BYTE, name, value);
public static NbtBase<Byte> of(String name, byte value) {
return ofWrapper(NbtType.TAG_BYTE, name, value);
}
/**
@ -235,8 +235,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<Short> of(String name, short value) {
return ofType(NbtType.TAG_SHORT, name, value);
public static NbtBase<Short> of(String name, short value) {
return ofWrapper(NbtType.TAG_SHORT, name, value);
}
/**
@ -245,8 +245,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<Integer> of(String name, int value) {
return ofType(NbtType.TAG_INT, name, value);
public static NbtBase<Integer> of(String name, int value) {
return ofWrapper(NbtType.TAG_INT, name, value);
}
/**
@ -255,8 +255,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<Long> of(String name, long value) {
return ofType(NbtType.TAG_LONG, name, value);
public static NbtBase<Long> of(String name, long value) {
return ofWrapper(NbtType.TAG_LONG, name, value);
}
/**
@ -265,8 +265,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<Float> of(String name, float value) {
return ofType(NbtType.TAG_FLOAT, name, value);
public static NbtBase<Float> of(String name, float value) {
return ofWrapper(NbtType.TAG_FLOAT, name, value);
}
/**
@ -275,8 +275,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<Double> of(String name, double value) {
return ofType(NbtType.TAG_DOUBlE, name, value);
public static NbtBase<Double> of(String name, double value) {
return ofWrapper(NbtType.TAG_DOUBlE, name, value);
}
/**
@ -285,8 +285,8 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<byte[]> of(String name, byte[] value) {
return ofType(NbtType.TAG_BYTE_ARRAY, name, value);
public static NbtBase<byte[]> of(String name, byte[] value) {
return ofWrapper(NbtType.TAG_BYTE_ARRAY, name, value);
}
/**
@ -295,12 +295,12 @@ public class NbtFactory {
* @param value - value of the tag.
* @return The constructed NBT tag.
*/
public static NbtWrapper<int[]> of(String name, int[] value) {
return ofType(NbtType.TAG_INT_ARRAY, name, value);
public static NbtBase<int[]> of(String name, int[] value) {
return ofWrapper(NbtType.TAG_INT_ARRAY, name, value);
}
/**
* Construct a new NBT compound wrapper initialized with a given list of NBT values.
* Construct a new NBT compound initialized with a given list of NBT values.
* @param name - the name of the compound wrapper.
* @param list - the list of elements to add.
* @return The new wrapped NBT compound.
@ -314,7 +314,7 @@ public class NbtFactory {
* @param name - the name of the compound wrapper.
* @return The new wrapped NBT compound.
*/
public static WrappedCompound ofCompound(String name) {
public static NbtCompound ofCompound(String name) {
return WrappedCompound.fromName(name);
}
@ -328,6 +328,16 @@ public class NbtFactory {
return WrappedList.fromArray(name, elements);
}
/**
* Construct a NBT list of out a list of values.
* @param name - name of this list.
* @param elements - elements to add.
* @return The new filled NBT list.
*/
public static <T> NbtList<T> ofList(String name, Collection<? extends T> elements) {
return WrappedList.fromList(name, elements);
}
/**
* Create a new NBT wrapper from a given type.
* @param type - the NBT type.
@ -336,7 +346,7 @@ public class NbtFactory {
* @throws FieldAccessException If we're unable to create the underlying tag.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> NbtWrapper<T> ofType(NbtType type, String name) {
public static <T> NbtWrapper<T> ofWrapper(NbtType type, String name) {
if (type == null)
throw new IllegalArgumentException("type cannot be NULL.");
if (type == NbtType.TAG_END)
@ -376,8 +386,8 @@ public class NbtFactory {
* @return The new wrapped NBT tag.
* @throws FieldAccessException If we're unable to create the underlying tag.
*/
public static <T> NbtWrapper<T> ofType(NbtType type, String name, T value) {
NbtWrapper<T> created = ofType(type, name);
public static <T> NbtWrapper<T> ofWrapper(NbtType type, String name, T value) {
NbtWrapper<T> created = ofWrapper(type, name);
// Update the value
created.setValue(value);
@ -393,7 +403,7 @@ public class NbtFactory {
* @throws FieldAccessException If we're unable to create the underlying tag.
* @throws IllegalArgumentException If the given class type is not valid NBT.
*/
public static <T> NbtWrapper<T> ofType(Class<?> type, String name, T value) {
return ofType(NbtType.getTypeFromClass(type), name, value);
public static <T> NbtWrapper<T> ofWrapper(Class<?> type, String name, T value) {
return ofWrapper(NbtType.getTypeFromClass(type), name, value);
}
}

View File

@ -8,6 +8,9 @@ import java.util.List;
* Represents a list of NBT tags of the same type without names.
* <p>
* Use {@link NbtFactory} to load or create an instance.
* <p>
* The {@link NbtBase#getValue()} method returns a {@link java.util.List} that will correctly return the content
* of this NBT list, but may throw an {@link UnsupportedOperationException} for any of the write operations.
*
* @author Kristian
*

View File

@ -21,6 +21,8 @@ import java.io.DataOutput;
/**
* Indicates that this NBT wraps an underlying net.minecraft.server instance.
* <p>
* Use {@link NbtFactory} to load or create instances.
*
* @author Kristian
*

View File

@ -28,7 +28,7 @@ import java.util.Set;
*
* @author Kristian
*/
public class WrappedCompound implements NbtWrapper<Map<String, NbtBase<?>>>, Iterable<NbtBase<?>>, NbtCompound {
class WrappedCompound implements NbtWrapper<Map<String, NbtBase<?>>>, Iterable<NbtBase<?>>, NbtCompound {
// A list container
private WrappedElement<Map<String, Object>> container;
@ -42,7 +42,7 @@ public class WrappedCompound implements NbtWrapper<Map<String, NbtBase<?>>>, Ite
*/
public static WrappedCompound fromName(String name) {
// Simplify things for the caller
return (WrappedCompound) NbtFactory.<Map<String, NbtBase<?>>>ofType(NbtType.TAG_COMPOUND, name);
return (WrappedCompound) NbtFactory.<Map<String, NbtBase<?>>>ofWrapper(NbtType.TAG_COMPOUND, name);
}
/**
@ -63,7 +63,7 @@ public class WrappedCompound implements NbtWrapper<Map<String, NbtBase<?>>>, Ite
* Construct a wrapped compound from a given NMS handle.
* @param handle - the NMS handle.
*/
WrappedCompound(Object handle) {
public WrappedCompound(Object handle) {
this.container = new WrappedElement<Map<String,Object>>(handle);
}
@ -164,7 +164,7 @@ public class WrappedCompound implements NbtWrapper<Map<String, NbtBase<?>>>, Ite
// Create or get a compound
if (nbt == null)
put(nbt = NbtFactory.ofType(type, key));
put(nbt = NbtFactory.ofWrapper(type, key));
else if (nbt.getType() != type)
throw new IllegalArgumentException("Cannot get tag " + nbt + ": Not a " + type);

View File

@ -27,14 +27,12 @@ import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.base.Objects;
/**
* Represents an arbitrary NBT tag element, composite or not.
* <p>
* Use {@link NbtFactory} to load or create an instance.
* @author Kristian
* Represents a wrapped NBT tag element, composite or not.
*
* @author Kristian
* @param <TType> - type of the value field.
*/
public class WrappedElement<TType> implements NbtWrapper<TType> {
class WrappedElement<TType> implements NbtWrapper<TType> {
// Structure modifier for the base class
private static volatile StructureModifier<Object> baseModifier;
@ -57,7 +55,7 @@ public class WrappedElement<TType> implements NbtWrapper<TType> {
* Initialize a NBT wrapper for a generic element.
* @param handle - the NBT element to wrap.
*/
WrappedElement(Object handle) {
public WrappedElement(Object handle) {
this.handle = handle;
}
@ -135,12 +133,20 @@ public class WrappedElement<TType> implements NbtWrapper<TType> {
return type;
}
NbtType getSubType() {
/**
* Retrieve the sub element type of the underlying NMS NBT list.
* @return The NBT sub type.
*/
public NbtType getSubType() {
int subID = getCurrentBaseModifier().<Byte>withType(byte.class).withTarget(handle).read(0);
return NbtType.getTypeFromID(subID);
}
void setSubType(NbtType type) {
/**
* Set the sub element type of the underlying NMS NBT list.
* @param type - the new sub element type.
*/
public void setSubType(NbtType type) {
byte subID = (byte) type.getRawID();
getCurrentBaseModifier().<Byte>withType(byte.class).withTarget(handle).write(0, subID);
}

View File

@ -34,7 +34,7 @@ import com.google.common.collect.Iterables;
*
* @param <TType> - the type of the value in each NBT sub element.
*/
public class WrappedList<TType> implements NbtWrapper<List<NbtBase<TType>>>, Iterable<TType>, NbtList<TType> {
class WrappedList<TType> implements NbtWrapper<List<NbtBase<TType>>>, Iterable<TType>, NbtList<TType> {
// A list container
private WrappedElement<List<Object>> container;
@ -47,7 +47,7 @@ public class WrappedList<TType> implements NbtWrapper<List<NbtBase<TType>>>, Ite
* @return The new empty NBT list.
*/
public static <T> WrappedList<T> fromName(String name) {
return (WrappedList<T>) NbtFactory.<List<NbtBase<T>>>ofType(NbtType.TAG_LIST, name);
return (WrappedList<T>) NbtFactory.<List<NbtBase<T>>>ofWrapper(NbtType.TAG_LIST, name);
}
/**
@ -62,7 +62,7 @@ public class WrappedList<TType> implements NbtWrapper<List<NbtBase<TType>>>, Ite
for (T element : elements) {
if (element == null)
throw new IllegalArgumentException("An NBT list cannot contain a null element!");
result.add(NbtFactory.ofType(element.getClass(), EMPTY_NAME, element));
result.add(NbtFactory.ofWrapper(element.getClass(), EMPTY_NAME, element));
}
return result;
}
@ -79,7 +79,7 @@ public class WrappedList<TType> implements NbtWrapper<List<NbtBase<TType>>>, Ite
for (T element : elements) {
if (element == null)
throw new IllegalArgumentException("An NBT list cannot contain a null element!");
result.add(NbtFactory.ofType(element.getClass(), EMPTY_NAME, element));
result.add(NbtFactory.ofWrapper(element.getClass(), EMPTY_NAME, element));
}
return result;
}

View File

@ -50,7 +50,6 @@ import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
import com.comphenix.protocol.wrappers.nbt.WrappedCompound;
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
import com.google.common.collect.Iterables;
@ -257,7 +256,7 @@ public class PacketContainerTest {
public void testGetNbtModifier() {
PacketContainer updateTileEntity = new PacketContainer(132);
WrappedCompound compound = NbtFactory.ofCompound("test");
NbtCompound compound = NbtFactory.ofCompound("test");
compound.put("test", "name");
compound.put(NbtFactory.ofList("ages", 1, 2, 3));