From a170ea3a1c6574790ca107d03f4abc7cefc0f516 Mon Sep 17 00:00:00 2001 From: Sandro Marques Date: Fri, 15 Dec 2023 16:27:42 +0000 Subject: [PATCH] Add missing docs --- .../sandrohc/schematic4j/SchematicFormat.java | 14 +- .../schematic4j/nbt/Deserializer.java | 45 ++- .../schematic4j/nbt/ExceptionBiFunction.java | 16 +- .../schematic4j/nbt/ExceptionTriConsumer.java | 14 + .../nbt/MaxDepthReachedException.java | 1 - .../sandrohc/schematic4j/nbt/io/NBTInput.java | 17 + .../sandrohc/schematic4j/nbt/io/NBTUtil.java | 249 ++++++-------- .../sandrohc/schematic4j/nbt/io/NamedTag.java | 30 ++ .../schematic4j/nbt/tag/ArrayTag.java | 9 + .../schematic4j/nbt/tag/ByteArrayTag.java | 10 + .../sandrohc/schematic4j/nbt/tag/ByteTag.java | 22 +- .../schematic4j/nbt/tag/CompoundTag.java | 305 +++++++++++++++++- .../schematic4j/nbt/tag/DoubleTag.java | 23 ++ .../sandrohc/schematic4j/nbt/tag/EndTag.java | 13 + .../schematic4j/nbt/tag/FloatTag.java | 22 ++ .../schematic4j/nbt/tag/IntArrayTag.java | 17 + .../sandrohc/schematic4j/nbt/tag/IntTag.java | 22 ++ .../sandrohc/schematic4j/nbt/tag/ListTag.java | 259 ++++++++++++++- .../schematic4j/nbt/tag/LongArrayTag.java | 17 + .../sandrohc/schematic4j/nbt/tag/LongTag.java | 22 ++ .../schematic4j/nbt/tag/NonNullEntrySet.java | 25 +- .../schematic4j/nbt/tag/NumberTag.java | 15 + .../schematic4j/nbt/tag/ShortTag.java | 22 ++ .../schematic4j/nbt/tag/StringTag.java | 17 + .../net/sandrohc/schematic4j/nbt/tag/Tag.java | 4 +- .../schematic/LitematicaSchematic.java | 242 +++++++++++++- .../schematic4j/schematic/Schematic.java | 34 +- .../schematic/SchematicaSchematic.java | 75 ++++- .../schematic/SpongeSchematic.java | 87 ++++- .../schematic/types/SchematicBiome.java | 3 + .../schematic/types/SchematicBlock.java | 32 +- .../schematic/types/SchematicBlockEntity.java | 24 +- .../schematic/types/SchematicBlockPos.java | 29 ++ .../schematic/types/SchematicEntity.java | 24 +- .../schematic/types/SchematicEntityPos.java | 36 ++- .../schematic/types/SchematicItem.java | 24 +- .../schematic/types/SchematicNamed.java | 12 +- .../schematic4j/nbt/io/NBTUtilTest.java | 131 ++++++++ 38 files changed, 1736 insertions(+), 227 deletions(-) create mode 100644 src/test/java/net/sandrohc/schematic4j/nbt/io/NBTUtilTest.java diff --git a/src/main/java/net/sandrohc/schematic4j/SchematicFormat.java b/src/main/java/net/sandrohc/schematic4j/SchematicFormat.java index 4168c33..e7b99ef 100644 --- a/src/main/java/net/sandrohc/schematic4j/SchematicFormat.java +++ b/src/main/java/net/sandrohc/schematic4j/SchematicFormat.java @@ -20,15 +20,11 @@ import net.sandrohc.schematic4j.parser.SpongeParser; public enum SchematicFormat { - SPONGE_V1 ("schem", SpongeParser::new), - SPONGE_V2 ("schem", SpongeParser::new), - SPONGE_V3 ("schem", SpongeParser::new), - LITEMATICA ("litematic"), - SCHEMATICA ("schematic", SchematicaParser::new), - WORLD_EDITOR ("schematic"), - MCEDIT ("schematic"), - MCEDIT_UNIFIED ("schematic"), - MCEDIT2 ("schematic"), + SPONGE_V1("schem", SpongeParser::new), + SPONGE_V2("schem", SpongeParser::new), + SPONGE_V3("schem", SpongeParser::new), + LITEMATICA("litematic", LitematicaParser::new), + SCHEMATICA("schematic", SchematicaParser::new), UNKNOWN; private static final Logger log = LoggerFactory.getLogger(SchematicFormat.class); diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/Deserializer.java b/src/main/java/net/sandrohc/schematic4j/nbt/Deserializer.java index 245188d..a8b7d65 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/Deserializer.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/Deserializer.java @@ -4,26 +4,60 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.file.Files; +/** + * A generic NBT deserializer. + * + * @param Type of the deserialized value + */ public interface Deserializer { + /** + * Deserialize NBT from an input stream. + * + * @param stream The input stream containing the NBT data + * @return The deserialized NBT + * @throws IOException In case there's an error reading from the input stream + */ T fromStream(InputStream stream) throws IOException; + /** + * Deserialize NBT from a file. + * + * @param file The file containing the NBT data + * @return The deserialized NBT + * @throws IOException In case there's an error reading from the file + */ default T fromFile(File file) throws IOException { - try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) { + try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()))) { return fromStream(bis); } } + /** + * Deserialize NBT from a byte array. + * + * @param data The byte array containing the NBT data + * @return The deserialized NBT + * @throws IOException In case there's an error reading from the byte array + */ default T fromBytes(byte[] data) throws IOException { ByteArrayInputStream stream = new ByteArrayInputStream(data); return fromStream(stream); } + /** + * Deserialize NBT from a JAR resource. + * + * @param clazz The class belonging to the JAR that contains the resource + * @param path The resource path containing the NBT data + * @return The deserialized NBT + * @throws IOException In case there's an error reading from the resource + */ default T fromResource(Class clazz, String path) throws IOException { try (InputStream stream = clazz.getClassLoader().getResourceAsStream(path)) { if (stream == null) { @@ -33,6 +67,13 @@ default T fromResource(Class clazz, String path) throws IOException { } } + /** + * Deserialize NBT from a URL. + * + * @param url The URL containing the NBT data + * @return The deserialized NBT + * @throws IOException In case there's an error reading from the URL + */ default T fromURL(URL url) throws IOException { try (InputStream stream = url.openStream()) { return fromStream(stream); diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionBiFunction.java b/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionBiFunction.java index b222f56..c695b72 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionBiFunction.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionBiFunction.java @@ -1,8 +1,22 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt; +/** + * A bi-function that may throw an exception. + * + * @param First value type + * @param Second value type + * @param Return type + * @param Exception type + */ @FunctionalInterface -public interface ExceptionBiFunction { +public interface ExceptionBiFunction { + /** + * @param t The first value + * @param u The second value + * @return The return value + * @throws E The exception + */ R accept(T t, U u) throws E; } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionTriConsumer.java b/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionTriConsumer.java index ceaf46c..cb9d439 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionTriConsumer.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/ExceptionTriConsumer.java @@ -1,8 +1,22 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt; +/** + * A tri-consumer that may throw an exception. + * + * @param First value type + * @param Second value type + * @param Third value type + * @param Exception type + */ @FunctionalInterface public interface ExceptionTriConsumer { + /** + * @param t The first value + * @param u The second value + * @param v The third value + * @throws E The exception + */ void accept(T t, U u, V v) throws E; } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/MaxDepthReachedException.java b/src/main/java/net/sandrohc/schematic4j/nbt/MaxDepthReachedException.java index 38732f0..97b0e7d 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/MaxDepthReachedException.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/MaxDepthReachedException.java @@ -4,7 +4,6 @@ /** * Exception indicating that the maximum (de-)serialization depth has been reached. */ -@SuppressWarnings("serial") public class MaxDepthReachedException extends RuntimeException { public MaxDepthReachedException(String msg) { diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTInput.java b/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTInput.java index e65f1d0..f0dea2a 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTInput.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTInput.java @@ -5,9 +5,26 @@ import net.sandrohc.schematic4j.nbt.tag.Tag; +/** + * A generic NBT input + */ public interface NBTInput { + /** + * Read a named tag from the input. + * + * @param maxDepth Maximum depth before failing deserialization + * @return The named tag read + * @throws IOException In case of error reading from the input + */ NamedTag readTag(int maxDepth) throws IOException; + /** + * Read a tag from the input. + * + * @param maxDepth Maximum depth before failing deserialization + * @return The tag read + * @throws IOException In case of error reading from the input + */ Tag readRawTag(int maxDepth) throws IOException; } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTUtil.java b/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTUtil.java index a965e5c..5538281 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTUtil.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/io/NBTUtil.java @@ -1,7 +1,14 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.io; -import java.io.*; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PushbackInputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -11,56 +18,73 @@ public final class NBTUtil { - private NBTUtil() {} + private NBTUtil() { + } /** * Writer helper that follows the builder pattern. *

* Usage example: - *

{@code Writer.write()
-	 *     .tag(nbtTag)
+	 * 
{@code Writer.write(nbtTag)
 	 *     .littleEndian()
 	 *     .compressed(false)
 	 *     .to("file.schematic")}
*/ public static class Writer { - private NamedTag tag; + public final NamedTag tag; private boolean compressed = true; private boolean littleEndian = false; - public Writer() { - } - - public static Writer write() { - return new Writer(); + private Writer(NamedTag tag) { + this.tag = tag; } - public Writer tag(NamedTag tag) { - this.tag = tag; - return this; + public static Writer write(NamedTag tag) { + return new Writer(tag); } - public Writer tag(Tag tag) { - this.tag = new NamedTag(null, tag); - return this; + public static Writer write(Tag tag) { + return new Writer(new NamedTag(null, tag)); } + /** + * Toggle compression for the output. GZIP compression is used. + * + * @param compressed Whether the output should be compressed or not + * @return The writer builder + */ public Writer compressed(boolean compressed) { this.compressed = compressed; return this; } + /** + * Write to the output as Little Endian. Usually reserved for network packets or some systems architectures. + * + * @return the writer builder + */ public Writer littleEndian() { this.littleEndian = true; return this; } + /** + * Write to the output as Big Endian. This is the default. + * + * @return the writer builder + */ public Writer bigEndian() { this.littleEndian = false; return this; } + /** + * Writes the NBT tag to an output stream. Terminal operator. + * + * @param os The output stream to write to + * @throws IOException In case of error writing to the output stream + */ public void to(OutputStream os) throws IOException { if (tag == null) throw new IllegalStateException("tag must be set"); @@ -70,16 +94,34 @@ public void to(OutputStream os) throws IOException { new NBTSerializer(compressed, littleEndian).toStream(tag, os); } + /** + * Writes the NBT tag to a file. Terminal operator. + * + * @param path The file path fo write to + * @throws IOException In case of error writing to the file + */ public void to(Path path) throws IOException { try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(path))) { to(os); } } + /** + * Writes the NBT tag to a file. Terminal operator. + * + * @param file The file path fo write to + * @throws IOException In case of error writing to the file + */ public void to(File file) throws IOException { to(file.toPath()); } + /** + * Writes the NBT tag to a file. Terminal operator. + * + * @param file The file path fo write to + * @throws IOException In case of error writing to the file + */ public void to(String file) throws IOException { to(Paths.get(file)); } @@ -104,31 +146,80 @@ public static Reader read() { return new Reader(); } + /** + * Read from the source as Little Endian. Usually reserved for network packets or some systems architectures. + * + * @return the reader builder + */ public Reader littleEndian() { this.littleEndian = true; return this; } + /** + * Read from the source as Big Endian. This is the default. + * + * @return the reader builder + */ public Reader bigEndian() { this.littleEndian = false; return this; } + /** + * Reads the NBT tag from an input stream. Terminal operator. + * + * @param is The input stream to read from + * @return The parsed NBT tag + * @throws IOException In case of error reading from the input stream + */ public NamedTag from(InputStream is) throws IOException { return new NBTDeserializer(false/* ignored, will autodetect compression */, littleEndian) .fromStream(detectDecompression(is)); } + /** + * Reads the NBT tag from a byte array. Terminal operator. + * + * @param bytes The byte array + * @return The parsed NBT tag + * @throws IOException In case of error reading from the input stream + */ + public NamedTag from(byte[] bytes) throws IOException { + return from(new ByteArrayInputStream(bytes)); + } + + /** + * Reads the NBT tag from a file. Terminal operator. + * + * @param path The file path to read from + * @return The parsed NBT tag + * @throws IOException In case of error reading from the file + */ public NamedTag from(Path path) throws IOException { try (InputStream is = new BufferedInputStream(Files.newInputStream(path))) { return from(is); } } + /** + * Reads the NBT tag from a file. Terminal operator. + * + * @param file The file path to read from + * @return The parsed NBT tag + * @throws IOException In case of error reading from the file + */ public NamedTag from(File file) throws IOException { return from(file.toPath()); } + /** + * Reads the NBT tag from a file. Terminal operator. + * + * @param file The file path to read from + * @return The parsed NBT tag + * @throws IOException In case of error reading from the file + */ public NamedTag from(String file) throws IOException { return from(Paths.get(file)); } @@ -141,130 +232,4 @@ private static InputStream detectDecompression(InputStream is) throws IOExceptio return signature == GZIPInputStream.GZIP_MAGIC ? new GZIPInputStream(pbis) : pbis; } } - - - @Deprecated - public static void write(NamedTag tag, File file, boolean compressed) throws IOException { - Writer.write().tag(tag).compressed(compressed).to(file); - } - - @Deprecated - public static void write(NamedTag tag, String file, boolean compressed) throws IOException { - Writer.write().tag(tag).compressed(compressed).to(file); - } - - @Deprecated - public static void write(NamedTag tag, File file) throws IOException { - Writer.write().tag(tag).to(file); - } - - @Deprecated - public static void write(NamedTag tag, String file) throws IOException { - Writer.write().tag(tag).to(file); - } - - @Deprecated - public static void write(Tag tag, File file, boolean compressed) throws IOException { - Writer.write().tag(tag).compressed(compressed).to(file); - } - - @Deprecated - public static void write(Tag tag, String file, boolean compressed) throws IOException { - Writer.write().tag(tag).compressed(compressed).to(file); - } - - @Deprecated - public static void write(Tag tag, File file) throws IOException { - Writer.write().tag(tag).to(file); - } - - @Deprecated - public static void write(Tag tag, String file) throws IOException { - Writer.write().tag(tag).to(file); - } - - @Deprecated - public static void writeLE(NamedTag tag, File file, boolean compressed) throws IOException { - Writer.write().tag(tag).littleEndian().compressed(compressed).to(file); - } - - @Deprecated - public static void writeLE(NamedTag tag, String file, boolean compressed) throws IOException { - Writer.write().tag(tag).littleEndian().compressed(compressed).to(file); - } - - @Deprecated - public static void writeLE(NamedTag tag, File file) throws IOException { - Writer.write().tag(tag).littleEndian().to(file); - } - - @Deprecated - public static void writeLE(NamedTag tag, String file) throws IOException { - Writer.write().tag(tag).littleEndian().to(file); - } - - @Deprecated - public static void writeLE(Tag tag, File file, boolean compressed) throws IOException { - Writer.write().tag(tag).littleEndian().compressed(compressed).to(file); - } - - @Deprecated - public static void writeLE(Tag tag, String file, boolean compressed) throws IOException { - Writer.write().tag(tag).littleEndian().compressed(compressed).to(file); - } - - @Deprecated - public static void writeLE(Tag tag, File file) throws IOException { - Writer.write().tag(tag).littleEndian().to(file); - } - - @Deprecated - public static void writeLE(Tag tag, String file) throws IOException { - Writer.write().tag(tag).littleEndian().to(file); - } - - @Deprecated - @SuppressWarnings("unused") - public static NamedTag read(File file, boolean compressed) throws IOException { - return Reader.read().from(file); - } - - @Deprecated - @SuppressWarnings("unused") - public static NamedTag read(String file, boolean compressed) throws IOException { - return Reader.read().from(file); - } - - @Deprecated - public static NamedTag read(File file) throws IOException { - return Reader.read().from(file); - } - - @Deprecated - public static NamedTag read(String file) throws IOException { - return Reader.read().from(file); - } - - @Deprecated - @SuppressWarnings("unused") - public static NamedTag readLE(File file, boolean compressed) throws IOException { - return Reader.read().littleEndian().from(file); - } - - @Deprecated - @SuppressWarnings("unused") - public static NamedTag readLE(String file, boolean compressed) throws IOException { - return Reader.read().littleEndian().from(file); - } - - @Deprecated - public static NamedTag readLE(File file) throws IOException { - return Reader.read().littleEndian().from(file); - } - - @Deprecated - public static NamedTag readLE(String file) throws IOException { - return Reader.read().littleEndian().from(file); - } - } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/io/NamedTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/io/NamedTag.java index 02105bb..001ce97 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/io/NamedTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/io/NamedTag.java @@ -3,9 +3,19 @@ import net.sandrohc.schematic4j.nbt.tag.Tag; +/** + * A named tag. + */ public class NamedTag { + /** + * The name of the named tag. + */ private String name; + + /** + * The inner tag. + */ private Tag tag; public NamedTag(String name, Tag tag) { @@ -13,18 +23,38 @@ public NamedTag(String name, Tag tag) { this.tag = tag; } + /** + * Set a new name. + * + * @param name The new name + */ public void setName(String name) { this.name = name; } + /** + * Set a new tag. + * + * @param tag The new tag + */ public void setTag(Tag tag) { this.tag = tag; } + /** + * Get the named tag name. + * + * @return The named tag name + */ public String getName() { return name; } + /** + * Get the named tag inner tag. + * + * @return The named tag inner tag + */ public Tag getTag() { return tag; } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ArrayTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ArrayTag.java index 98e11c8..37b0213 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ArrayTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ArrayTag.java @@ -20,6 +20,10 @@ public ArrayTag(T value) { } } + /** + * Get ghe array length, or size. + * @return The array length + */ public int length() { return Array.getLength(getValue()); } @@ -39,6 +43,11 @@ public String valueToString(int maxDepth) { return arrayToString("", ""); } + /** + * @param prefix The item prefix + * @param suffix The item suffix + * @return The generated string + */ protected String arrayToString(String prefix, String suffix) { StringBuilder sb = new StringBuilder("[").append(prefix).append("".equals(prefix) ? "" : ";"); for (int i = 0; i < length(); i++) { diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteArrayTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteArrayTag.java index 1bffefa..035c259 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteArrayTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteArrayTag.java @@ -3,9 +3,19 @@ import java.util.Arrays; +/** + * A byte array NBT tag. + */ public class ByteArrayTag extends ArrayTag implements Comparable { + /** + * The byte array tag discriminator. + */ public static final byte ID = 7; + + /** + * The default value. + */ public static final byte[] ZERO_VALUE = new byte[0]; /** diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteTag.java index 2350a10..8164fea 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ByteTag.java @@ -1,13 +1,23 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A byte NBT tag. + */ public class ByteTag extends NumberTag implements Comparable { + /** + * The byte tag discriminator. + */ public static final byte ID = 1; + + /** + * The default value. + */ public static final byte ZERO_VALUE = 0; /** - * An empty byte tag. + * A byte tag with the default value. */ public ByteTag() { super(ZERO_VALUE); @@ -34,10 +44,20 @@ public byte getID() { return ID; } + /** + * Convert this byte into a boolean value. Values greater than zero map to true. + * + * @return {@code true} if greater than 0, {@code false} otherwise + */ public boolean asBoolean() { return getValue() > 0; } + /** + * Sets the inner byte value. + * + * @param value The new value + */ public void setValue(byte value) { super.setValue(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/CompoundTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/CompoundTag.java index 6cac957..ad8b696 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/CompoundTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/CompoundTag.java @@ -9,13 +9,18 @@ import java.util.Set; import java.util.function.BiConsumer; +import org.checkerframework.checker.nullness.qual.NonNull; + import net.sandrohc.schematic4j.nbt.MaxDepthIO; /** - * A compound tag. Works like a map. + * A compound NBT tag. Works like a map. */ public class CompoundTag extends Tag>> implements Iterable>>, Comparable, MaxDepthIO { + /** + * The compound tag discriminator. + */ public static final byte ID = 10; /** @@ -34,47 +39,112 @@ private static Map> createEmptyValue() { return new HashMap<>(8); } + /** + * Get the number of entries. + * + * @return The number of entries + */ public int size() { return getValue().size(); } + /** + * Check if this compound tag is empty. + * + * @return Whether this compound tag is empty + */ + public boolean isEmpty() { + return getValue().isEmpty(); + } + + /** + * Removes an entry by key. + * + * @param key The entry key to remove + * @return The removed entry + */ public Tag remove(String key) { return getValue().remove(key); } + /** + * Remove all entries. + */ public void clear() { getValue().clear(); } + /** + * Returns true if this compound tag contains a mapping for the specified key. + * + * @param key key whose presence in this map is to be tested + * @return {@code true} if this map contains a mapping for the specified key + */ public boolean containsKey(String key) { return getValue().containsKey(key); } + /** + * Returns true if this map maps one or more keys to the specified value. More formally, returns true if and only + * if this map contains at least one mapping to a value v such that (value==null ? v==null : value.equals(v)). + * + * @param value value whose presence in this map is to be tested + * @return true if this map maps one or more keys to the specified value + */ public boolean containsValue(Tag value) { return getValue().containsValue(value); } + /** + * Returns a Collection view of the values contained in this compound tag. + * + * @return a collection view of the values contained in this compound tag + */ public Collection> values() { return getValue().values(); } + /** + * Returns a Set view of the keys contained in this compound tag. + * + * @return a set view of the keys contained in this compound tag + */ public Set keySet() { return getValue().keySet(); } + /** + * Returns a Set view of the mappings contained in this compound tag. + * + * @return a set view of the mappings contained in this compound tag + */ public Set>> entrySet() { return new NonNullEntrySet<>(getValue().entrySet()); } @Override - public Iterator>> iterator() { + public @NonNull Iterator>> iterator() { return entrySet().iterator(); } + /** + * Performs the given action for each entry in this map until all entries have been processed or the action throws an exception. + * + * @param action The action to be performed for each entry + */ public void forEach(BiConsumer> action) { getValue().forEach(action); } + /** + * Returns the value to which the specified key is mapped coerced into a type, or null if this map contains no + * mapping for the key. + * + * @param key the key whose associated value is to be returned + * @param type the type of the value + * @param the type of the value + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public > C get(String key, Class type) { Tag t = getValue().get(key); if (t != null) { @@ -83,157 +153,386 @@ public > C get(String key, Class type) { return null; } + /** + * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public Tag get(String key) { return getValue().get(key); } + /** + * Get value as a byte array tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public ByteTag getByteTag(String key) { return get(key, ByteTag.class); } + /** + * Get value as a short tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public ShortTag getShortTag(String key) { return get(key, ShortTag.class); } + /** + * Get value as an int tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public IntTag getIntTag(String key) { return get(key, IntTag.class); } + /** + * Get value as a long tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public LongTag getLongTag(String key) { return get(key, LongTag.class); } + /** + * Get value as a float tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public FloatTag getFloatTag(String key) { return get(key, FloatTag.class); } + /** + * Get value as a double tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public DoubleTag getDoubleTag(String key) { return get(key, DoubleTag.class); } + /** + * Get value as a string tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public StringTag getStringTag(String key) { return get(key, StringTag.class); } + /** + * Get value as a byte array tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public ByteArrayTag getByteArrayTag(String key) { return get(key, ByteArrayTag.class); } + /** + * Get value as an int array tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public IntArrayTag getIntArrayTag(String key) { return get(key, IntArrayTag.class); } + /** + * Get value as a long array tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public LongArrayTag getLongArrayTag(String key) { return get(key, LongArrayTag.class); } + /** + * Get value as a list tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public ListTag getListTag(String key) { return get(key, ListTag.class); } + /** + * Get value as a compound tag. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public CompoundTag getCompoundTag(String key) { return get(key, CompoundTag.class); } + /** + * Get value as a boolean. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public boolean getBoolean(String key) { Tag t = get(key); - return t instanceof ByteTag && ((ByteTag) t).asByte() > 0; + return t instanceof ByteTag && ((ByteTag) t).asBoolean(); } + /** + * Get value as a byte. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public byte getByte(String key) { ByteTag t = getByteTag(key); return t == null ? ByteTag.ZERO_VALUE : t.asByte(); } + /** + * Get value as a short. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public short getShort(String key) { ShortTag t = getShortTag(key); return t == null ? ShortTag.ZERO_VALUE : t.asShort(); } + /** + * Get value as an int. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public int getInt(String key) { IntTag t = getIntTag(key); return t == null ? IntTag.ZERO_VALUE : t.asInt(); } + /** + * Get value as a long. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public long getLong(String key) { LongTag t = getLongTag(key); return t == null ? LongTag.ZERO_VALUE : t.asLong(); } + /** + * Get value as a float. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public float getFloat(String key) { FloatTag t = getFloatTag(key); return t == null ? FloatTag.ZERO_VALUE : t.asFloat(); } + /** + * Get value as a double. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public double getDouble(String key) { DoubleTag t = getDoubleTag(key); return t == null ? DoubleTag.ZERO_VALUE : t.asDouble(); } + /** + * Get value as a string. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public String getString(String key) { StringTag t = getStringTag(key); return t == null ? StringTag.ZERO_VALUE : t.getValue(); } + /** + * Get value as a byte array. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public byte[] getByteArray(String key) { ByteArrayTag t = getByteArrayTag(key); return t == null ? ByteArrayTag.ZERO_VALUE : t.getValue(); } + /** + * Get value as an int array. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public int[] getIntArray(String key) { IntArrayTag t = getIntArrayTag(key); return t == null ? IntArrayTag.ZERO_VALUE : t.getValue(); } + /** + * Get value as a long array. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped, or null if this map contains no mapping for the key + */ public long[] getLongArray(String key) { LongArrayTag t = getLongArrayTag(key); return t == null ? LongArrayTag.ZERO_VALUE : t.getValue(); } + /** + * Associates the specified value with the specified key in this map (optional operation). If the map previously + * contained a mapping for the key, the old value is replaced by the specified value. + * + * @param key key with which the specified value is to be associated value + * @param tag value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag put(String key, Tag tag) { return getValue().put(Objects.requireNonNull(key), Objects.requireNonNull(tag)); } + /** + * Inserts the boolean value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putBoolean(String key, boolean value) { return put(key, new ByteTag(value)); } + /** + * Inserts the byte value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putByte(String key, byte value) { return put(key, new ByteTag(value)); } + /** + * Inserts the short value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putShort(String key, short value) { return put(key, new ShortTag(value)); } + /** + * Inserts the int value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putInt(String key, int value) { return put(key, new IntTag(value)); } + /** + * Inserts the long value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putLong(String key, long value) { return put(key, new LongTag(value)); } + /** + * Inserts the float value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putFloat(String key, float value) { return put(key, new FloatTag(value)); } + /** + * Inserts the double value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putDouble(String key, double value) { return put(key, new DoubleTag(value)); } + /** + * Inserts the string value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putString(String key, String value) { return put(key, new StringTag(value)); } + /** + * Inserts the byte array value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putByteArray(String key, byte[] value) { return put(key, new ByteArrayTag(value)); } + /** + * Inserts the int array value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putIntArray(String key, int[] value) { return put(key, new IntArrayTag(value)); } + /** + * Inserts the long array value into this compound tag. + * + * @param key key with which the specified value is to be associated value + * @param value value to be associated with the specified key + * @return the previous value associated with key, or null if there was no mapping for key + */ public Tag putLongArray(String key, long[] value) { return put(key, new LongArrayTag(value)); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/DoubleTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/DoubleTag.java index ce4affa..68ea97f 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/DoubleTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/DoubleTag.java @@ -1,15 +1,33 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A double NBT tag. + */ public class DoubleTag extends NumberTag implements Comparable { + /** + * The double tag discriminator. + */ public static final byte ID = 6; + + /** + * The default value. + */ public static final double ZERO_VALUE = 0.0D; + /** + * A double tag with the default value. + */ public DoubleTag() { super(ZERO_VALUE); } + /** + * A double tag. + * + * @param value The inner value + */ public DoubleTag(double value) { super(value); } @@ -19,6 +37,11 @@ public byte getID() { return ID; } + /** + * Set a new value. + * + * @param value The new value + */ public void setValue(double value) { super.setValue(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/EndTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/EndTag.java index a845a23..111579b 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/EndTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/EndTag.java @@ -1,11 +1,24 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * An end NBT tag. Used to represent the lack of value, like a {@code null}. + */ public final class EndTag extends Tag { + /** + * The end tag discriminator. + */ public static final byte ID = 0; + + /** + * The default value. + */ public static final EndTag INSTANCE = new EndTag(); + /** + * An end tag. + */ private EndTag() { super(null); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/FloatTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/FloatTag.java index 55fd580..b5e5223 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/FloatTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/FloatTag.java @@ -1,15 +1,32 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A float NBT tag. + */ public class FloatTag extends NumberTag implements Comparable { + /** + * The float tag discriminator. + */ public static final byte ID = 5; + + /** + * The default value. + */ public static final float ZERO_VALUE = 0.0F; + /** + * A float tag with the default value. + */ public FloatTag() { super(ZERO_VALUE); } + /** + * A float tag. + * @param value The inner value + */ public FloatTag(float value) { super(value); } @@ -19,6 +36,11 @@ public byte getID() { return ID; } + /** + * Set a new value. + * + * @param value The new value + */ public void setValue(float value) { super.setValue(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntArrayTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntArrayTag.java index 54fc578..294eb85 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntArrayTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntArrayTag.java @@ -3,15 +3,32 @@ import java.util.Arrays; +/** + * An int array NBT tag. + */ public class IntArrayTag extends ArrayTag implements Comparable { + /** + * The int array tag discriminator. + */ public static final byte ID = 11; + + /** + * The default value. + */ public static final int[] ZERO_VALUE = new int[0]; + /** + * An empty int array tag. + */ public IntArrayTag() { super(ZERO_VALUE); } + /** + * An int array tag. + * @param value The inner value + */ public IntArrayTag(int[] value) { super(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntTag.java index 4e9c672..f45b59f 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/IntTag.java @@ -1,15 +1,32 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * An int NBT tag. + */ public class IntTag extends NumberTag implements Comparable { + /** + * The int tag discriminator. + */ public static final byte ID = 3; + + /** + * The default value. + */ public static final int ZERO_VALUE = 0; + /** + * An int tag with the default value. + */ public IntTag() { super(ZERO_VALUE); } + /** + * An int tag. + * @param value The inner value + */ public IntTag(int value) { super(value); } @@ -19,6 +36,11 @@ public byte getID() { return ID; } + /** + * Set a new value. + * + * @param value The new value + */ public void setValue(int value) { super.setValue(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ListTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ListTag.java index f4971fc..66b603a 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ListTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ListTag.java @@ -9,20 +9,33 @@ import java.util.Objects; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.NonNull; + import net.sandrohc.schematic4j.nbt.MaxDepthIO; /** * ListTag represents a typed List in the nbt structure. * An empty {@link ListTag} will be of type {@link EndTag} (unknown type). - * The type of an empty untyped {@link ListTag} can be set by using any of the {@code add()} + * The type of empty untyped {@link ListTag} can be set by using any of the {@code add()} * methods or any of the {@code as...List()} methods. - * */ + * + * @param The type of the list entries + */ public class ListTag> extends Tag> implements Iterable, Comparable>, MaxDepthIO { + /** + * The list tag discriminator. + */ public static final byte ID = 9; + /** + * The type of the list entries. + */ private Class typeClass = null; + /** + * A list tag. + */ private ListTag() { super(createEmptyValue(3)); } @@ -31,14 +44,15 @@ private ListTag() { public byte getID() { return ID; } - + /** - *

Creates a non-type-safe ListTag. Its element type will be set after the first + *

Creates a non-type-safe ListTag. Its element type will be set after the first * element was added.

- * - *

This is an internal helper method for cases where the element type is not known + * + *

This is an internal helper method for cases where the element type is not known * at construction time. Use {@link #ListTag(Class)} when the type is known.

- * + * + * @param typeClass The type of the list entries * @return A new non-type-safe ListTag */ public static ListTag createUnchecked(Class typeClass) { @@ -50,10 +64,10 @@ public static ListTag createUnchecked(Class typeClass) { /** *

Creates an empty mutable list to be used as empty value of ListTags.

* - * @param Type of the list elements + * @param Type of the list elements * @param initialCapacity The initial capacity of the returned List * @return An instance of {@link java.util.List} with an initial capacity of 3 - * */ + */ private static List createEmptyValue(int initialCapacity) { return new ArrayList<>(initialCapacity); } @@ -61,7 +75,7 @@ private static List createEmptyValue(int initialCapacity) { /** * @param typeClass The exact class of the elements * @throws IllegalArgumentException When {@code typeClass} is {@link EndTag}{@code .class} - * @throws NullPointerException When {@code typeClass} is {@code null} + * @throws NullPointerException When {@code typeClass} is {@code null} */ public ListTag(Class typeClass) throws IllegalArgumentException, NullPointerException { super(createEmptyValue(3)); @@ -71,36 +85,83 @@ public ListTag(Class typeClass) throws IllegalArgumentException, Null this.typeClass = Objects.requireNonNull(typeClass); } + /** + * Get the type of the entries in this list. + * + * @return The type of the entries in this list + */ public Class getTypeClass() { return typeClass == null ? EndTag.class : typeClass; } + /** + * Returns the number of elements in this list. If this list contains more than Integer.MAX_VALUE elements, + * returns Integer.MAX_VALUE. + * + * @return the number of elements in this list + */ public int size() { return getValue().size(); } + /** + * Removes the element at the specified position in this list (optional operation). Shifts any subsequent elements + * to the left (subtracts one from their indices). Returns the element that was removed from the list. + * + * @param index the index of the element to be removed + * @return the element previously at the specified position + */ public T remove(int index) { return getValue().remove(index); } + /** + * Removes all the elements from this list (optional operation). The list will be empty after this call returns. + */ public void clear() { getValue().clear(); } + /** + * Returns true if this list contains the specified element. More formally, returns true if and only if this list + * contains at least one element e such that (o==null ? e==null : o.equals(e)). + * + * @param t element whose presence in this list is to be tested + * @return true if this list contains the specified element + */ public boolean contains(T t) { return getValue().contains(t); } + /** + * Returns true if this list contains all of the elements of the specified collection. + * + * @param tags collection to be checked for containment in this list + * @return true if this list contains all the elements of the specified collection + */ public boolean containsAll(Collection> tags) { return getValue().containsAll(tags); } + /** + * Sorts this list according to the order induced by the specified Comparator. + *

+ * All elements in this list must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) + * must not throw a ClassCastException for any elements e1 and e2 in the list). + *

+ * If the specified comparator is null then all elements in this list must implement the Comparable interface and + * the elements' natural ordering should be used. + *

+ * This list must be modifiable, but need not be resizable. + * + * @param comparator the Comparator used to compare list elements. A null value indicates that the elements' natural ordering should be used + */ public void sort(Comparator comparator) { getValue().sort(comparator); } @Override - public Iterator iterator() { + public @NonNull Iterator iterator() { return getValue().iterator(); } @@ -109,18 +170,33 @@ public void forEach(Consumer action) { getValue().forEach(action); } + /** + * Replaces the element at the specified position in this list with the specified element (optional operation). + * + * @param index index of the element to replace element + * @param t element to be stored at the specified position + * @return the element previously at the specified position + */ public T set(int index, T t) { return getValue().set(index, Objects.requireNonNull(t)); } /** * Adds a Tag to this ListTag after the last index. + * * @param t The element to be added. - * */ + */ public void add(T t) { add(size(), t); } + /** + * Inserts the specified element at the specified position in this list (optional operation). Shifts the element + * currently at that position (if any) and any subsequent elements to the right (adds one to their indices). + * + * @param index index at which the specified element is to be inserted element + * @param t element to be inserted + */ public void add(int index, T t) { Objects.requireNonNull(t); if (getTypeClass() == EndTag.class) { @@ -134,12 +210,23 @@ public void add(int index, T t) { getValue().add(index, t); } + /** + * Add all entries in collection to the list tag. + * + * @param t Entries to add + */ public void addAll(Collection t) { for (T tt : t) { add(tt); } } + /** + * Add all entries in collection to the list tag at a specific index. + * + * @param index The index to insert the new values + * @param t Entries to add + */ public void addAll(int index, Collection t) { int i = 0; for (T tt : t) { @@ -148,104 +235,238 @@ public void addAll(int index, Collection t) { } } + /** + * Add a boolean value. + * + * @param value The new value + */ public void addBoolean(boolean value) { addUnchecked(new ByteTag(value)); } + /** + * Add a byte value. + * + * @param value The new value + */ public void addByte(byte value) { addUnchecked(new ByteTag(value)); } + /** + * Add a short value. + * + * @param value The new value + */ public void addShort(short value) { addUnchecked(new ShortTag(value)); } + /** + * Add an int value. + * + * @param value The new value + */ public void addInt(int value) { addUnchecked(new IntTag(value)); } + /** + * Add a long value. + * + * @param value The new value + */ public void addLong(long value) { addUnchecked(new LongTag(value)); } + /** + * Add a float value. + * + * @param value The new value + */ public void addFloat(float value) { addUnchecked(new FloatTag(value)); } + /** + * Add a double value. + * + * @param value The new value + */ public void addDouble(double value) { addUnchecked(new DoubleTag(value)); } + /** + * Add a string value. + * + * @param value The new value + */ public void addString(String value) { addUnchecked(new StringTag(value)); } + /** + * Add a byte array value. + * + * @param value The new value + */ public void addByteArray(byte[] value) { addUnchecked(new ByteArrayTag(value)); } + /** + * Add an int array value. + * + * @param value The new value + */ public void addIntArray(int[] value) { addUnchecked(new IntArrayTag(value)); } + /** + * Add a long array value. + * + * @param value The new value + */ public void addLongArray(long[] value) { addUnchecked(new LongArrayTag(value)); } + /** + * Returns the element at the specified position in this list. + * + * @param index index of the element to return + * @return the element at the specified position in this list + * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= size()) + */ public T get(int index) { return getValue().get(index); } + /** + * Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not + * contain the element. More formally, returns the lowest index i such that + * (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index. + * + * @param t element to search for + * @return the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element + * @throws ClassCastException if the type of the specified element is incompatible with this list (optional) + * @throws NullPointerException if the specified element is null and this list does not permit null elements (optional) + */ public int indexOf(T t) { return getValue().indexOf(t); } + /** + * Coerces this list tag into a specific type. + * + * @param type The type to coerce into + * @param The type to coerce into + * @return The coerced list tag + */ @SuppressWarnings("unchecked") public > ListTag asTypedList(Class type) { checkTypeClass(type); return (ListTag) this; } + /** + * Coerces this list tag into a byte tag list. + * + * @return The coerced list tag + */ public ListTag asByteTagList() { return asTypedList(ByteTag.class); } + /** + * Coerces this list tag into a short tag list. + * + * @return The coerced list tag + */ public ListTag asShortTagList() { return asTypedList(ShortTag.class); } + /** + * Coerces this list tag into an int tag list. + * + * @return The coerced list tag + */ public ListTag asIntTagList() { return asTypedList(IntTag.class); } + /** + * Coerces this list tag into a long tag list. + * + * @return The coerced list tag + */ public ListTag asLongTagList() { return asTypedList(LongTag.class); } + /** + * Coerces this list tag into a float tag list. + * + * @return The coerced list tag + */ public ListTag asFloatTagList() { return asTypedList(FloatTag.class); } + /** + * Coerces this list tag into a double tag list. + * + * @return The coerced list tag + */ public ListTag asDoubleTagList() { return asTypedList(DoubleTag.class); } + /** + * Coerces this list tag into a string tag list. + * + * @return The coerced list tag + */ public ListTag asStringTagList() { return asTypedList(StringTag.class); } + /** + * Coerces this list tag into a byte array tag list. + * + * @return The coerced list tag + */ public ListTag asByteArrayTagList() { return asTypedList(ByteArrayTag.class); } + /** + * Coerces this list tag into an int array tag list. + * + * @return The coerced list tag + */ public ListTag asIntArrayTagList() { return asTypedList(IntArrayTag.class); } + /** + * Coerces this list tag into a long array tag list. + * + * @return The coerced list tag + */ public ListTag asLongArrayTagList() { return asTypedList(LongArrayTag.class); } + /** + * Coerces this list tag into a list of list tags. + * + * @return The coerced list tag + */ @SuppressWarnings("unchecked") public ListTag> asListTagList() { checkTypeClass(ListTag.class); @@ -253,6 +474,11 @@ public ListTag> asListTagList() { return (ListTag>) this; } + /** + * Coerces this list tag into a compound tag list. + * + * @return The coerced list tag + */ public ListTag asCompoundTagList() { return asTypedList(CompoundTag.class); } @@ -305,6 +531,11 @@ public ListTag clone() { return copy; } + /** + * Inserts the specified element without confirming if it is the same type as the list. + * + * @param tag element to be inserted + */ @SuppressWarnings("unchecked") public void addUnchecked(Tag tag) { if (getTypeClass() != EndTag.class && typeClass != tag.getClass()) { @@ -315,6 +546,10 @@ public void addUnchecked(Tag tag) { add(size(), (T) tag); } + /** + * Check the type of the entries on this list tag. + * @param clazz The expected type + */ private void checkTypeClass(Class clazz) { if (getTypeClass() != EndTag.class && typeClass != clazz) { throw new ClassCastException(String.format( diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongArrayTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongArrayTag.java index 51a2ff5..6915982 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongArrayTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongArrayTag.java @@ -3,15 +3,32 @@ import java.util.Arrays; +/** + * A long array NBT tag. + */ public class LongArrayTag extends ArrayTag implements Comparable { + /** + * The long array tag discriminator. + */ public static final byte ID = 12; + + /** + * The default value. + */ public static final long[] ZERO_VALUE = new long[0]; + /** + * An empty long array tag. + */ public LongArrayTag() { super(ZERO_VALUE); } + /** + * A long array tag. + * @param value The inner value + */ public LongArrayTag(long[] value) { super(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongTag.java index 3b5cc2d..0e5ebd8 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/LongTag.java @@ -1,15 +1,32 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A long NBT tag. + */ public class LongTag extends NumberTag implements Comparable { + /** + * The long tag discriminator. + */ public static final byte ID = 4; + + /** + * The default value. + */ public static final long ZERO_VALUE = 0L; + /** + * A long tag with the default value. + */ public LongTag() { super(ZERO_VALUE); } + /** + * A long tag. + * @param value The inner value + */ public LongTag(long value) { super(value); } @@ -19,6 +36,11 @@ public byte getID() { return ID; } + /** + * Set a new value. + * + * @param value The new value + */ public void setValue(long value) { super.setValue(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/NonNullEntrySet.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/NonNullEntrySet.java index 84454a8..06d5e31 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/NonNullEntrySet.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/NonNullEntrySet.java @@ -6,13 +6,18 @@ import java.util.Map; import java.util.Set; +import org.checkerframework.checker.nullness.qual.NonNull; + /** * A decorator for the Set returned by CompoundTag#entrySet() * that disallows setting null values. * */ class NonNullEntrySet implements Set> { - private Set> set; + /** + * The inner set. + */ + private final Set> set; NonNullEntrySet(Set> set) { this.set = set; @@ -34,17 +39,17 @@ public boolean contains(Object o) { } @Override - public Iterator> iterator() { + public @NonNull Iterator> iterator() { return new NonNullEntrySetIterator(set.iterator()); } @Override - public Object[] toArray() { + public Object @NonNull [] toArray() { return set.toArray(); } @Override - public T[] toArray(T[] a) { + public T @NonNull [] toArray(T @NonNull [] a) { return set.toArray(a); } @@ -59,22 +64,22 @@ public boolean remove(Object o) { } @Override - public boolean containsAll(Collection c) { + public boolean containsAll(@NonNull Collection c) { return set.containsAll(c); } @Override - public boolean addAll(Collection> c) { + public boolean addAll(@NonNull Collection> c) { return set.addAll(c); } @Override - public boolean retainAll(Collection c) { + public boolean retainAll(@NonNull Collection c) { return set.retainAll(c); } @Override - public boolean removeAll(Collection c) { + public boolean removeAll(@NonNull Collection c) { return set.removeAll(c); } @@ -85,7 +90,7 @@ public void clear() { class NonNullEntrySetIterator implements Iterator> { - private Iterator> iterator; + private final Iterator> iterator; NonNullEntrySetIterator(Iterator> iterator) { this.iterator = iterator; @@ -104,7 +109,7 @@ public Map.Entry next() { class NonNullEntry implements Map.Entry { - private Map.Entry entry; + private final Map.Entry entry; NonNullEntry(Map.Entry entry) { this.entry = entry; diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/NumberTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/NumberTag.java index f08841d..afc53bb 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/NumberTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/NumberTag.java @@ -1,8 +1,23 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A generic numeric NBT tag. + * + * @see ByteTag + * @see ShortTag + * @see IntTag + * @see LongTag + * @see FloatTag + * @see DoubleTag + */ public abstract class NumberTag> extends Tag { + /** + * A number tag. + * + * @param value The inner value + */ public NumberTag(T value) { super(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ShortTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ShortTag.java index d9ee2ba..39299ec 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/ShortTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/ShortTag.java @@ -1,15 +1,32 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A short NBT tag. + */ public class ShortTag extends NumberTag implements Comparable { + /** + * The short tag discriminator. + */ public static final byte ID = 2; + + /** + * The default value. + */ public static final short ZERO_VALUE = 0; + /** + * A short tag with the default value. + */ public ShortTag() { super(ZERO_VALUE); } + /** + * A short tag. + * @param value The inner value + */ public ShortTag(short value) { super(value); } @@ -19,6 +36,11 @@ public byte getID() { return ID; } + /** + * Set a new value. + * + * @param value The new value + */ public void setValue(short value) { super.setValue(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/StringTag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/StringTag.java index 2d8268f..4a05003 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/StringTag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/StringTag.java @@ -1,15 +1,32 @@ /* Vendored version of Quertz NBT 6.1 - https://github.com/Querz/NBT */ package net.sandrohc.schematic4j.nbt.tag; +/** + * A string NBT tag. + */ public class StringTag extends Tag implements Comparable { + /** + * The string tag discriminator. + */ public static final byte ID = 8; + + /** + * The default value. + */ public static final String ZERO_VALUE = ""; + /** + * An empty string tag. + */ public StringTag() { super(ZERO_VALUE); } + /** + * A string tag. + * @param value The inner value + */ public StringTag(String value) { super(value); } diff --git a/src/main/java/net/sandrohc/schematic4j/nbt/tag/Tag.java b/src/main/java/net/sandrohc/schematic4j/nbt/tag/Tag.java index 6900e0d..8d10044 100644 --- a/src/main/java/net/sandrohc/schematic4j/nbt/tag/Tag.java +++ b/src/main/java/net/sandrohc/schematic4j/nbt/tag/Tag.java @@ -41,6 +41,9 @@ public abstract class Tag implements Cloneable { * */ public static final int DEFAULT_MAX_DEPTH = 512; + /** + * Map of characters and their escaped counterparts. + */ private static final Map ESCAPE_CHARACTERS; static { final Map temp = new HashMap<>(); @@ -162,7 +165,6 @@ public int hashCode() { * Creates a clone of this Tag. * @return A clone of this Tag. * */ - @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") public abstract Tag clone(); /** diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/LitematicaSchematic.java b/src/main/java/net/sandrohc/schematic4j/schematic/LitematicaSchematic.java index e3ab9aa..c957b97 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/LitematicaSchematic.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/LitematicaSchematic.java @@ -32,9 +32,11 @@ public class LitematicaSchematic implements Schematic { public int version = 1; /** - * Specifies the data version of Minecraft that was used to create the schematic. This is to allow for block and - * entity data to be validated and auto-converted from older versions. This is dependent on the Minecraft version, - * e.g. Minecraft 1.12.2's data version is 1343. + * Specifies the data version of Minecraft that was used to create the schematic. + *

+ * This is to allow for block and entity data to be validated and auto-converted from older versions. + * This is dependent on the Minecraft version, e.g. Minecraft 1.12.2's data version is + * 1343. */ public @Nullable Integer minecraftDataVersion; @@ -43,17 +45,35 @@ public class LitematicaSchematic implements Schematic { */ public @NonNull Metadata metadata = new Metadata(); + /** + * The regions that compose this schematic. They can be thought of as their own little schematics. + */ public Region @NonNull [] regions = new Region[0]; + /** + * A Litematica schematic. + */ public LitematicaSchematic() { } + /** + * A Litematica schematic + * + * @param version The schematic version + * @param minecraftDataVersion The schematic Minecraft data version + * @param metadata The schematic metadata + * @param regions The schematic regions + */ public LitematicaSchematic(int version, @Nullable Integer minecraftDataVersion, @Nullable Metadata metadata, Region @Nullable [] regions) { this.version = version; this.minecraftDataVersion = minecraftDataVersion; - this.metadata = metadata != null ? metadata : new Metadata(); - this.regions = regions != null ? regions : new Region[0]; + if (metadata != null) { + this.metadata = metadata; + } + if (regions != null) { + this.regions = regions; + } } @Override @@ -117,6 +137,11 @@ public int[] offset() { return Arrays.stream(regions).flatMap(r -> Arrays.stream(r.entities)); } + /** + * The regions that compose this schematic. They can be thought of as their own little schematics. + * + * @return The regions + */ public @NonNull Region[] regions() { return regions; } @@ -136,10 +161,24 @@ public int[] offset() { return metadata.timeCreated; } + /** + * Specifies the data version of Minecraft that was used to create the schematic. + *

+ * This is to allow for block and entity data to be validated and auto-converted from older versions. + * This is dependent on the Minecraft version, e.g. Minecraft 1.12.2's data version is + * 1343. + * + * @return The Minecraft data version + */ public @Nullable Integer dataVersion() { return minecraftDataVersion; } + /** + * The optional metadata about the schematic. + * + * @return The schematic metadata + */ public @NonNull Metadata metadata() { return metadata; } @@ -155,6 +194,9 @@ public String toString() { ']'; } + /** + * The schematic metadata. + */ public static class Metadata { /** * The name of the schematic. @@ -181,16 +223,34 @@ public static class Metadata { */ public @Nullable LocalDateTime timeModified; + /** + * The size of the schematic including all regions. + */ public @Nullable SchematicBlockPos enclosingSize; + /** + * The number of regions inside this schematic. + */ public @Nullable Integer regionCount; + /** + * The total number of blocks from all the regions that compose this schematic. Does not include air blocks. + */ public @Nullable Long totalBlocks; + /** + * The total volume of blocks from all the regions that compose this schematic. This includes air blocks. + */ public @Nullable Long totalVolume; + /** + * Schematic thumbnail, if available. + */ public int @Nullable [] previewImageData; + /** + * Extra metadata not represented in the specification. + */ public @NonNull Map extra; public Metadata(@Nullable String name, @Nullable String description, @Nullable String author, @@ -226,15 +286,68 @@ public String toString() { } } + /** + * A schematic region. + *

+ * It can be thought of as its own little schematics, since it contains a unique size and block palette. + */ public static class Region { + /** + * The region name. + */ public @Nullable String name; + + /** + * The region position in reference to the schematic origin at (0, 0, 0). + */ public @NonNull SchematicBlockPos position; + + /** + * The region size. + */ public @NonNull SchematicBlockPos size; + + /** + * The encoded (but unpacked) block states. Each index represents a block position and each value represents + * an index in the {@link Region#blockStatePalette}. + *

+ * Each index is encoded as {@code x + (z * regionSize.x) (y * regionSize.x * regionSize.z)} and can be decoded as follows: + *

+		 * int x = index % regionSize.x;
+		 * int z = (index / regionSize.x) % regionSize.z;
+		 * int y = index / (regionSize.x * regionSize.z);
+		 * 
+ * + * @see Region#indexToPos(int) to convert an index to a block position + * @see Region#posToIndex(int, int, int) to convert a block position to an index + */ public int @NonNull [] blockStates; + + /** + * The block state palette. Each entry in the array represents a unique block state in this schematic region. + *

+ * The values in {@link Region#blockStates} are indices to this array. + */ public SchematicBlock @NonNull [] blockStatePalette; + + /** + * The block/tile entities in this schematic region. + */ public SchematicBlockEntity @NonNull [] blockEntities; + + /** + * The entities in this schematic region. + */ public SchematicEntity @NonNull [] entities; + + /** + * The list of blocks with pending tick calculations. + */ public PendingTicks @NonNull [] pendingBlockTicks; + + /** + * The list of fluids with pending tick calculations. + */ public PendingTicks @NonNull [] pendingFluidTicks; public Region(@Nullable String name, @Nullable SchematicBlockPos position, @Nullable SchematicBlockPos size, @@ -267,6 +380,99 @@ public int posToIndex(int x, int y, int z) { return new SchematicBlockPos(x, y, z); } + /** + * The region name. + * + * @return The region name + */ + public @Nullable String name() { + return name; + } + + /** + * The region position in reference to the schematic origin at (0, 0, 0). + * + * @return The region position + */ + public @NonNull SchematicBlockPos position() { + return position; + } + + /** + * The region size. + * + * @return The region size + */ + public @NonNull SchematicBlockPos size() { + return size; + } + + /** + * The encoded (but unpacked) block states. Each index represents a block position and each value represents + * an index in the {@link Region#blockStatePalette}. + *

+ * Each index is encoded as {@code x + (z * regionSize.x) (y * regionSize.x * regionSize.z)} and can be decoded as follows: + *

+		 * int x = index % regionSize.x;
+		 * int z = (index / regionSize.x) % regionSize.z;
+		 * int y = index / (regionSize.x * regionSize.z);
+		 * 
+ * + * @return The encoded (but unpacked) block states + * @see Region#indexToPos(int) to convert an index to a block position + * @see Region#posToIndex(int, int, int) to convert a block position to an index + */ + public int @NonNull [] blockStates() { + return blockStates; + } + + /** + * The block state palette. Each entry in the array represents a unique block state in this schematic region. + *

+ * The values in {@link Region#blockStates} are indices to this array. + * + * @return The block state palette + */ + public SchematicBlock @NonNull [] blockStatePalette() { + return blockStatePalette; + } + + /** + * The block/tile entities in this schematic region. + * + * @return The block entities in this region + */ + public SchematicBlockEntity @NonNull [] blockEntities() { + return blockEntities; + } + + /** + * The entities in this schematic region. + * + * @return The entities in this region + */ + public SchematicEntity @NonNull [] entities() { + return entities; + } + + /** + * The list of blocks with pending tick calculations. + * + * @return The blocks pending ticks + */ + public PendingTicks @NonNull [] pendingBlockTicks() { + return pendingBlockTicks; + } + + /** + * The list of fluids with pending tick calculations. + * + * @return The fluids pending ticks + */ + public PendingTicks @NonNull [] pendingFluidTicks() { + return pendingFluidTicks; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -297,12 +503,38 @@ public String toString() { } } + /** + * Represents a block or fluid pending tick calculations. + */ public static class PendingTicks { + /** + * The pending tick priority. + */ public @Nullable Integer priority; + + /** + * The sub-tick. + */ public @Nullable Long subTick; + + /** + * The time. + */ public @Nullable Integer time; + + /** + * The X coordinate inside the region it is found. + */ public @Nullable Integer x; + + /** + * The Y coordinate inside the region it is found. + */ public @Nullable Integer y; + + /** + * The Z coordinate inside the region it is found. + */ public @Nullable Integer z; } } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/Schematic.java b/src/main/java/net/sandrohc/schematic4j/schematic/Schematic.java index b2eab8a..aea2ceb 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/Schematic.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/Schematic.java @@ -19,6 +19,8 @@ import net.sandrohc.schematic4j.schematic.types.SchematicEntity; import net.sandrohc.schematic4j.schematic.types.SchematicItem; +import static net.sandrohc.schematic4j.schematic.types.SchematicBlock.AIR; + /** * A generic schematic. */ @@ -62,21 +64,37 @@ public interface Schematic { int[] offset(); /** - * The block at the specified block. + * The block at the specified position. *

* Depending on the schematic format, each coordinate can also be negative and is relative to the schematic origin. * * @param x The X coordinate, can be a negative value - * @param y The X coordinate, can be a negative value - * @param z The X coordinate, can be a negative value + * @param y The Y coordinate, can be a negative value + * @param z The Z coordinate, can be a negative value * @return block, or {@code null} if information is not available. */ @NonNull SchematicBlock block(int x, int y, int z); + /** + * The block at the specified position. + *

+ * Depending on the schematic format, each coordinate can also be negative and is relative to the schematic origin. + * + * @param pos The position + * @return block, or {@code null} if information is not available. + * @see Schematic#block(int, int, int) + */ + default @NonNull SchematicBlock block(@Nullable SchematicBlockPos pos) { + if (pos == null) { + return AIR; + } + return block(pos.x, pos.y, pos.z); + } + /** * Iterate over the list of blocks. Follows a zigzag pattern: first visits X, then Z, then Y. * - * @return an iterator + * @return An iterator over block and position pairs */ default @NonNull Stream> blocks() { return IntStream.range(0, width() * length() * height()).mapToObj(index -> { @@ -108,12 +126,12 @@ public interface Schematic { } /** - * The biome at the specified block. + * The biome at the specified position. * * @param x the X coordinate * @param y the Y coordinate * @param z the Z coordinate - * @return biome, or {@code null} if information is not available. + * @return biome, or {@code SchematicBiome.AIR} if information is not available. */ default @NonNull SchematicBiome biome(int x, int y, int z) { return SchematicBiome.AIR; @@ -122,7 +140,7 @@ public interface Schematic { /** * Iterate over the list of biomes. Follows a zigzag pattern: first visits X, then Z, then Y. * - * @return an iterator + * @return An iterator over biome and position pairs */ default @NonNull Stream> biomes() { return IntStream.range(0, width() * length() * height()).mapToObj(index -> { @@ -154,7 +172,7 @@ public interface Schematic { } /** - * The date that this schematic was created on. + * The date that this schematic was created on. Assumes time is in the UTC timezone. * * @return creation date, or {@code null} if information is not available. */ diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/SchematicaSchematic.java b/src/main/java/net/sandrohc/schematic4j/schematic/SchematicaSchematic.java index abbf6c4..e7350e8 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/SchematicaSchematic.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/SchematicaSchematic.java @@ -34,18 +34,56 @@ public class SchematicaSchematic implements Schematic { public static final String MATERIAL_ALPHA = "Alpha"; public static final String MATERIAL_STRUCTURE = "Structure"; + /** + * The schematic width, the X axis. + */ public final int width; + + /** + * The schematic height, the Y axis. + */ public final int height; + + /** + * The schematic length, the Z axis. + */ public final int length; + + /** + * The unpacked list of blocks. + */ public final @NonNull SchematicBlock[][][] blocks; - public final SchematicBlockEntity[] blockEntities; - public final SchematicEntity[] entities; - public final SchematicItem icon; - public final String materials; + + /** + * The list of block/tile entities. + */ + public final @NonNull SchematicBlockEntity[] blockEntities; + + /** + * The list of entities. + */ + public final @NonNull SchematicEntity[] entities; + + /** + * The schematic icon, if available. + */ + public final @Nullable SchematicItem icon; + + /** + * The schematic materials, if available. + *

+ * One of: + *

    + *
  • {@link SchematicaSchematic#MATERIAL_CLASSIC MATERIAL_CLASSIC}
  • + *
  • {@link SchematicaSchematic#MATERIAL_ALPHA MATERIAL_ALPHA}
  • + *
  • {@link SchematicaSchematic#MATERIAL_STRUCTURE MATERIAL_STRUCTURE}
  • + *
+ */ + public final @Nullable String materials; public SchematicaSchematic(int width, int height, int length, @NonNull SchematicBlock[][][] blocks, @NonNull SchematicBlockEntity[] blockEntities, @NonNull SchematicEntity[] entities, - SchematicItem icon, String materials) { + @Nullable SchematicItem icon, @Nullable String materials) { this.width = width; this.height = height; @@ -91,6 +129,11 @@ public int[] offset() { return blocks[x][y][z]; } + /** + * The raw block data. + * + * @return The raw block data + */ public @NonNull SchematicBlock[][][] blockData() { return blocks; } @@ -100,6 +143,11 @@ public int[] offset() { return Arrays.stream(blockEntities); } + /** + * The raw block entity data. + * + * @return The raw block entity data + */ public @NonNull SchematicBlockEntity[] blockEntityData() { return blockEntities; } @@ -109,6 +157,11 @@ public int[] offset() { return Arrays.stream(entities); } + /** + * The raw entity data. + * + * @return The raw entity data + */ public @NonNull SchematicEntity[] entityData() { return entities; } @@ -118,6 +171,18 @@ public int[] offset() { return icon; } + /** + * The schematic materials, if available. + *

+ * One of: + *

    + *
  • {@link SchematicaSchematic#MATERIAL_CLASSIC MATERIAL_CLASSIC}
  • + *
  • {@link SchematicaSchematic#MATERIAL_ALPHA MATERIAL_ALPHA}
  • + *
  • {@link SchematicaSchematic#MATERIAL_STRUCTURE MATERIAL_STRUCTURE}
  • + *
+ * + * @return The schematic materials, if available + */ public @Nullable String materials() { return materials; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/SpongeSchematic.java b/src/main/java/net/sandrohc/schematic4j/schematic/SpongeSchematic.java index 7ae78b5..ba9c7ca 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/SpongeSchematic.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/SpongeSchematic.java @@ -34,9 +34,11 @@ public class SpongeSchematic implements Schematic { public int version; /** - * Specifies the data version of Minecraft that was used to create the schematic. This is to allow for block and - * entity data to be validated and auto-converted from older versions. This is dependent on the Minecraft version, - * e.g. Minecraft 1.12.2's data version is 1343. + * Specifies the data version of Minecraft that was used to create the schematic. + *

+ * This is to allow for block and entity data to be validated and auto-converted from older versions. + * This is dependent on the Minecraft version, e.g. Minecraft 1.12.2's data version is + * 1343. */ public @Nullable Integer dataVersion; @@ -66,14 +68,32 @@ public class SpongeSchematic implements Schematic { * not provided is [0, 0, 0]. Example: If a player is pasting from 1, 2, 3, and the offset is 4, 5, 6, then the * first block should be placed at 5, 7, 9 */ - public int[] offset; + public int @NonNull [] offset; + /** + * The unpacked block data. + */ public @NonNull SchematicBlock[][][] blocks; - public SchematicBlockEntity[] blockEntities; - public SchematicEntity[] entities; - public SchematicBiome[][][] biomes; - public final int biomeHeight; + /** + * The block/tile entity data. + */ + public @NonNull SchematicBlockEntity[] blockEntities; + + /** + * The entity data. + */ + public @NonNull SchematicEntity[] entities; + + /** + * The tile entity data. + */ + public @NonNull SchematicBiome[][][] biomes; + + /** + * The biome height. In older versions of the specification, only 2D biome data was supported. + */ + public int biomeHeight; public SpongeSchematic(int version, @Nullable Integer dataVersion, @Nullable Metadata metadata, int width, int height, int length, int[] offset, @NonNull SchematicBlock[][][] blocks, @@ -135,6 +155,11 @@ public int[] offset() { return blocks[x][y][z]; } + /** + * The raw block data. + * + * @return The raw block data + */ public @NonNull SchematicBlock[][][] blockData() { return blocks; } @@ -144,6 +169,11 @@ public int[] offset() { return Arrays.stream(blockEntities); } + /** + * The raw block entity data. + * + * @return The raw block data + */ public @NonNull SchematicBlockEntity[] blockEntityData() { return blockEntities; } @@ -153,6 +183,11 @@ public int[] offset() { return Arrays.stream(entities); } + /** + * The raw entity data. + * + * @return The raw block data + */ public @NonNull SchematicEntity[] entityData() { return entities; } @@ -183,6 +218,11 @@ public int[] offset() { }); } + /** + * The raw biome data. + * + * @return The raw block data + */ public @NonNull SchematicBiome[][][] biomeData() { return biomes; } @@ -202,6 +242,15 @@ public int[] offset() { return metadata.date; } + /** + * Specifies the data version of Minecraft that was used to create the schematic. + *

+ * This is to allow for block and entity data to be validated and auto-converted from older versions. + * This is dependent on the Minecraft version, e.g. Minecraft 1.12.2's data version is + * 1343. + * + * @return The Minecraft data version + */ public @Nullable Integer dataVersion() { return dataVersion; } @@ -214,6 +263,11 @@ public int[] offset() { return dataVersion(); } + /** + * The optional metadata about the schematic. + * + * @return The schematic metadata + */ public @NonNull Metadata metadata() { return metadata; } @@ -237,29 +291,34 @@ public String toString() { ']'; } - + /** + * The schematic metadata. + */ public static class Metadata { /** * The name of the schematic. */ - public final @Nullable String name; + public @Nullable String name; /** * The name of the author of the schematic. */ - public final @Nullable String author; + public @Nullable String author; /** * The date that this schematic was created on. */ - public final @Nullable LocalDateTime date; + public @Nullable LocalDateTime date; /** * An array of mod IDs. */ - public final @NonNull String[] requiredMods; + public @NonNull String[] requiredMods; - public final @NonNull Map extra; + /** + * Extra metadata not represented in the specification. + */ + public @NonNull Map extra; public Metadata(@Nullable String name, @Nullable String author, @Nullable LocalDateTime date, @NonNull String[] requiredMods, @NonNull Map extra) { diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBiome.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBiome.java index 2434150..9f44a04 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBiome.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBiome.java @@ -1,5 +1,8 @@ package net.sandrohc.schematic4j.schematic.types; +/** + * Represents a biome as a resource ID, like "minecraft:plains". + */ public class SchematicBiome extends SchematicBlock { public static final SchematicBiome AIR = new SchematicBiome("minecraft:air"); diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlock.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlock.java index f9b6aca..8e201d8 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlock.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlock.java @@ -6,12 +6,26 @@ import org.checkerframework.checker.nullness.qual.NonNull; +/** + * Represents a block as a resource identifier plus block states, like "minecraft:dirt" or "minecraft:chest[facing=south]". + */ public class SchematicBlock extends SchematicNamed { public static final SchematicBlock AIR = new SchematicBlock("minecraft:air"); - public final @NonNull String block; - public final @NonNull Map states; + /** + * The block name excluding block states. + *
+ * For example, the block state "minecraft:chest[facing=south]" would become just "minecraft:chest". + */ + public @NonNull String block; + + /** + * The list of block states or properties. + *
+ * For example, chests have the "facing", "type" and "waterlogged" properties. + */ + public @NonNull Map states; public SchematicBlock(@NonNull String block, @NonNull Map states) { super(blockNameAndStatesToString(block, states)); @@ -23,10 +37,24 @@ public SchematicBlock(String blockAndStates) { this(extractBlockName(blockAndStates), extractBlockStates(blockAndStates)); } + /** + * The block name excluding block states. + *
+ * For example, the block state "minecraft:chest[facing=south]" would become just "minecraft:chest". + * + * @return The block name + */ public @NonNull String block() { return block; } + /** + * The list of block states or properties. + *
+ * For example, chests have the "facing", "type" and "waterlogged" properties. + * + * @return The block states + */ public @NonNull Map states() { return states; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockEntity.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockEntity.java index afe80dd..5bd09f3 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockEntity.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockEntity.java @@ -11,10 +11,20 @@ import static java.util.stream.Collectors.toMap; import static net.sandrohc.schematic4j.utils.TagUtils.unwrap; +/** + * Represents a block/tile entity, like a chest or a furnace. + */ public class SchematicBlockEntity extends SchematicNamed { - public final SchematicBlockPos pos; - public final Map data; + /** + * The position where they can be found in the schematic. + */ + public SchematicBlockPos pos; + + /** + * Extra NBT data, like the items stored in a chest, if available. + */ + public Map data; public SchematicBlockEntity(String name, SchematicBlockPos pos, Map data) { super(name); @@ -40,10 +50,20 @@ public SchematicBlockEntity(String name, SchematicBlockPos pos, Map extra() { return data; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockPos.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockPos.java index 326c6c6..564798a 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockPos.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicBlockPos.java @@ -8,12 +8,26 @@ import net.sandrohc.schematic4j.nbt.tag.CompoundTag; import net.sandrohc.schematic4j.nbt.tag.Tag; +/** + * Represents a block position. + */ public class SchematicBlockPos implements Comparable { public static final SchematicBlockPos ZERO = new SchematicBlockPos(0, 0, 0); + /** + * The X coordinate. + */ public final int x; + + /** + * The Y coordinate. + */ public final int y; + + /** + * The Z coordinate. + */ public final int z; public SchematicBlockPos(int x, int y, int z) { @@ -53,14 +67,29 @@ public static SchematicBlockPos from(SchematicBlockPos other) { return new SchematicBlockPos(other); } + /** + * The X coordinate. + * + * @return The X coordinate + */ public int x() { return x; } + /** + * The Y coordinate. + * + * @return The Y coordinate + */ public int y() { return y; } + /** + * The Z coordinate. + * + * @return The Z coordinate + */ public int z() { return z; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntity.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntity.java index 88cfa57..795c2b4 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntity.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntity.java @@ -13,10 +13,20 @@ import static net.sandrohc.schematic4j.utils.TagUtils.getString; import static net.sandrohc.schematic4j.utils.TagUtils.unwrap; +/** + * Represents an entity, like a creeper. + */ public class SchematicEntity extends SchematicNamed { - public final SchematicEntityPos pos; - public final Map data; + /** + * The position of the entity on the schematic. + */ + public SchematicEntityPos pos; + + /** + * The extra NBT data the entity is holding, like a wolf's owner. + */ + public Map data; public SchematicEntity(String name, SchematicEntityPos pos, Map data) { super(name); @@ -39,10 +49,20 @@ public SchematicEntity(String name, SchematicEntityPos pos, Map return new SchematicEntity(id, pos, extra); } + /** + * The position of the entity on the schematic. + * + * @return The position of the entity + */ public SchematicEntityPos pos() { return pos; } + /** + * The extra NBT data the entity is holding, like a wolf's owner. + * + * @return The extra NBT data + */ public Map data() { return data; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntityPos.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntityPos.java index 34710b7..14f91bc 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntityPos.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicEntityPos.java @@ -9,10 +9,25 @@ import net.sandrohc.schematic4j.nbt.tag.ListTag; import net.sandrohc.schematic4j.nbt.tag.Tag; +/** + * Represents an entity position with decimal place precision. + */ public class SchematicEntityPos implements Comparable { - public final double x; - public final double y; - public final double z; + + /** + * The X coordinate. + */ + public double x; + + /** + * The Y coordinate. + */ + public double y; + + /** + * The Z coordinate. + */ + public double z; public SchematicEntityPos(double x, double y, double z) { this.x = x; @@ -52,14 +67,29 @@ public static SchematicEntityPos from(SchematicEntityPos other) { return new SchematicEntityPos(other); } + /** + * The X coordinate. + * + * @return The X coordinate + */ public double x() { return x; } + /** + * The Y coordinate. + * + * @return The Y coordinate + */ public double y() { return y; } + /** + * The Z coordinate. + * + * @return The Z coordinate + */ public double z() { return z; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicItem.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicItem.java index 25b329b..fa6c1f0 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicItem.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicItem.java @@ -1,9 +1,19 @@ package net.sandrohc.schematic4j.schematic.types; +/** + * Represents an item, like a stick. + */ public class SchematicItem extends SchematicNamed { - public final int count; - public final int damage; + /** + * The item count, like a stack of 64 sticks. + */ + public int count; + + /** + * The damage amount. + */ + public int damage; public SchematicItem(String name, int count, int damage) { super(name); @@ -11,10 +21,20 @@ public SchematicItem(String name, int count, int damage) { this.damage = damage; } + /** + * The item count, like a stack of 64 sticks. + * + * @return The item count + */ public int count() { return count; } + /** + * The damage amount. + * + * @return The damage amount + */ public int damage() { return damage; } diff --git a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicNamed.java b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicNamed.java index d713bd6..93251ff 100644 --- a/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicNamed.java +++ b/src/main/java/net/sandrohc/schematic4j/schematic/types/SchematicNamed.java @@ -6,13 +6,21 @@ public abstract class SchematicNamed implements Comparable { - public final @NonNull String name; + /** + * The resource name, usually as a resource identifier like "minecraft:dirt". + */ + public @NonNull String name; public SchematicNamed(@NonNull String name) { this.name = name; } - public String name() { + /** + * The resource name. + * + * @return The resource name + */ + public @NonNull String name() { return name; } diff --git a/src/test/java/net/sandrohc/schematic4j/nbt/io/NBTUtilTest.java b/src/test/java/net/sandrohc/schematic4j/nbt/io/NBTUtilTest.java new file mode 100644 index 0000000..6575a46 --- /dev/null +++ b/src/test/java/net/sandrohc/schematic4j/nbt/io/NBTUtilTest.java @@ -0,0 +1,131 @@ +package net.sandrohc.schematic4j.nbt.io; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.junit.jupiter.api.Test; + +import net.sandrohc.schematic4j.nbt.tag.StringTag; +import net.sandrohc.schematic4j.nbt.tag.Tag; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + +public class NBTUtilTest { + + public static final StringTag TAG = new StringTag("TEST"); + + public static final boolean DEFAULT_COMPRESSED = true; + public static final boolean DEFAULT_LITTLE_ENDIAN = false; + + protected static byte[] serialize(Tag tag, boolean compressed, boolean littleEndian) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos)) { + new NBTSerializer(compressed, littleEndian).toStream(new NamedTag(null, tag), dos); + } catch (IOException ex) { + ex.printStackTrace(); + fail(ex.getMessage()); + } + return baos.toByteArray(); + } + + @Test + public void testWriter_invalidParams() throws IOException { + try { + NBTUtil.Writer.write((NamedTag) null).to(new ByteArrayOutputStream()); + fail("did not check null tag"); + } catch (IllegalStateException ignored) { + } + + try { + NBTUtil.Writer.write(TAG).to((OutputStream) null); + fail("did not check null output stream"); + } catch (IllegalStateException ignored) { + } + } + + @Test + public void testWriter_compressionEnabled() throws IOException { + final boolean compressed = true; + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + NBTUtil.Writer.write(TAG).compressed(compressed).to(os); + + assertThat(os.toByteArray()).isEqualTo(serialize(TAG, compressed, DEFAULT_LITTLE_ENDIAN)); + } + + @Test + public void testWriter_compressionDisabled() throws IOException { + final boolean compressed = false; + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + NBTUtil.Writer.write(TAG).compressed(compressed).to(os); + + assertThat(os.toByteArray()).isEqualTo(serialize(TAG, compressed, DEFAULT_LITTLE_ENDIAN)); + } + + @Test + public void testReader_compressionEnabled() throws IOException { + final boolean compressed = true; + final InputStream is = new ByteArrayInputStream(serialize(TAG, compressed, DEFAULT_LITTLE_ENDIAN)); + + final NamedTag tag = NBTUtil.Reader.read().from(is); + + assertThat(tag.getTag()).isEqualTo(TAG); + } + + @Test + public void testReader_compressionDisabled() throws IOException { + final boolean compressed = false; + final InputStream is = new ByteArrayInputStream(serialize(TAG, compressed, DEFAULT_LITTLE_ENDIAN)); + + final NamedTag tag = NBTUtil.Reader.read().from(is); + + assertThat(tag.getTag()).isEqualTo(TAG); + } + + + @Test + public void testWriter_littleEndian() throws IOException { + final boolean littleEndian = true; + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + NBTUtil.Writer.write(TAG).littleEndian().to(os); + + assertThat(os.toByteArray()).isEqualTo(serialize(TAG, DEFAULT_COMPRESSED, littleEndian)); + } + + @Test + public void testWriter_bigEndian() throws IOException { + final boolean littleEndian = false; + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + + NBTUtil.Writer.write(TAG).bigEndian().to(os); + + assertThat(os.toByteArray()).isEqualTo(serialize(TAG, DEFAULT_COMPRESSED, littleEndian)); + } + + @Test + public void testReader_littleEndian() throws IOException { + final boolean littleEndian = true; + final InputStream is = new ByteArrayInputStream(serialize(TAG, DEFAULT_COMPRESSED, littleEndian)); + + final NamedTag tag = NBTUtil.Reader.read().littleEndian().from(is); + + assertThat(tag.getTag()).isEqualTo(TAG); + } + + @Test + public void testReader_bigEndian() throws IOException { + final boolean littleEndian = false; + final InputStream is = new ByteArrayInputStream(serialize(TAG, DEFAULT_COMPRESSED, littleEndian)); + + final NamedTag tag = NBTUtil.Reader.read().bigEndian().from(is); + + assertThat(tag.getTag()).isEqualTo(TAG); + } +}