Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-12-25 15:50:10 +01:00
Update OpenNBT (now ViaNBT)
Dieser Commit ist enthalten in:
Ursprung
d8f98945e2
Commit
3e0eb90662
@ -22,7 +22,7 @@ dependencies {
|
||||
api(libs.fastutil)
|
||||
api(libs.flare)
|
||||
api(libs.flareFastutil)
|
||||
api(libs.openNBT)
|
||||
api(libs.nbt)
|
||||
api(libs.gson)
|
||||
|
||||
compileOnlyApi(libs.snakeYaml)
|
||||
|
@ -1,216 +0,0 @@
|
||||
/*
|
||||
* This file is part of adventure, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2017-2020 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
// Specific Via changes:
|
||||
// - Use OpenNBT tags
|
||||
// - Added readString/writeString methods from TagStringIO
|
||||
// - Has not been updated for the sake of keeping the class simple
|
||||
|
||||
/**
|
||||
* Serialization operations for binary tags.
|
||||
*/
|
||||
public final class BinaryTagIO {
|
||||
private BinaryTagIO() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a compound tag from {@code path}.
|
||||
*
|
||||
* @param path the path
|
||||
* @return the compound tag
|
||||
* @throws IOException if an exception was encountered while reading a compound tag
|
||||
*/
|
||||
public static @NonNull CompoundTag readPath(final @NonNull Path path) throws IOException {
|
||||
return readInputStream(Files.newInputStream(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a compound tag from an input stream.
|
||||
*
|
||||
* @param input the input stream
|
||||
* @return the compound tag
|
||||
* @throws IOException if an exception was encountered while reading a compound tag
|
||||
*/
|
||||
public static @NonNull CompoundTag readInputStream(final @NonNull InputStream input) throws IOException {
|
||||
try (final DataInputStream dis = new DataInputStream(input)) {
|
||||
return readDataInput(dis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a compound tag from {@code path} using GZIP decompression.
|
||||
*
|
||||
* @param path the path
|
||||
* @return the compound tag
|
||||
* @throws IOException if an exception was encountered while reading a compound tag
|
||||
*/
|
||||
public static @NonNull CompoundTag readCompressedPath(final @NonNull Path path) throws IOException {
|
||||
return readCompressedInputStream(Files.newInputStream(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a compound tag from an input stream using GZIP decompression.
|
||||
*
|
||||
* @param input the input stream
|
||||
* @return the compound tag
|
||||
* @throws IOException if an exception was encountered while reading a compound tag
|
||||
*/
|
||||
public static @NonNull CompoundTag readCompressedInputStream(final @NonNull InputStream input) throws IOException {
|
||||
try (final DataInputStream dis = new DataInputStream(new BufferedInputStream(new GZIPInputStream(input)))) {
|
||||
return readDataInput(dis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a compound tag from {@code input}.
|
||||
*
|
||||
* @param input the input
|
||||
* @return the compound tag
|
||||
* @throws IOException if an exception was encountered while reading a compound tag
|
||||
*/
|
||||
public static @NonNull CompoundTag readDataInput(final @NonNull DataInput input) throws IOException {
|
||||
byte type = input.readByte();
|
||||
if (type != CompoundTag.ID) {
|
||||
throw new IOException(String.format("Expected root tag to be a CompoundTag, was %s", type));
|
||||
}
|
||||
input.skipBytes(input.readUnsignedShort()); // read empty name
|
||||
|
||||
final CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.read(input);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a compound tag to {@code path}.
|
||||
*
|
||||
* @param tag the compound tag
|
||||
* @param path the path
|
||||
* @throws IOException if an exception was encountered while writing the compound tag
|
||||
*/
|
||||
public static void writePath(final @NonNull CompoundTag tag, final @NonNull Path path) throws IOException {
|
||||
writeOutputStream(tag, Files.newOutputStream(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a compound tag to an output stream.
|
||||
*
|
||||
* @param tag the compound tag
|
||||
* @param output the output stream
|
||||
* @throws IOException if an exception was encountered while writing the compound tag
|
||||
*/
|
||||
public static void writeOutputStream(final @NonNull CompoundTag tag, final @NonNull OutputStream output) throws IOException {
|
||||
try (final DataOutputStream dos = new DataOutputStream(output)) {
|
||||
writeDataOutput(tag, dos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a compound tag to {@code path} using GZIP compression.
|
||||
*
|
||||
* @param tag the compound tag
|
||||
* @param path the path
|
||||
* @throws IOException if an exception was encountered while writing the compound tag
|
||||
*/
|
||||
public static void writeCompressedPath(final @NonNull CompoundTag tag, final @NonNull Path path) throws IOException {
|
||||
writeCompressedOutputStream(tag, Files.newOutputStream(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a compound tag to an output stream using GZIP compression.
|
||||
*
|
||||
* @param tag the compound tag
|
||||
* @param output the output stream
|
||||
* @throws IOException if an exception was encountered while writing the compound tag
|
||||
*/
|
||||
public static void writeCompressedOutputStream(final @NonNull CompoundTag tag, final @NonNull OutputStream output) throws IOException {
|
||||
try (final DataOutputStream dos = new DataOutputStream(new GZIPOutputStream(output))) {
|
||||
writeDataOutput(tag, dos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a compound tag to {@code output}.
|
||||
*
|
||||
* @param tag the compound tag
|
||||
* @param output the output
|
||||
* @throws IOException if an exception was encountered while writing the compound tag
|
||||
*/
|
||||
public static void writeDataOutput(final @NonNull CompoundTag tag, final @NonNull DataOutput output) throws IOException {
|
||||
output.writeByte(CompoundTag.ID);
|
||||
output.writeUTF(""); // write empty name
|
||||
tag.write(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a compound tag from a {@link String}.
|
||||
*
|
||||
* @param input the string
|
||||
* @return the compound tag
|
||||
* @throws IOException if an exception was encountered while reading a compound tag
|
||||
*/
|
||||
public static @NonNull CompoundTag readString(final @NonNull String input) throws IOException {
|
||||
try {
|
||||
final CharBuffer buffer = new CharBuffer(input);
|
||||
final TagStringReader parser = new TagStringReader(buffer);
|
||||
final CompoundTag tag = parser.compound();
|
||||
if (buffer.skipWhitespace().hasMore()) {
|
||||
throw new IOException("Document had trailing content after first CompoundTag");
|
||||
}
|
||||
return tag;
|
||||
} catch (final StringTagParseException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a compound tag to a {@link String}.
|
||||
*
|
||||
* @param tag the compound tag
|
||||
* @return the string
|
||||
* @throws IOException if an exception was encountered while writing the compound tag
|
||||
*/
|
||||
public static @NonNull String writeString(final @NonNull CompoundTag tag) throws IOException {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
try (final TagStringWriter emit = new TagStringWriter(sb)) {
|
||||
emit.writeTag(tag);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* This file is part of adventure, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2017-2021 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.nbt;
|
||||
|
||||
/**
|
||||
* A character buffer designed to be inspected by a parser.
|
||||
*/
|
||||
final class CharBuffer {
|
||||
private final CharSequence sequence;
|
||||
private int index;
|
||||
|
||||
CharBuffer(final CharSequence sequence) {
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the character at the current position.
|
||||
*
|
||||
* @return The current character
|
||||
*/
|
||||
public char peek() {
|
||||
return this.sequence.charAt(this.index);
|
||||
}
|
||||
|
||||
public char peek(final int offset) {
|
||||
return this.sequence.charAt(this.index + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current character and advance.
|
||||
*
|
||||
* @return current character
|
||||
*/
|
||||
public char take() {
|
||||
return this.sequence.charAt(this.index++);
|
||||
}
|
||||
|
||||
public boolean advance() {
|
||||
this.index++;
|
||||
return this.hasMore();
|
||||
}
|
||||
|
||||
public boolean hasMore() {
|
||||
return this.index < this.sequence.length();
|
||||
}
|
||||
|
||||
public boolean hasMore(final int offset) {
|
||||
return this.index + offset < this.sequence.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the provided token, and advance the reader index past the {@code until} character.
|
||||
*
|
||||
* @param until Case-insensitive token
|
||||
* @return the string starting at the current position (inclusive) and going until the location of {@code until}, exclusive
|
||||
*/
|
||||
public CharSequence takeUntil(char until) throws StringTagParseException {
|
||||
until = Character.toLowerCase(until);
|
||||
int endIdx = -1;
|
||||
for (int idx = this.index; idx < this.sequence.length(); ++idx) {
|
||||
if (this.sequence.charAt(idx) == Tokens.ESCAPE_MARKER) {
|
||||
idx++;
|
||||
} else if (Character.toLowerCase(this.sequence.charAt(idx)) == until) {
|
||||
endIdx = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (endIdx == -1) {
|
||||
throw this.makeError("No occurrence of " + until + " was found");
|
||||
}
|
||||
|
||||
final CharSequence result = this.sequence.subSequence(this.index, endIdx);
|
||||
this.index = endIdx + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the next non-whitespace character is the provided parameter.
|
||||
*
|
||||
* <p>If the assertion is successful, the token will be consumed.</p>
|
||||
*
|
||||
* @param expectedChar expected character
|
||||
* @return this
|
||||
* @throws StringTagParseException if EOF or non-matching value is found
|
||||
*/
|
||||
public CharBuffer expect(final char expectedChar) throws StringTagParseException {
|
||||
this.skipWhitespace();
|
||||
if (!this.hasMore()) {
|
||||
throw this.makeError("Expected character '" + expectedChar + "' but got EOF");
|
||||
}
|
||||
if (this.peek() != expectedChar) {
|
||||
throw this.makeError("Expected character '" + expectedChar + "' but got '" + this.peek() + "'");
|
||||
}
|
||||
this.take();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the next non-whitespace character is {@code token}, advance past it.
|
||||
*
|
||||
* <p>This method always consumes whitespace.</p>
|
||||
*
|
||||
* @param token next non-whitespace character to query
|
||||
* @return if the next non-whitespace character is {@code token}
|
||||
*/
|
||||
public boolean takeIf(final char token) {
|
||||
this.skipWhitespace();
|
||||
if (this.hasMore() && this.peek() == token) {
|
||||
this.advance();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public CharBuffer skipWhitespace() {
|
||||
while (this.hasMore() && Character.isWhitespace(this.peek())) this.advance();
|
||||
return this;
|
||||
}
|
||||
|
||||
public StringTagParseException makeError(final String message) {
|
||||
return new StringTagParseException(message, this.sequence, this.index);
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* This file is part of adventure, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2017-2020 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.nbt;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception thrown when parsing a string tag.
|
||||
*/
|
||||
class StringTagParseException extends IOException {
|
||||
private static final long serialVersionUID = -3001637554903912905L;
|
||||
private final CharSequence buffer;
|
||||
private final int position;
|
||||
|
||||
public StringTagParseException(final String message, final CharSequence buffer, final int position) {
|
||||
super(message);
|
||||
this.buffer = buffer;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return super.getMessage() + "(at position " + this.position + ")";
|
||||
}
|
||||
}
|
@ -1,358 +0,0 @@
|
||||
/*
|
||||
* This file is part of adventure, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2017-2021 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.DoubleTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.FloatTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
// Specific Via changes:
|
||||
// - Use OpenNBT tags
|
||||
// - Small byteArray() optimization
|
||||
// - acceptLegacy = true by default
|
||||
final class TagStringReader {
|
||||
private static final int MAX_DEPTH = 512;
|
||||
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||
private static final int[] EMPTY_INT_ARRAY = new int[0];
|
||||
private static final long[] EMPTY_LONG_ARRAY = new long[0];
|
||||
|
||||
private final CharBuffer buffer;
|
||||
private boolean acceptLegacy = true; // Via - always true
|
||||
private int depth;
|
||||
|
||||
TagStringReader(final CharBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public CompoundTag compound() throws StringTagParseException {
|
||||
this.buffer.expect(Tokens.COMPOUND_BEGIN);
|
||||
final CompoundTag compoundTag = new CompoundTag();
|
||||
if (this.buffer.takeIf(Tokens.COMPOUND_END)) {
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
while (this.buffer.hasMore()) {
|
||||
compoundTag.put(this.key(), this.tag());
|
||||
if (this.separatorOrCompleteWith(Tokens.COMPOUND_END)) {
|
||||
return compoundTag;
|
||||
}
|
||||
}
|
||||
throw this.buffer.makeError("Unterminated compound tag!");
|
||||
}
|
||||
|
||||
public ListTag list() throws StringTagParseException {
|
||||
final ListTag listTag = new ListTag();
|
||||
this.buffer.expect(Tokens.ARRAY_BEGIN);
|
||||
final boolean prefixedIndex = this.acceptLegacy && this.buffer.peek() == '0' && this.buffer.peek(1) == ':';
|
||||
if (!prefixedIndex && this.buffer.takeIf(Tokens.ARRAY_END)) {
|
||||
return listTag;
|
||||
}
|
||||
while (this.buffer.hasMore()) {
|
||||
if (prefixedIndex) {
|
||||
this.buffer.takeUntil(':');
|
||||
}
|
||||
|
||||
final Tag next = this.tag();
|
||||
listTag.add(next);
|
||||
if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) {
|
||||
return listTag;
|
||||
}
|
||||
}
|
||||
throw this.buffer.makeError("Reached end of file without end of list tag!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to a list tag in syntax, but returning a single array tag rather than a list of tags.
|
||||
*
|
||||
* @return array-typed tag
|
||||
*/
|
||||
public Tag array(char elementType) throws StringTagParseException {
|
||||
this.buffer.expect(Tokens.ARRAY_BEGIN)
|
||||
.expect(elementType)
|
||||
.expect(Tokens.ARRAY_SIGNATURE_SEPARATOR);
|
||||
|
||||
elementType = Character.toLowerCase(elementType);
|
||||
if (elementType == Tokens.TYPE_BYTE) {
|
||||
return new ByteArrayTag(this.byteArray());
|
||||
} else if (elementType == Tokens.TYPE_INT) {
|
||||
return new IntArrayTag(this.intArray());
|
||||
} else if (elementType == Tokens.TYPE_LONG) {
|
||||
return new LongArrayTag(this.longArray());
|
||||
} else {
|
||||
throw this.buffer.makeError("Type " + elementType + " is not a valid element type in an array!");
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] byteArray() throws StringTagParseException {
|
||||
if (this.buffer.takeIf(Tokens.ARRAY_END)) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
|
||||
final IntList bytes = new IntArrayList(); // Via - no boxing
|
||||
while (this.buffer.hasMore()) {
|
||||
final CharSequence value = this.buffer.skipWhitespace().takeUntil(Tokens.TYPE_BYTE);
|
||||
try {
|
||||
bytes.add(Byte.parseByte(value.toString())); // Via
|
||||
} catch (final NumberFormatException ex) {
|
||||
throw this.buffer.makeError("All elements of a byte array must be bytes!");
|
||||
}
|
||||
|
||||
if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) {
|
||||
final byte[] result = new byte[bytes.size()];
|
||||
for (int i = 0; i < bytes.size(); ++i) {
|
||||
result[i] = (byte) bytes.getInt(i); // Via
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
throw this.buffer.makeError("Reached end of document without array close");
|
||||
}
|
||||
|
||||
private int[] intArray() throws StringTagParseException {
|
||||
if (this.buffer.takeIf(Tokens.ARRAY_END)) {
|
||||
return EMPTY_INT_ARRAY;
|
||||
}
|
||||
|
||||
final IntStream.Builder builder = IntStream.builder();
|
||||
while (this.buffer.hasMore()) {
|
||||
final Tag value = this.tag();
|
||||
if (!(value instanceof IntTag)) {
|
||||
throw this.buffer.makeError("All elements of an int array must be ints!");
|
||||
}
|
||||
builder.add(((NumberTag) value).asInt());
|
||||
if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) {
|
||||
return builder.build().toArray();
|
||||
}
|
||||
}
|
||||
throw this.buffer.makeError("Reached end of document without array close");
|
||||
}
|
||||
|
||||
private long[] longArray() throws StringTagParseException {
|
||||
if (this.buffer.takeIf(Tokens.ARRAY_END)) {
|
||||
return EMPTY_LONG_ARRAY;
|
||||
}
|
||||
|
||||
final LongStream.Builder longs = LongStream.builder();
|
||||
while (this.buffer.hasMore()) {
|
||||
final CharSequence value = this.buffer.skipWhitespace().takeUntil(Tokens.TYPE_LONG);
|
||||
try {
|
||||
longs.add(Long.parseLong(value.toString()));
|
||||
} catch (final NumberFormatException ex) {
|
||||
throw this.buffer.makeError("All elements of a long array must be longs!");
|
||||
}
|
||||
|
||||
if (this.separatorOrCompleteWith(Tokens.ARRAY_END)) {
|
||||
return longs.build().toArray();
|
||||
}
|
||||
}
|
||||
throw this.buffer.makeError("Reached end of document without array close");
|
||||
}
|
||||
|
||||
public String key() throws StringTagParseException {
|
||||
this.buffer.skipWhitespace();
|
||||
final char starChar = this.buffer.peek();
|
||||
try {
|
||||
if (starChar == Tokens.SINGLE_QUOTE || starChar == Tokens.DOUBLE_QUOTE) {
|
||||
return unescape(this.buffer.takeUntil(this.buffer.take()).toString());
|
||||
}
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
while (this.buffer.hasMore()) {
|
||||
final char peek = this.buffer.peek();
|
||||
if (!Tokens.id(peek)) {
|
||||
if (this.acceptLegacy) {
|
||||
// In legacy format, a key is any non-colon character, with escapes allowed
|
||||
if (peek == Tokens.ESCAPE_MARKER) {
|
||||
this.buffer.take(); // skip
|
||||
continue;
|
||||
} else if (peek != Tokens.COMPOUND_KEY_TERMINATOR) {
|
||||
builder.append(this.buffer.take());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
builder.append(this.buffer.take());
|
||||
}
|
||||
return builder.toString();
|
||||
} finally {
|
||||
this.buffer.expect(Tokens.COMPOUND_KEY_TERMINATOR);
|
||||
}
|
||||
}
|
||||
|
||||
public Tag tag() throws StringTagParseException {
|
||||
if (this.depth++ > MAX_DEPTH) {
|
||||
throw this.buffer.makeError("Exceeded maximum allowed depth of " + MAX_DEPTH + " when reading tag");
|
||||
}
|
||||
try {
|
||||
final char startToken = this.buffer.skipWhitespace().peek();
|
||||
switch (startToken) {
|
||||
case Tokens.COMPOUND_BEGIN:
|
||||
return this.compound();
|
||||
case Tokens.ARRAY_BEGIN:
|
||||
// Maybe add in a legacy-only mode to read those?
|
||||
if (this.buffer.hasMore(2) && this.buffer.peek(2) == ';') { // we know we're an array tag
|
||||
return this.array(this.buffer.peek(1));
|
||||
} else {
|
||||
return this.list();
|
||||
}
|
||||
case Tokens.SINGLE_QUOTE:
|
||||
case Tokens.DOUBLE_QUOTE:
|
||||
// definitely a string tag
|
||||
this.buffer.advance();
|
||||
return new StringTag(unescape(this.buffer.takeUntil(startToken).toString()));
|
||||
default: // scalar
|
||||
return this.scalar();
|
||||
}
|
||||
} finally {
|
||||
this.depth--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A tag that is definitely some sort of scalar.
|
||||
*
|
||||
* <p>Does not detect quoted strings, so those should have been parsed already.</p>
|
||||
*
|
||||
* @return a parsed tag
|
||||
*/
|
||||
private Tag scalar() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
int noLongerNumericAt = -1;
|
||||
while (this.buffer.hasMore()) {
|
||||
char current = this.buffer.peek();
|
||||
if (current == '\\') { // escape -- we are significantly more lenient than original format at the moment
|
||||
this.buffer.advance();
|
||||
current = this.buffer.take();
|
||||
} else if (Tokens.id(current)) {
|
||||
this.buffer.advance();
|
||||
} else { // end of value
|
||||
break;
|
||||
}
|
||||
builder.append(current);
|
||||
if (noLongerNumericAt == -1 && !Tokens.numeric(current)) {
|
||||
noLongerNumericAt = builder.length();
|
||||
}
|
||||
}
|
||||
|
||||
final int length = builder.length();
|
||||
final String built = builder.toString();
|
||||
if (noLongerNumericAt == length) {
|
||||
final char last = built.charAt(length - 1);
|
||||
try {
|
||||
switch (Character.toLowerCase(last)) { // try to read and return as a number
|
||||
case Tokens.TYPE_BYTE:
|
||||
return new ByteTag(Byte.parseByte(built.substring(0, length - 1)));
|
||||
case Tokens.TYPE_SHORT:
|
||||
return new ShortTag(Short.parseShort(built.substring(0, length - 1)));
|
||||
case Tokens.TYPE_INT:
|
||||
return new IntTag(Integer.parseInt(built.substring(0, length - 1)));
|
||||
case Tokens.TYPE_LONG:
|
||||
return new LongTag(Long.parseLong(built.substring(0, length - 1)));
|
||||
case Tokens.TYPE_FLOAT:
|
||||
final float floatValue = Float.parseFloat(built.substring(0, length - 1));
|
||||
if (Float.isFinite(floatValue)) { // don't accept NaN and Infinity
|
||||
return new FloatTag(floatValue);
|
||||
}
|
||||
break;
|
||||
case Tokens.TYPE_DOUBLE:
|
||||
final double doubleValue = Double.parseDouble(built.substring(0, length - 1));
|
||||
if (Double.isFinite(doubleValue)) { // don't accept NaN and Infinity
|
||||
return new DoubleTag(doubleValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (final NumberFormatException ignored) {
|
||||
}
|
||||
} else if (noLongerNumericAt == -1) { // if we run out of content without an explicit value separator, then we're either an integer or string tag -- all others have a character at the end
|
||||
try {
|
||||
return new IntTag(Integer.parseInt(built));
|
||||
} catch (final NumberFormatException ex) {
|
||||
if (built.indexOf('.') != -1) {
|
||||
try {
|
||||
return new DoubleTag(Double.parseDouble(built));
|
||||
} catch (final NumberFormatException ex2) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (built.equalsIgnoreCase(Tokens.LITERAL_TRUE)) {
|
||||
return new ByteTag((byte) 1);
|
||||
} else if (built.equalsIgnoreCase(Tokens.LITERAL_FALSE)) {
|
||||
return new ByteTag((byte) 0);
|
||||
}
|
||||
return new StringTag(built);
|
||||
|
||||
}
|
||||
|
||||
private boolean separatorOrCompleteWith(final char endCharacter) throws StringTagParseException {
|
||||
if (this.buffer.takeIf(endCharacter)) {
|
||||
return true;
|
||||
}
|
||||
this.buffer.expect(Tokens.VALUE_SEPARATOR);
|
||||
return this.buffer.takeIf(endCharacter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove simple escape sequences from a string.
|
||||
*
|
||||
* @param withEscapes input string with escapes
|
||||
* @return string with escapes processed
|
||||
*/
|
||||
private static String unescape(final String withEscapes) {
|
||||
int escapeIdx = withEscapes.indexOf(Tokens.ESCAPE_MARKER);
|
||||
if (escapeIdx == -1) { // nothing to unescape
|
||||
return withEscapes;
|
||||
}
|
||||
int lastEscape = 0;
|
||||
final StringBuilder output = new StringBuilder(withEscapes.length());
|
||||
do {
|
||||
output.append(withEscapes, lastEscape, escapeIdx);
|
||||
lastEscape = escapeIdx + 1;
|
||||
} while ((escapeIdx = withEscapes.indexOf(Tokens.ESCAPE_MARKER, lastEscape + 1)) != -1); // add one extra character to make sure we don't include escaped backslashes
|
||||
output.append(withEscapes.substring(lastEscape));
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
public void legacy(final boolean acceptLegacy) {
|
||||
this.acceptLegacy = acceptLegacy;
|
||||
}
|
||||
}
|
@ -1,261 +0,0 @@
|
||||
/*
|
||||
* This file is part of adventure, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2017-2020 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.nbt;
|
||||
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.DoubleTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.FloatTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
// Specific Via changes:
|
||||
// - Use OpenNBT tags
|
||||
// - Has not been updated to support pretty printing and legacy writing since that is not needed
|
||||
|
||||
/**
|
||||
* An emitter for the SNBT format.
|
||||
*
|
||||
* <p>Details on the format are described in the package documentation.</p>
|
||||
*/
|
||||
final class TagStringWriter implements AutoCloseable {
|
||||
private final Appendable out;
|
||||
private int level;
|
||||
/**
|
||||
* Whether a {@link Tokens#VALUE_SEPARATOR} needs to be printed before the beginning of the next object.
|
||||
*/
|
||||
private boolean needsSeparator;
|
||||
|
||||
public TagStringWriter(final Appendable out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
// NBT-specific
|
||||
|
||||
public TagStringWriter writeTag(final Tag tag) throws IOException {
|
||||
if (tag instanceof CompoundTag) {
|
||||
return this.writeCompound((CompoundTag) tag);
|
||||
} else if (tag instanceof ListTag) {
|
||||
return this.writeList((ListTag) tag);
|
||||
} else if (tag instanceof ByteArrayTag) {
|
||||
return this.writeByteArray((ByteArrayTag) tag);
|
||||
} else if (tag instanceof IntArrayTag) {
|
||||
return this.writeIntArray((IntArrayTag) tag);
|
||||
} else if (tag instanceof LongArrayTag) {
|
||||
return this.writeLongArray((LongArrayTag) tag);
|
||||
} else if (tag instanceof StringTag) {
|
||||
return this.value(((StringTag) tag).getValue(), Tokens.EOF);
|
||||
} else if (tag instanceof ByteTag) {
|
||||
return this.value(Byte.toString(((NumberTag) tag).asByte()), Tokens.TYPE_BYTE);
|
||||
} else if (tag instanceof ShortTag) {
|
||||
return this.value(Short.toString(((NumberTag) tag).asShort()), Tokens.TYPE_SHORT);
|
||||
} else if (tag instanceof IntTag) {
|
||||
return this.value(Integer.toString(((NumberTag) tag).asInt()), Tokens.TYPE_INT);
|
||||
} else if (tag instanceof LongTag) {
|
||||
return this.value(Long.toString(((NumberTag) tag).asLong()), Character.toUpperCase(Tokens.TYPE_LONG)); // special case
|
||||
} else if (tag instanceof FloatTag) {
|
||||
return this.value(Float.toString(((NumberTag) tag).asFloat()), Tokens.TYPE_FLOAT);
|
||||
} else if (tag instanceof DoubleTag) {
|
||||
return this.value(Double.toString(((NumberTag) tag).asDouble()), Tokens.TYPE_DOUBLE);
|
||||
} else {
|
||||
throw new IOException("Unknown tag type: " + tag.getClass().getSimpleName());
|
||||
// unknown!
|
||||
}
|
||||
}
|
||||
|
||||
private TagStringWriter writeCompound(final CompoundTag tag) throws IOException {
|
||||
this.beginCompound();
|
||||
for (final Map.Entry<String, Tag> entry : tag.entrySet()) {
|
||||
this.key(entry.getKey());
|
||||
this.writeTag(entry.getValue());
|
||||
}
|
||||
this.endCompound();
|
||||
return this;
|
||||
}
|
||||
|
||||
private TagStringWriter writeList(final ListTag tag) throws IOException {
|
||||
this.beginList();
|
||||
for (final Tag el : tag) {
|
||||
this.printAndResetSeparator();
|
||||
this.writeTag(el);
|
||||
}
|
||||
this.endList();
|
||||
return this;
|
||||
}
|
||||
|
||||
private TagStringWriter writeByteArray(final ByteArrayTag tag) throws IOException {
|
||||
this.beginArray(Tokens.TYPE_BYTE);
|
||||
|
||||
final byte[] value = tag.getValue();
|
||||
for (int i = 0, length = value.length; i < length; i++) {
|
||||
this.printAndResetSeparator();
|
||||
this.value(Byte.toString(value[i]), Tokens.TYPE_BYTE);
|
||||
}
|
||||
this.endArray();
|
||||
return this;
|
||||
}
|
||||
|
||||
private TagStringWriter writeIntArray(final IntArrayTag tag) throws IOException {
|
||||
this.beginArray(Tokens.TYPE_INT);
|
||||
|
||||
final int[] value = tag.getValue();
|
||||
for (int i = 0, length = value.length; i < length; i++) {
|
||||
this.printAndResetSeparator();
|
||||
this.value(Integer.toString(value[i]), Tokens.TYPE_INT);
|
||||
}
|
||||
this.endArray();
|
||||
return this;
|
||||
}
|
||||
|
||||
private TagStringWriter writeLongArray(final LongArrayTag tag) throws IOException {
|
||||
this.beginArray(Tokens.TYPE_LONG);
|
||||
|
||||
final long[] value = tag.getValue();
|
||||
for (int i = 0, length = value.length; i < length; i++) {
|
||||
this.printAndResetSeparator();
|
||||
this.value(Long.toString(value[i]), Tokens.TYPE_LONG);
|
||||
}
|
||||
this.endArray();
|
||||
return this;
|
||||
}
|
||||
|
||||
// Value types
|
||||
|
||||
public TagStringWriter beginCompound() throws IOException {
|
||||
this.printAndResetSeparator();
|
||||
this.level++;
|
||||
this.out.append(Tokens.COMPOUND_BEGIN);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TagStringWriter endCompound() throws IOException {
|
||||
this.out.append(Tokens.COMPOUND_END);
|
||||
this.level--;
|
||||
this.needsSeparator = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TagStringWriter key(final String key) throws IOException {
|
||||
this.printAndResetSeparator();
|
||||
this.writeMaybeQuoted(key, false);
|
||||
this.out.append(Tokens.COMPOUND_KEY_TERMINATOR);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TagStringWriter value(final String value, final char valueType) throws IOException {
|
||||
if (valueType == Tokens.EOF) { // string doesn't have its type
|
||||
this.writeMaybeQuoted(value, true);
|
||||
} else {
|
||||
this.out.append(value);
|
||||
if (valueType != Tokens.TYPE_INT) {
|
||||
this.out.append(valueType);
|
||||
}
|
||||
}
|
||||
this.needsSeparator = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TagStringWriter beginList() throws IOException {
|
||||
this.printAndResetSeparator();
|
||||
this.level++;
|
||||
this.out.append(Tokens.ARRAY_BEGIN);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TagStringWriter endList() throws IOException {
|
||||
this.out.append(Tokens.ARRAY_END);
|
||||
this.level--;
|
||||
this.needsSeparator = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
private TagStringWriter beginArray(final char type) throws IOException {
|
||||
this.beginList()
|
||||
.out.append(type)
|
||||
.append(Tokens.ARRAY_SIGNATURE_SEPARATOR);
|
||||
return this;
|
||||
}
|
||||
|
||||
private TagStringWriter endArray() throws IOException {
|
||||
return this.endList();
|
||||
}
|
||||
|
||||
private void writeMaybeQuoted(final String content, boolean requireQuotes) throws IOException {
|
||||
if (!requireQuotes) {
|
||||
for (int i = 0; i < content.length(); ++i) {
|
||||
if (!Tokens.id(content.charAt(i))) {
|
||||
requireQuotes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (requireQuotes) {
|
||||
this.out.append(Tokens.DOUBLE_QUOTE);
|
||||
this.out.append(escape(content, Tokens.DOUBLE_QUOTE));
|
||||
this.out.append(Tokens.DOUBLE_QUOTE);
|
||||
} else {
|
||||
this.out.append(content);
|
||||
}
|
||||
}
|
||||
|
||||
private static String escape(final String content, final char quoteChar) {
|
||||
final StringBuilder output = new StringBuilder(content.length());
|
||||
for (int i = 0; i < content.length(); ++i) {
|
||||
final char c = content.charAt(i);
|
||||
if (c == quoteChar || c == '\\') {
|
||||
output.append(Tokens.ESCAPE_MARKER);
|
||||
}
|
||||
output.append(c);
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private void printAndResetSeparator() throws IOException {
|
||||
if (this.needsSeparator) {
|
||||
this.out.append(Tokens.VALUE_SEPARATOR);
|
||||
this.needsSeparator = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (this.level != 0) {
|
||||
throw new IllegalStateException("Document finished with unbalanced start and end objects");
|
||||
}
|
||||
if (this.out instanceof Writer) {
|
||||
((Writer) this.out).flush();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* This file is part of adventure, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) 2017-2021 KyoriPowered
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.viaversion.viaversion.api.minecraft.nbt;
|
||||
|
||||
final class Tokens {
|
||||
// Compounds
|
||||
static final char COMPOUND_BEGIN = '{';
|
||||
static final char COMPOUND_END = '}';
|
||||
static final char COMPOUND_KEY_TERMINATOR = ':';
|
||||
|
||||
// Arrays
|
||||
static final char ARRAY_BEGIN = '[';
|
||||
static final char ARRAY_END = ']';
|
||||
static final char ARRAY_SIGNATURE_SEPARATOR = ';';
|
||||
|
||||
static final char VALUE_SEPARATOR = ',';
|
||||
|
||||
static final char SINGLE_QUOTE = '\'';
|
||||
static final char DOUBLE_QUOTE = '"';
|
||||
static final char ESCAPE_MARKER = '\\';
|
||||
|
||||
static final char TYPE_BYTE = 'b';
|
||||
static final char TYPE_SHORT = 's';
|
||||
static final char TYPE_INT = 'i'; // array only
|
||||
static final char TYPE_LONG = 'l';
|
||||
static final char TYPE_FLOAT = 'f';
|
||||
static final char TYPE_DOUBLE = 'd';
|
||||
|
||||
static final String LITERAL_TRUE = "true";
|
||||
static final String LITERAL_FALSE = "false";
|
||||
|
||||
static final String NEWLINE = System.getProperty("line.separator", "\n");
|
||||
static final char EOF = '\0';
|
||||
|
||||
private Tokens() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if a character is a valid component in an identifier.
|
||||
*
|
||||
* <p>An identifier character must match the expression {@code [a-zA-Z0-9_+.-]}</p>
|
||||
*
|
||||
* @param c the character
|
||||
* @return identifier
|
||||
*/
|
||||
static boolean id(final char c) {
|
||||
return (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9')
|
||||
|| c == '-' || c == '_'
|
||||
|| c == '.' || c == '+';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a character could be at some position in a number.
|
||||
*
|
||||
* <p>A string passing this check does not necessarily mean it is syntactically valid.</p>
|
||||
*
|
||||
* @param c character to check
|
||||
* @return if possibly part of a number
|
||||
*/
|
||||
static boolean numeric(final char c) {
|
||||
return (c >= '0' && c <= '9') // digit
|
||||
|| c == '+' || c == '-' // positive or negative
|
||||
|| c == 'e' || c == 'E' // exponent
|
||||
|| c == '.'; // decimal
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data;
|
||||
|
||||
import com.github.steveice10.opennbt.stringified.SNBT;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ShortTag;
|
||||
@ -27,12 +28,10 @@ import com.google.gson.JsonPrimitive;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.minecraft.item.DataItem;
|
||||
import com.viaversion.viaversion.api.minecraft.item.Item;
|
||||
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
|
||||
import com.viaversion.viaversion.api.protocol.Protocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
|
||||
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
||||
import com.viaversion.viaversion.rewriter.ComponentRewriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ComponentRewriter1_13<C extends ClientboundPacketType> extends ComponentRewriter<C> {
|
||||
|
||||
@ -54,7 +53,7 @@ public class ComponentRewriter1_13<C extends ClientboundPacketType> extends Comp
|
||||
|
||||
CompoundTag tag;
|
||||
try {
|
||||
tag = BinaryTagIO.readString(text);
|
||||
tag = SNBT.deserializeCompoundTag(text);
|
||||
} catch (Exception e) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().warning("Error reading NBT in show_item:" + text);
|
||||
@ -86,10 +85,10 @@ public class ComponentRewriter1_13<C extends ClientboundPacketType> extends Comp
|
||||
array.add(object);
|
||||
String serializedNBT;
|
||||
try {
|
||||
serializedNBT = BinaryTagIO.writeString(tag);
|
||||
serializedNBT = SNBT.serialize(tag);
|
||||
object.addProperty("text", serializedNBT);
|
||||
hoverEvent.add("value", array);
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().warning("Error writing NBT in show_item:" + text);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_16_2to1_16_1.data;
|
||||
|
||||
import com.github.steveice10.opennbt.NBTIO;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
@ -24,7 +25,6 @@ import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.data.MappingDataBase;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -40,7 +40,7 @@ public class MappingData extends MappingDataBase {
|
||||
@Override
|
||||
public void loadExtras(final CompoundTag data) {
|
||||
try {
|
||||
dimensionRegistry = BinaryTagIO.readInputStream(MappingDataLoader.getResource("dimension-registry-1.16.2.nbt"));
|
||||
dimensionRegistry = NBTIO.readTag(MappingDataLoader.getResource("dimension-registry-1.16.2.nbt"));
|
||||
} catch (final IOException e) {
|
||||
Via.getPlatform().getLogger().severe("Error loading dimension registry:");
|
||||
e.printStackTrace();
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_19_1to1_19;
|
||||
|
||||
import com.github.steveice10.opennbt.stringified.SNBT;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ByteTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
@ -28,7 +29,6 @@ import com.google.gson.JsonElement;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.api.connection.UserConnection;
|
||||
import com.viaversion.viaversion.api.minecraft.ProfileKey;
|
||||
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
|
||||
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
|
||||
import com.viaversion.viaversion.api.protocol.packet.State;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
@ -46,7 +46,6 @@ import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.storage.NonceSto
|
||||
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19;
|
||||
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ServerboundPackets1_19;
|
||||
import com.viaversion.viaversion.util.CipherUtil;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@ -83,11 +82,7 @@ public final class Protocol1_19_1To1_19 extends AbstractProtocol<ClientboundPack
|
||||
private static final CompoundTag CHAT_REGISTRY;
|
||||
|
||||
static {
|
||||
try {
|
||||
CHAT_REGISTRY = BinaryTagIO.readString(CHAT_REGISTRY_SNBT).get("minecraft:chat_type");
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
CHAT_REGISTRY = SNBT.deserializeCompoundTag(CHAT_REGISTRY_SNBT).get("minecraft:chat_type");
|
||||
}
|
||||
|
||||
public Protocol1_19_1To1_19() {
|
||||
|
@ -17,10 +17,10 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.data;
|
||||
|
||||
import com.github.steveice10.opennbt.NBTIO;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.viaversion.viaversion.api.data.MappingDataBase;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class MappingData extends MappingDataBase {
|
||||
@ -34,7 +34,7 @@ public final class MappingData extends MappingDataBase {
|
||||
@Override
|
||||
protected void loadExtras(final CompoundTag data) {
|
||||
try {
|
||||
damageTypesRegistry = BinaryTagIO.readInputStream(MappingDataLoader.getResource("damage-types-1.19.4.nbt"));
|
||||
damageTypesRegistry = NBTIO.readTag(MappingDataLoader.getResource("damage-types-1.19.4.nbt"));
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -17,13 +17,13 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_19to1_18_2.data;
|
||||
|
||||
import com.github.steveice10.opennbt.NBTIO;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.viaversion.viaversion.api.data.MappingDataBase;
|
||||
import com.viaversion.viaversion.api.data.MappingDataLoader;
|
||||
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.io.IOException;
|
||||
@ -40,7 +40,7 @@ public final class MappingData extends MappingDataBase {
|
||||
@Override
|
||||
protected void loadExtras(final CompoundTag daata) {
|
||||
try {
|
||||
final ListTag chatTypes = BinaryTagIO.readInputStream(MappingDataLoader.getResource("chat-types-1.19.nbt")).get("values");
|
||||
final ListTag chatTypes = NBTIO.readTag(MappingDataLoader.getResource("chat-types-1.19.nbt")).get("values");
|
||||
for (final Tag chatType : chatTypes) {
|
||||
final CompoundTag chatTypeCompound = (CompoundTag) chatType;
|
||||
final NumberTag idTag = chatTypeCompound.get("id");
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package com.viaversion.viaversion.protocols.protocol1_19to1_18_2.packets;
|
||||
|
||||
import com.github.steveice10.opennbt.stringified.SNBT;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.IntTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.ListTag;
|
||||
@ -31,7 +32,6 @@ import com.viaversion.viaversion.api.minecraft.entities.Entity1_19Types;
|
||||
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
|
||||
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
|
||||
import com.viaversion.viaversion.api.minecraft.metadata.Metadata;
|
||||
import com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO;
|
||||
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
|
||||
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
|
||||
import com.viaversion.viaversion.api.type.Type;
|
||||
@ -46,7 +46,6 @@ import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.storage.Dimensio
|
||||
import com.viaversion.viaversion.rewriter.EntityRewriter;
|
||||
import com.viaversion.viaversion.util.Key;
|
||||
import com.viaversion.viaversion.util.Pair;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
@ -82,11 +81,7 @@ public final class EntityPackets extends EntityRewriter<ClientboundPackets1_18,
|
||||
public static final CompoundTag CHAT_REGISTRY;
|
||||
|
||||
static {
|
||||
try {
|
||||
CHAT_REGISTRY = BinaryTagIO.readString(CHAT_REGISTRY_SNBT).get("minecraft:chat_type");
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
CHAT_REGISTRY = SNBT.deserializeCompoundTag(CHAT_REGISTRY_SNBT).get("minecraft:chat_type");
|
||||
}
|
||||
|
||||
public EntityPackets(final Protocol1_19To1_18_2 protocol) {
|
||||
|
@ -21,35 +21,36 @@ import java.io.IOException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.viaversion.viaversion.api.minecraft.nbt.BinaryTagIO.readString;
|
||||
import static com.github.steveice10.opennbt.stringified.SNBT.deserialize;
|
||||
import static com.github.steveice10.opennbt.stringified.SNBT.deserializeCompoundTag;
|
||||
|
||||
public class NBTTagTest {
|
||||
|
||||
@Test
|
||||
void test() throws IOException {
|
||||
readString("{id:5}");
|
||||
readString("{id:5b}");
|
||||
readString("{id:test,test:1,}");
|
||||
readString("{id:[3.2,64.5,129.5]}");
|
||||
readString("{id:[I;1,2, 3, 4,5]}"); // >=1.11
|
||||
readString("{id:1b,b:true}");
|
||||
readString("{id:[L;1l,2L,3L]}"); // >=1.11
|
||||
readString("{id:[I;1i,2I,3I]}");
|
||||
readString("{id:'minecraft:stone'}"); // >=1.13
|
||||
readString("{id:1,id:2}");
|
||||
readString("{id:-20b,test:3.19f}");
|
||||
readString("{id:[I;1,2,3,]}");
|
||||
readString("{id:[1,2,3,]}");
|
||||
deserialize("{id:5}");
|
||||
deserialize("{id:5b}");
|
||||
deserialize("{id:test,test:1,}");
|
||||
deserialize("{id:[3.2,64.5,129.5]}");
|
||||
deserialize("{id:[I;1,2, 3, 4,5]}"); // >=1.11
|
||||
deserialize("{id:1b,b:true}");
|
||||
deserialize("{id:[L;1l,2L,3L]}"); // >=1.11
|
||||
deserialize("{id:[I;1i,2I,3I]}");
|
||||
deserialize("{id:'minecraft:stone'}"); // >=1.13
|
||||
deserialize("{id:1,id:2}");
|
||||
deserialize("{id:-20b,test:3.19f}");
|
||||
deserialize("{id:[I;1,2,3,]}");
|
||||
deserialize("{id:[1,2,3,]}");
|
||||
|
||||
Assertions.assertEquals("0da", readString("{id:0da}").get("id").getValue());
|
||||
Assertions.assertEquals("NaNd", readString("{id:NaNd}").get("id").getValue());
|
||||
Assertions.assertEquals("Infinityd", readString("{id:Infinityd}").get("id").getValue());
|
||||
Assertions.assertEquals("2147483649", readString("{id:9000b,thisisastring:2147483649}").get("thisisastring").getValue());
|
||||
Assertions.assertEquals((byte) 1, readString("{thisisabyte:true}").get("thisisabyte").getValue());
|
||||
Assertions.assertEquals((byte) 0, readString("{thisisabyte:false}").get("thisisabyte").getValue());
|
||||
Assertions.assertEquals("0da", deserializeCompoundTag("{id:0da}").get("id").getValue());
|
||||
Assertions.assertEquals("NaNd", deserializeCompoundTag("{id:NaNd}").get("id").getValue());
|
||||
Assertions.assertEquals("Infinityd", deserializeCompoundTag("{id:Infinityd}").get("id").getValue());
|
||||
Assertions.assertEquals("2147483649", deserializeCompoundTag("{id:9000b,thisisastring:2147483649}").get("thisisastring").getValue());
|
||||
Assertions.assertEquals((byte) 1, deserializeCompoundTag("{thisisabyte:true}").get("thisisabyte").getValue());
|
||||
Assertions.assertEquals((byte) 0, deserializeCompoundTag("{thisisabyte:false}").get("thisisabyte").getValue());
|
||||
|
||||
//TODO fix legacy < 1.12
|
||||
// readString("{id:minecraft:stone}");
|
||||
// readString("{id:[1,2, 3, 4,5]}");
|
||||
// deserialize("{id:minecraft:stone}");
|
||||
// deserialize("{id:[1,2, 3, 4,5]}");
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ adventure = "4.14.0"
|
||||
gson = "2.10.1"
|
||||
fastutil = "8.5.12"
|
||||
flare = "2.0.1"
|
||||
openNBT = "2.1.3"
|
||||
nbt = "3.0.0"
|
||||
|
||||
# Common provided
|
||||
netty = "4.0.20.Final"
|
||||
@ -37,7 +37,7 @@ gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
|
||||
fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" }
|
||||
flare = { group = "space.vectrix.flare", name = "flare", version.ref = "flare" }
|
||||
flareFastutil = { group = "space.vectrix.flare", name = "flare-fastutil", version.ref = "flare" }
|
||||
openNBT = { group = "com.viaversion", name = "opennbt", version.ref = "openNBT" }
|
||||
nbt = { group = "com.viaversion", name = "nbt", version.ref = "nbt" }
|
||||
|
||||
netty = { group = "io.netty", name = "netty-all", version.ref = "netty" }
|
||||
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren