diff --git a/src/client/java/works/nuty/calcite/CalciteModClient.java b/src/client/java/works/nuty/calcite/CalciteModClient.java index f4da2a0..b3243d6 100644 --- a/src/client/java/works/nuty/calcite/CalciteModClient.java +++ b/src/client/java/works/nuty/calcite/CalciteModClient.java @@ -1,8 +1,12 @@ package works.nuty.calcite; import net.fabricmc.api.ClientModInitializer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class CalciteModClient implements ClientModInitializer { + public static Logger LOGGER = LogManager.getLogger("calcite"); + @Override public void onInitializeClient() { // This entrypoint is suitable for setting up client-specific logic, such as rendering. diff --git a/src/client/java/works/nuty/calcite/VerticalNbtTextFormatter.java b/src/client/java/works/nuty/calcite/VerticalNbtTextFormatter.java new file mode 100644 index 0000000..1452666 --- /dev/null +++ b/src/client/java/works/nuty/calcite/VerticalNbtTextFormatter.java @@ -0,0 +1,248 @@ +package works.nuty.calcite; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.mojang.logging.LogUtils; +import it.unimi.dsi.fastutil.bytes.ByteCollection; +import it.unimi.dsi.fastutil.bytes.ByteOpenHashSet; +import net.minecraft.nbt.*; +import net.minecraft.nbt.visitor.NbtElementVisitor; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import org.slf4j.Logger; + +import java.util.*; +import java.util.regex.Pattern; + +public class VerticalNbtTextFormatter + implements NbtElementVisitor { + private static final Logger LOGGER = LogUtils.getLogger(); + private static final int field_33271 = 8; + private static final ByteCollection SINGLE_LINE_ELEMENT_TYPES = new ByteOpenHashSet(Arrays.asList((byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6)); + private static final Formatting NAME_COLOR = Formatting.AQUA; + private static final Formatting STRING_COLOR = Formatting.GREEN; + private static final Formatting NUMBER_COLOR = Formatting.GOLD; + private static final Formatting TYPE_SUFFIX_COLOR = Formatting.RED; + private static final Pattern SIMPLE_NAME = Pattern.compile("[A-Za-z0-9._+-]+"); + private static final String KEY_VALUE_SEPARATOR = String.valueOf(':'); + private static final String ENTRY_SEPARATOR = String.valueOf(','); + private static final String SQUARE_OPEN_BRACKET = "["; + private static final String SQUARE_CLOSE_BRACKET = "]"; + private static final String SEMICOLON = ";"; + private static final String SPACE = " "; + private static final String CURLY_OPEN_BRACKET = "{"; + private static final String CURLY_CLOSE_BRACKET = "}"; + private final String prefix; + private final int indentationLevel; + private final List resultList = new ArrayList<>(); + private MutableText result = Text.literal(""); + + public VerticalNbtTextFormatter(String prefix, int indentationLevel) { + this.prefix = prefix; + this.indentationLevel = indentationLevel; + } + + protected static Text escapeName(String name) { + if (SIMPLE_NAME.matcher(name).matches()) { + return Text.literal(name).formatted(NAME_COLOR); + } + String string = NbtString.escape(name); + String string2 = string.substring(0, 1); + MutableText text = Text.literal(string.substring(1, string.length() - 1)).formatted(NAME_COLOR); + return Text.literal(string2).append(text).append(string2); + } + + /** + * {@return the textified NBT {@code element}} + */ + public List apply(NbtElement element) { + element.accept(this); + newLine(); + return this.resultList; + } + + public void newLine() { + resultList.add(this.result); + this.result = Text.literal(""); + } + + public void append(String string) { + this.result.append(Text.literal(string)); + } + + public void append(Text text) { + this.result.append(text); + } + + public void append(List texts) { + if (texts.isEmpty()) return; + this.result.append(texts.get(0)); + for (int i = 1; i < texts.size(); i++) { + newLine(); + this.result.append(texts.get(i)); + } + + } + + @Override + public void visitString(NbtString element) { + String string = NbtString.escape(element.asString()); + String string2 = string.substring(0, 1); + MutableText text = Text.literal(string.substring(1, string.length() - 1)).formatted(STRING_COLOR); + append(Text.literal(string2).append(text).append(string2)); + } + + @Override + public void visitByte(NbtByte element) { + MutableText text = Text.literal("b").formatted(TYPE_SUFFIX_COLOR); + append(Text.literal(String.valueOf(element.numberValue())).append(text).formatted(NUMBER_COLOR)); + } + + @Override + public void visitShort(NbtShort element) { + MutableText text = Text.literal("s").formatted(TYPE_SUFFIX_COLOR); + append(Text.literal(String.valueOf(element.numberValue())).append(text).formatted(NUMBER_COLOR)); + } + + @Override + public void visitInt(NbtInt element) { + append(Text.literal(String.valueOf(element.numberValue())).formatted(NUMBER_COLOR)); + } + + @Override + public void visitLong(NbtLong element) { + MutableText text = Text.literal("L").formatted(TYPE_SUFFIX_COLOR); + append(Text.literal(String.valueOf(element.numberValue())).append(text).formatted(NUMBER_COLOR)); + } + + @Override + public void visitFloat(NbtFloat element) { + MutableText text = Text.literal("f").formatted(TYPE_SUFFIX_COLOR); + append(Text.literal(String.valueOf(element.floatValue())).append(text).formatted(NUMBER_COLOR)); + } + + @Override + public void visitDouble(NbtDouble element) { + MutableText text = Text.literal("d").formatted(TYPE_SUFFIX_COLOR); + append(Text.literal(String.valueOf(element.doubleValue())).append(text).formatted(NUMBER_COLOR)); + } + + @Override + public void visitByteArray(NbtByteArray element) { + MutableText text = Text.literal("B").formatted(TYPE_SUFFIX_COLOR); + MutableText mutableText = Text.literal(SQUARE_OPEN_BRACKET).append(text).append(SEMICOLON); + byte[] bs = element.getByteArray(); + for (int i = 0; i < bs.length; ++i) { + MutableText mutableText2 = Text.literal(String.valueOf(bs[i])).formatted(NUMBER_COLOR); + mutableText.append(SPACE).append(mutableText2).append(text); + if (i == bs.length - 1) continue; + mutableText.append(ENTRY_SEPARATOR); + } + mutableText.append(SQUARE_CLOSE_BRACKET); + append(mutableText); + } + + @Override + public void visitIntArray(NbtIntArray element) { + MutableText text = Text.literal("I").formatted(TYPE_SUFFIX_COLOR); + MutableText mutableText = Text.literal(SQUARE_OPEN_BRACKET).append(text).append(SEMICOLON); + int[] is = element.getIntArray(); + for (int i = 0; i < is.length; ++i) { + mutableText.append(SPACE).append(Text.literal(String.valueOf(is[i])).formatted(NUMBER_COLOR)); + if (i == is.length - 1) continue; + mutableText.append(ENTRY_SEPARATOR); + } + mutableText.append(SQUARE_CLOSE_BRACKET); + append(mutableText); + } + + @Override + public void visitLongArray(NbtLongArray element) { + MutableText text = Text.literal("L").formatted(TYPE_SUFFIX_COLOR); + MutableText mutableText = Text.literal(SQUARE_OPEN_BRACKET).append(text).append(SEMICOLON); + long[] ls = element.getLongArray(); + for (int i = 0; i < ls.length; ++i) { + MutableText text2 = Text.literal(String.valueOf(ls[i])).formatted(NUMBER_COLOR); + mutableText.append(SPACE).append(text2).append(text); + if (i == ls.length - 1) continue; + mutableText.append(ENTRY_SEPARATOR); + } + mutableText.append(SQUARE_CLOSE_BRACKET); + append(mutableText); + } + + @Override + public void visitList(NbtList element) { + if (element.isEmpty()) { + append(Text.literal("[]")); + newLine(); + return; + } + if (SINGLE_LINE_ELEMENT_TYPES.contains(element.getHeldType()) && element.size() <= 8) { + String string = ENTRY_SEPARATOR + SPACE; + append(Text.literal(SQUARE_OPEN_BRACKET)); + for (int i = 0; i < element.size(); ++i) { + if (i != 0) { + append(string); + } + append(new VerticalNbtTextFormatter(this.prefix, this.indentationLevel).apply(element.get(i))); + } + append(SQUARE_CLOSE_BRACKET); + return; + } + append(Text.literal(SQUARE_OPEN_BRACKET)); + if (!this.prefix.isEmpty()) { + newLine(); + } + for (int j = 0; j < element.size(); ++j) { + append(Text.literal(Strings.repeat(this.prefix, this.indentationLevel + 1))); + append(new VerticalNbtTextFormatter(this.prefix, this.indentationLevel + 1).apply(element.get(j))); + if (j != element.size() - 1) { + append(ENTRY_SEPARATOR); + newLine(); + } + } + newLine(); + append(Strings.repeat(this.prefix, this.indentationLevel)); + append(SQUARE_CLOSE_BRACKET); + } + + @Override + public void visitCompound(NbtCompound compound) { + if (compound.isEmpty()) { + append(Text.literal("{}")); + return; + } + append(Text.literal(CURLY_OPEN_BRACKET)); + Collection collection = compound.getKeys(); + if (LOGGER.isDebugEnabled()) { + ArrayList list = Lists.newArrayList(compound.getKeys()); + Collections.sort(list); + collection = list; + } + if (!this.prefix.isEmpty()) { + newLine(); + } + Iterator iterator = collection.iterator(); + while (iterator.hasNext()) { + String string = (String) iterator.next(); + append(Text.literal(Strings.repeat(this.prefix, this.indentationLevel + 1)).append(VerticalNbtTextFormatter.escapeName(string)).append(KEY_VALUE_SEPARATOR).append(SPACE)); + append(new VerticalNbtTextFormatter(this.prefix, this.indentationLevel + 1).apply(compound.get(string))); + if (iterator.hasNext()) { + append(ENTRY_SEPARATOR); + newLine(); + } + } + if (!this.prefix.isEmpty()) { + newLine(); + append(Strings.repeat(this.prefix, this.indentationLevel)); + } + append(CURLY_CLOSE_BRACKET); + } + + @Override + public void visitEnd(NbtEnd element) { + this.result = Text.literal(""); + } +} diff --git a/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java b/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java index 6ce4de1..93f3ea1 100644 --- a/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java +++ b/src/client/java/works/nuty/calcite/screen/CalciteCommandScreen.java @@ -231,8 +231,11 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { commandSuggestorRenderer = null; } + context.getMatrices().push(); + context.getMatrices().translate(0, 0, 1); doneButton.render(context, mouseX, mouseY, delta); cancelButton.render(context, mouseX, mouseY, delta); + context.getMatrices().pop(); } @Environment(EnvType.CLIENT) diff --git a/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java b/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java index 8491080..f16f9cc 100644 --- a/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java +++ b/src/client/java/works/nuty/calcite/widget/CalciteTextFieldWidget.java @@ -19,14 +19,15 @@ import net.minecraft.command.CommandSource; import net.minecraft.command.argument.ItemStackArgument; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; import net.minecraft.text.*; import net.minecraft.util.Colors; import net.minecraft.util.Identifier; import net.minecraft.util.Util; import net.minecraft.util.math.MathHelper; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; +import works.nuty.calcite.CalciteModClient; +import works.nuty.calcite.VerticalNbtTextFormatter; import works.nuty.calcite.screen.CalciteInputSuggestor; import java.util.List; @@ -39,7 +40,6 @@ public class CalciteTextFieldWidget extends ClickableWidget implements Drawable { - private static final Logger LOGGER = LogManager.getLogger("calcite"); public static final int DEFAULT_EDITABLE_COLOR = 0xE0E0E0; private static final ButtonTextures TEXTURES = new ButtonTextures(new Identifier("widget/text_field"), new Identifier("widget/text_field_highlighted")); private static final int VERTICAL_CURSOR_COLOR = -3092272; @@ -424,7 +424,9 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delt int hw = this.textRenderer.getWidth(displayedString.substring(ds, de)); int hh = this.textRenderer.fontHeight + 2; - if (hx <= mouseX && mouseX <= hx + hw && hy <= mouseY && mouseY <= hy + hh) { + if (Screen.hasControlDown() && hx <= mouseX && mouseX <= hx + hw && hy <= mouseY && mouseY <= hy + hh) { + context.getMatrices().push(); + context.getMatrices().translate(0, 0, 2); Object result = arg.getResult(); if (result instanceof ItemStackArgument isa) { try { @@ -432,18 +434,22 @@ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delt context.drawItemTooltip(this.textRenderer, is, mouseX, mouseY); context.drawItem(is, mouseX - 8, mouseY - 8); } catch (CommandSyntaxException e) { - LOGGER.warn("Invalid item stack detected"); + CalciteModClient.LOGGER.warn("Invalid item stack detected"); } } else if (result instanceof MutableText mt) { try { var text = Texts.parse(null, mt, null, 0); context.drawTooltip(this.textRenderer, text, mouseX, mouseY); } catch (CommandSyntaxException e) { - LOGGER.warn("Invalid text component detected"); + CalciteModClient.LOGGER.warn("Invalid text component detected"); } + } else if (result instanceof NbtCompound nbt) { + List text = new VerticalNbtTextFormatter(" ", 0).apply(nbt); + context.drawTooltip(this.textRenderer, text, mouseX, mouseY); } else { - context.drawTooltip(this.textRenderer, List.of(Text.of(result.getClass().toString()), Text.of(result.toString())), mouseX, mouseY); +// context.drawTooltip(this.textRenderer, List.of(Text.of(result.getClass().toString()), Text.of(result.toString())), mouseX, mouseY); } + context.getMatrices().pop(); } } }