diff --git a/MCStructs-snbt/src/main/java/net/lenni0451/mcstructs/snbt/impl/v1_12/SNbtDeserializer_v1_12.java b/MCStructs-snbt/src/main/java/net/lenni0451/mcstructs/snbt/impl/v1_12/SNbtDeserializer_v1_12.java index 60ad052..1b98e7a 100644 --- a/MCStructs-snbt/src/main/java/net/lenni0451/mcstructs/snbt/impl/v1_12/SNbtDeserializer_v1_12.java +++ b/MCStructs-snbt/src/main/java/net/lenni0451/mcstructs/snbt/impl/v1_12/SNbtDeserializer_v1_12.java @@ -95,10 +95,28 @@ public class SNbtDeserializer_v1_12 implements ISNbtDeserializer { reader.read(); reader.skipWhitespaces(); if (!reader.canRead()) throw this.makeException(reader, "Expected value"); - else if (c == 'B') return new ByteArrayTag(this.readPrimitiveList(reader, ByteTag.class, ByteArrayTag.class)); - else if (c == 'L') return new LongArrayTag(this.readPrimitiveList(reader, LongTag.class, LongArrayTag.class)); - else if (c == 'I') return new IntArrayTag(this.readPrimitiveList(reader, IntTag.class, IntArrayTag.class)); - else throw new SNbtDeserializeException("Invalid array type '" + c + "' found"); + else if (c == 'B') { + final ListTag tags = this.readPrimitiveList(reader, ByteTag.class, ByteArrayTag.class); + final byte[] array = new byte[tags.size()]; + for (int i = 0; i < tags.size(); i++) { + array[i] = tags.get(i).asByte(); + } + return new ByteArrayTag(array); + } else if (c == 'L') { + final ListTag tags = this.readPrimitiveList(reader, LongTag.class, LongArrayTag.class); + final long[] array = new long[tags.size()]; + for (int i = 0; i < tags.size(); i++) { + array[i] = tags.get(i).asLong(); + } + return new LongArrayTag(array); + } else if (c == 'I') { + final ListTag tags = this.readPrimitiveList(reader, IntTag.class, IntArrayTag.class); + final int[] array = new int[tags.size()]; + for (int i = 0; i < tags.size(); i++) { + array[i] = tags.get(i).asInt(); + } + return new IntArrayTag(array); + } else throw new SNbtDeserializeException("Invalid array type '" + c + "' found"); } protected Tag readValue(final StringReader_v1_12 reader) throws SNbtDeserializeException { diff --git a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/ATextComponent.java b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/ATextComponent.java index a60fc64..e839e9b 100644 --- a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/ATextComponent.java +++ b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/ATextComponent.java @@ -32,6 +32,13 @@ public abstract class ATextComponent implements ICopyable { private final List siblings = new ArrayList<>(); private Style style = new Style(); + private int level = 1; + private void setLevel(int level) { + this.level = Math.max(this.level, level); + if (this.level > 512) { + throw new IllegalArgumentException("Too deep"); + } + } /** * Append a string to this component. @@ -52,6 +59,7 @@ public abstract class ATextComponent implements ICopyable { */ public ATextComponent append(final ATextComponent component) { this.siblings.add(component); + component.setLevel(this.level + 1); return this; } @@ -63,6 +71,7 @@ public abstract class ATextComponent implements ICopyable { */ public ATextComponent append(final ATextComponent... components) { this.siblings.addAll(Arrays.asList(components)); + for (ATextComponent component : components) component.setLevel(this.level + 1); return this; } @@ -177,24 +186,28 @@ public abstract class ATextComponent implements ICopyable { return out.toString(); } - /** - * @return A legacy formatted string representation of this component - */ - public String asLegacyFormatString() { - StringBuilder out = new StringBuilder(); - if (this.style.getColor() != null && this.style.getColor().isFormattingColor()) out.append(COLOR_CHAR).append(this.style.getColor().getCode()); - else out.append("§r"); - if (this.style.isObfuscated()) out.append(COLOR_CHAR).append(TextFormatting.OBFUSCATED.getCode()); - if (this.style.isBold()) out.append(COLOR_CHAR).append(TextFormatting.BOLD.getCode()); - if (this.style.isStrikethrough()) out.append(COLOR_CHAR).append(TextFormatting.STRIKETHROUGH.getCode()); - if (this.style.isUnderlined()) out.append(COLOR_CHAR).append(TextFormatting.UNDERLINE.getCode()); - if (this.style.isItalic()) out.append(COLOR_CHAR).append(TextFormatting.ITALIC.getCode()); - out.append(this.asSingleString()); + public void visit(final Consumer consumer) { + if (this.style.getColor() != null && this.style.getColor().isFormattingColor()) consumer.accept(Character.toString(COLOR_CHAR) + this.style.getColor().getCode()); + else consumer.accept("§r"); + if (this.style.isObfuscated()) consumer.accept(Character.toString(COLOR_CHAR) + TextFormatting.OBFUSCATED.getCode()); + if (this.style.isBold()) consumer.accept(Character.toString(COLOR_CHAR) + TextFormatting.BOLD.getCode()); + if (this.style.isStrikethrough()) consumer.accept(Character.toString(COLOR_CHAR) + TextFormatting.STRIKETHROUGH.getCode()); + if (this.style.isUnderlined()) consumer.accept(Character.toString(COLOR_CHAR) + TextFormatting.UNDERLINE.getCode()); + if (this.style.isItalic()) consumer.accept(Character.toString(COLOR_CHAR) + TextFormatting.ITALIC.getCode()); + consumer.accept(this.asSingleString()); for (ATextComponent sibling : this.siblings) { ATextComponent copy = sibling.copy(); copy.getStyle().setParent(this.style); - out.append(copy.asLegacyFormatString()); + copy.visit(consumer); } + } + /** + * @return A legacy formatted string representation of this component + */ + public final String asLegacyFormatString() { + // Improve traversal performance + StringBuilder out = new StringBuilder(); + this.visit(out::append); return out.toString(); } diff --git a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/components/TranslationComponent.java b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/components/TranslationComponent.java index 91b176d..8158521 100644 --- a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/components/TranslationComponent.java +++ b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/components/TranslationComponent.java @@ -142,8 +142,29 @@ public class TranslationComponent extends ATextComponent { } @Override - public String asLegacyFormatString() { - return this.resolveIntoComponents().asLegacyFormatString(); + public void visit(final java.util.function.Consumer consumer) { + if (consumer instanceof TranslatableContentConsumer) { + this.resolveIntoComponents().visit(consumer); + } else { + this.resolveIntoComponents().visit(new TranslatableContentConsumer(consumer)); + } + } + private static final class TranslatableContentConsumer implements java.util.function.Consumer { + private static final IllegalArgumentException EX = new IllegalArgumentException("Too long"); + private final java.util.function.Consumer runnable; + private int visited; + + private TranslatableContentConsumer(final java.util.function.Consumer runnable) { + this.runnable = runnable; + } + + @Override + public void accept(final String s) { + if (visited++ > 32) { + throw EX; + } + this.runnable.accept(s); + } } @Override diff --git a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/EntityHoverEvent.java b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/EntityHoverEvent.java index ed2644d..55c6e02 100644 --- a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/EntityHoverEvent.java +++ b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/EntityHoverEvent.java @@ -117,10 +117,10 @@ public class EntityHoverEvent extends AHoverEvent { @Override public String toString() { return ToString.of(this) - .put("action", this.action) - .put("entityType", this.entityType) - .put("uuid", this.uuid) - .put("name", this.name, Objects::nonNull) + .add("action", this.action) + .add("entityType", this.entityType) + .add("uuid", this.uuid) + .add("name", this.name, Objects::nonNull) .toString(); } diff --git a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/ItemHoverEvent.java b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/ItemHoverEvent.java index 2812bd2..aea17e6 100644 --- a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/ItemHoverEvent.java +++ b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/events/hover/impl/ItemHoverEvent.java @@ -119,10 +119,10 @@ public class ItemHoverEvent extends AHoverEvent { @Override public String toString() { return ToString.of(this) - .put("action", this.action) - .put("item", this.item) - .put("count", this.count, count -> count != 1) - .put("nbt", this.nbt, Objects::nonNull) + .add("action", this.action) + .add("item", this.item) + .add("count", this.count, count -> count != 1) + .add("nbt", this.nbt, Objects::nonNull) .toString(); } diff --git a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/utils/JsonNbtConverter.java b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/utils/JsonNbtConverter.java index 8bd6503..e512af7 100644 --- a/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/utils/JsonNbtConverter.java +++ b/MCStructs-text/src/main/java/net/lenni0451/mcstructs/text/utils/JsonNbtConverter.java @@ -25,23 +25,15 @@ public class JsonNbtConverter { @Nullable public static JsonElement toJson(@Nullable final Tag tag) { if (tag == null) return null; - switch (tag) { - case END: - return null; - case BYTE: - case SHORT: - case INT: - case LONG: - case FLOAT: - case DOUBLE: + if (tag instanceof NumberTag) { return new JsonPrimitive(((NumberTag) tag).getValue()); - case BYTE_ARRAY: + } else if (tag instanceof ByteArrayTag) { JsonArray byteArray = new JsonArray(); for (byte b : ((ByteArrayTag) tag).getValue()) byteArray.add(b); return byteArray; - case STRING: + } else if (tag instanceof StringTag) { return new JsonPrimitive(((StringTag) tag).getValue()); - case LIST: + } else if (tag instanceof ListTag) { JsonArray list = new JsonArray(); ListTag listTag = ((ListTag) tag); for (Tag tagInList : listTag.getValue()) { @@ -55,19 +47,19 @@ public class JsonNbtConverter { list.add(toJson(tagInList)); } return list; - case COMPOUND: + } else if (tag instanceof CompoundTag) { JsonObject compound = new JsonObject(); - for (Map.Entry entry : ((CompoundTag) tag).getValue().entrySet()) compound.put(entry.getKey(), toJson(entry.getValue())); + for (Map.Entry entry : ((CompoundTag) tag).getValue().entrySet()) compound.add(entry.getKey(), toJson(entry.getValue())); return compound; - case INT_ARRAY: + } else if (tag instanceof IntArrayTag) { JsonArray intArray = new JsonArray(); for (int i : ((IntArrayTag) tag).getValue()) intArray.add(i); return intArray; - case LONG_ARRAY: + } else if (tag instanceof LongArrayTag) { JsonArray longArray = new JsonArray(); for (long l : ((LongArrayTag) tag).getValue()) longArray.add(l); return longArray; - default: + } else { throw new IllegalArgumentException("Unknown Nbt type: " + tag); } } @@ -90,31 +82,37 @@ public class JsonNbtConverter { JsonArray array = element.getAsJsonArray(); List nbtTags = new ArrayList<>(); Tag listType = null; + boolean mixedList = false; for (JsonElement arrayElement : array) { Tag tag = toNbt(arrayElement); nbtTags.add(tag); listType = getListType(listType, tag); + if (listType == null) mixedList = true; } if (listType == null) { return new ListTag<>(); - } else if (listType == Tag.END) { //Mixed list + } else if (mixedList) { //Mixed list ListTag list = new ListTag<>(); for (Tag tag : nbtTags) { if (tag instanceof CompoundTag) list.add(((CompoundTag) tag)); - else list.add(new CompoundTag().put("", tag)); + else { + final CompoundTag entries = new CompoundTag(); + entries.put("", tag); + list.add(entries); + } } return list; - } else if (listType == Tag.BYTE) { + } else if (listType instanceof ByteTag) { byte[] bytes = new byte[nbtTags.size()]; - for (int i = 0; i < nbtTags.size(); i++) bytes[i] = nbtTags.get(i).asByteTag().byteValue(); + for (int i = 0; i < nbtTags.size(); i++) bytes[i] = ((NumberTag) nbtTags.get(i)).asByte(); return new ByteArrayTag(bytes); - } else if (listType == Tag.INT) { + } else if (listType instanceof IntTag) { int[] ints = new int[nbtTags.size()]; - for (int i = 0; i < nbtTags.size(); i++) ints[i] = nbtTags.get(i).asIntTag().intValue(); + for (int i = 0; i < nbtTags.size(); i++) ints[i] = ((NumberTag) nbtTags.get(i)).asInt(); return new IntArrayTag(ints); - } else if (listType == Tag.LONG) { + } else if (listType instanceof LongTag) { long[] longs = new long[nbtTags.size()]; - for (int i = 0; i < nbtTags.size(); i++) longs[i] = nbtTags.get(i).asIntTag().intValue(); + for (int i = 0; i < nbtTags.size(); i++) longs[i] = ((NumberTag) nbtTags.get(i)).asLong(); return new LongArrayTag(longs); } else { return new ListTag<>(nbtTags); @@ -148,7 +146,7 @@ public class JsonNbtConverter { private static Tag getListType(final Tag current, final Tag tag) { if (current == null) return tag; - if (current != tag) return Tag.END; //Placeholder for mixed lists + if (tag == null || current.getClass() != tag.getClass()) return null; //Placeholder for mixed lists return current; } diff --git a/MCStructs-text/src/test/java/net/lenni0451/mcstructs/text/serializer/TextComponentCodecTest.java b/MCStructs-text/src/test/java/net/lenni0451/mcstructs/text/serializer/TextComponentCodecTest.java index cb0628a..18f5d2e 100644 --- a/MCStructs-text/src/test/java/net/lenni0451/mcstructs/text/serializer/TextComponentCodecTest.java +++ b/MCStructs-text/src/test/java/net/lenni0451/mcstructs/text/serializer/TextComponentCodecTest.java @@ -61,9 +61,9 @@ class TextComponentCodecTest { @Test void legacyItemDeserialization() throws SNbtSerializeException { - CompoundTag legacyNbt = new CompoundTag() - .put("id", "stone") - .putByte("Count", (byte) 5); + CompoundTag legacyNbt = new CompoundTag(); + legacyNbt.put("id", new StringTag("stone")); + legacyNbt.putByte("Count", (byte) 5); ATextComponent legacyComponent = new StringComponent("test") .setStyle(new Style() .setHoverEvent(new TextHoverEvent(HoverEventAction.SHOW_ITEM, new StringComponent(SNbtSerializer.LATEST.serialize(legacyNbt)))) @@ -80,10 +80,10 @@ class TextComponentCodecTest { @Test void legacyEntityDeserialization() throws SNbtSerializeException { UUID randomUUID = UUID.randomUUID(); - CompoundTag legacyNbt = new CompoundTag() - .put("name", "{\"text\":\"test\"}") - .put("type", "cow") - .put("id", randomUUID.toString()); + CompoundTag legacyNbt = new CompoundTag(); + legacyNbt.put("name", new StringTag("{\"text\":\"test\"}")); + legacyNbt.put("type", new StringTag("cow")); + legacyNbt.put("id", new StringTag(randomUUID.toString())); ATextComponent legacyComponent = new StringComponent("test") .setStyle(new Style() .setHoverEvent(new TextHoverEvent(HoverEventAction.SHOW_ENTITY, new StringComponent(SNbtSerializer.LATEST.serialize(legacyNbt)))) @@ -100,19 +100,31 @@ class TextComponentCodecTest { @Test void arrayWithTag() { - ListTag tags = new ListTag<>() - .add(new CompoundTag() - .putString("translate", "test") - .addByteArray("with", (byte) 1, (byte) 2, (byte) 3)) - .add(new CompoundTag() - .putString("translate", "test") - .addIntArray("with", 1, 2, 3)) - .add(new CompoundTag() - .putString("translate", "test") - .addLongArray("with", 1, 2, 3)) - .add(new CompoundTag() - .putString("translate", "test") - .addList("with", 1, 2, 3)); + CompoundTag translateWithByteArray = new CompoundTag(); + translateWithByteArray.putString("translate", "test"); + translateWithByteArray.put("with", new ByteArrayTag(new byte[]{1, 2, 3})); + + CompoundTag translateWithIntArray = new CompoundTag(); + translateWithIntArray.putString("translate", "test"); + translateWithIntArray.put("with", new IntArrayTag(new int[]{1, 2, 3})); + + CompoundTag translateWithLongArray = new CompoundTag(); + translateWithLongArray.putString("translate", "test"); + translateWithLongArray.put("with", new LongArrayTag(new long[]{1, 2, 3})); + + CompoundTag translateWithList = new CompoundTag(); + ListTag numberList = new ListTag<>(IntTag.class); + numberList.add(new IntTag(1)); + numberList.add(new IntTag(2)); + numberList.add(new IntTag(3)); + translateWithList.putString("translate", "test"); + translateWithList.put("with", numberList); + + ListTag tags = new ListTag<>(CompoundTag.class); + tags.add(translateWithByteArray); + tags.add(translateWithIntArray); + tags.add(translateWithLongArray); + tags.add(translateWithList); ATextComponent component = new TranslationComponent("test", (byte) 1, (byte) 2, (byte) 3) .append(new TranslationComponent("test", 1, 2, 3)) .append(new TranslationComponent("test", 1L, 2L, 3L)) diff --git a/build.gradle b/build.gradle index 2178d6b..6b8f7e1 100644 --- a/build.gradle +++ b/build.gradle @@ -60,17 +60,17 @@ subprojects { publishing { repositories { maven { - name = "reposilite" - def releasesUrl = "https://maven.lenni0451.net/releases" - def snapshotsUrl = "https://maven.lenni0451.net/snapshots" - url = project.maven_version.endsWith("SNAPSHOT") ? snapshotsUrl : releasesUrl - - credentials(PasswordCredentials) + name = "Via" + url = uri("https://repo.viaversion.com/") + credentials { + username = System.getenv("via_username") + password = System.getenv("via_password") + } authentication { - basic(BasicAuthentication) + create(BasicAuthentication) } } - maven { + /*maven { name = "ossrh" def releasesUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" @@ -80,7 +80,7 @@ subprojects { authentication { basic(BasicAuthentication) } - } + }*/ } publications { maven(MavenPublication) { diff --git a/settings.gradle b/settings.gradle index 64fd6ec..46ca6cc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,11 +11,6 @@ plugins { rootProject.name = "MCStructs" -include(":MCStructs-all") -include(":MCStructs-converter") include(":MCStructs-core") -include(":MCStructs-data") -include(":MCStructs-itemcomponents") -include(":MCStructs-nbt") include(":MCStructs-snbt") include(":MCStructs-text")