From 399857a7b581de3751909f78b9c6a01ad44e489d Mon Sep 17 00:00:00 2001 From: ScarletRedMan Date: Tue, 14 Jan 2025 16:56:09 +0700 Subject: [PATCH] feat: fully implemented dialog renderer --- api/build.gradle | 2 + .../ru/dragonestia/msb3/api/Bootstrap.java | 50 ---- .../api/talk/dialogue/AnswerClickContext.java | 6 + .../talk/dialogue/DialogGlyphPositions.java | 50 +--- .../api/talk/dialogue/DialogueRenderer.java | 230 ++++++++++++++++-- .../msb3/api/talk/dialogue/DialogueTheme.java | 123 +++++++++- .../msb3/api/talk/dialogue/OnCloseDialog.java | 6 + 7 files changed, 352 insertions(+), 115 deletions(-) create mode 100644 api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/AnswerClickContext.java create mode 100644 api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/OnCloseDialog.java diff --git a/api/build.gradle b/api/build.gradle index 52ba959..e478258 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -19,4 +19,6 @@ dependencies { api 'io.prometheus:prometheus-metrics-core:1.3.1' api 'io.prometheus:prometheus-metrics-instrumentation-jvm:1.3.1' api 'io.prometheus:prometheus-metrics-exporter-httpserver:1.3.1' + + implementation 'org.apache.commons:commons-text:1.10.0' } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/Bootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/Bootstrap.java index 3b86dc0..480d536 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/Bootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/Bootstrap.java @@ -1,15 +1,10 @@ package ru.dragonestia.msb3.api; import lombok.extern.log4j.Log4j2; -import net.minestom.server.MinecraftServer; import net.minestom.server.entity.GameMode; -import net.minestom.server.event.player.PlayerChatEvent; import ru.dragonestia.msb3.api.module.FlatWorldModule; import ru.dragonestia.msb3.api.module.MotdModule; import ru.dragonestia.msb3.api.module.ResourcePackRepositoryModule; -import ru.dragonestia.msb3.api.resource.dialog.ButtonNumber; -import ru.dragonestia.msb3.api.talk.dialogue.DialogueRenderer; -import ru.dragonestia.msb3.api.talk.dialogue.DialogueTheme; @Log4j2 public class Bootstrap { @@ -20,51 +15,6 @@ public class Bootstrap { MotdModule.init("logo.png", "msb3 server"); FlatWorldModule.init(GameMode.ADVENTURE); - MinecraftServer.getGlobalEventHandler().addListener(PlayerChatEvent.class, event -> { - var player = event.getPlayer(); - - var render = new DialogueRenderer(player, DialogueTheme.builder().build()); - render.setText(""" - Абсолютно точно. - Я знаю точнo - невозможное возможно - Сойти с ума, влюбиться так неосторoжно - Найти тебя, не отпускать ни днём, ни ночью - Всё невозможное - возможно, знаю точно! - А где тебя искать, прошу ты мне ответь - В какие города мне за тобой лететь - Я готов на край Земли, я всё должен объяснить - Пойми, что без тебя я не умею жить - Я знаю точно - невозможное возможно - Сойти с ума, влюбиться так неосторожно - Найти тебя, не отпускать ни днём, ни ночью - Всё невозможное - возможно, знаю точно! - На-на-на-на (на-на-на-на), а-а, а-а - На-на-на-на (на-на-на-на), а-а, а-а - Всё готов делить, с тобой я пополам - Ты только мне поверь, я сделал выбор сам - Дай же мне последний шанс, я всё должен объяснить - Пойми, что без тебя я не умею жить - Я знаю точно - невозможное возможно - Сойти с ума, влюбиться так неосторожно - Найти тебя, не отпускать ни днём, ни ночью - Всё невозможное - возможно, знаю точно! - На-на-на-на (на-на-на-на), а-а, а-а - На-на-на-на (на-на-на-на), а-а, а-а - Я знаю точно - невозможное возможно - Сойти с ума, влюбиться так неосторожно - Найти тебя, не отпускать ни днём, ни ночью - Всё невозможное - возможно, знаю точно! - На-на-на-на (на-на-на-на), а-а, а-а - На-на-на-на (на-на-на-на), а-а, а-а"""); - - render.setButtonText(ButtonNumber.BUTTON_1, "Hello world!"); - render.setButtonText(ButtonNumber.BUTTON_2, "I am a teapot"); - render.setButtonText(ButtonNumber.BUTTON_3, "I love pizza\nMamma mia\nPeperoni\nPapa carlo\nZaebumba\nPidoraso ebanino"); - render.setButtonText(ButtonNumber.BUTTON_4, "msb3 is top!"); - - render.show(); - }); - ResourcePackRepositoryModule.init(boot, "0.0.0.0", 7270); boot.start("0.0.0.0", 25565); diff --git a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/AnswerClickContext.java b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/AnswerClickContext.java new file mode 100644 index 0000000..370d648 --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/AnswerClickContext.java @@ -0,0 +1,6 @@ +package ru.dragonestia.msb3.api.talk.dialogue; + +import net.minestom.server.entity.Player; +import ru.dragonestia.msb3.api.resource.dialog.ButtonNumber; + +public record AnswerClickContext(Player player, DialogueRenderer renderer, ButtonNumber buttonNumber, String buttonText) {} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogGlyphPositions.java b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogGlyphPositions.java index a387abc..a61dce9 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogGlyphPositions.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogGlyphPositions.java @@ -1,8 +1,5 @@ package ru.dragonestia.msb3.api.talk.dialogue; -import net.kyori.adventure.text.format.Style; -import net.kyori.adventure.text.format.TextColor; -import net.kyori.adventure.text.format.TextDecoration; import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties; public record DialogGlyphPositions(GuiBackground guiBackground, @@ -12,26 +9,24 @@ public record DialogGlyphPositions(GuiBackground guiBackground, AnswerText answerText, AnswerField answerField, AnswerButton answerButton, - ScrollPhraseButton scrollPhraseButton) { + ScrollPhraseButton scrollPhraseButton, + ChestSlotsButtons chestSlotsButtons) { public static final DialogGlyphPositions DEFAULT = new DialogGlyphPositions( new GuiBackground(35, -96, 262), - new PhraseText(11, -11, 340, 8, 8, "#000000"), + new PhraseText(11, -11, 340, 8, 8), new PhraseSubstrate(-24, 19, 356, 116), new Avatar(-144, 11, 100, 116), - new AnswerText(175, 4, 8, -145, 149, -122, -170, "#000000"), + new AnswerText(175, 4, 8, -145, 149, -122, -170), new AnswerField(-117, -165, -153, 141, 44), - new AnswerButton(-124, -182, 41, 97, 20, "#a18262", "#ffd8a8"), - new ScrollPhraseButton(0, 126, -100, 10, "#a18262") + new AnswerButton(-124, -182, 41, 97, 20), + new ScrollPhraseButton(0, 126, -100, 10), + new ChestSlotsButtons(new int[] {45, 46}, new int[] {52, 53}, new int[] {65, 66}, new int[] {68, 69}, new int[] {56, 57}, new int[] {59, 60}) ); public record GuiBackground(int topPartsY, int bottomPartsY, int height) {} - public record PhraseText(int maxLines, int lineX, int lineWidth, int fontHeight, int firstLineAscent, String textColorHex) { - - public TextColor textColor() { - return TextColor.fromHexString(textColorHex); - } + public record PhraseText(int maxLines, int lineX, int lineWidth, int fontHeight, int firstLineAscent) { public TextureProperties firstLineProperties() { return new TextureProperties(fontHeight, firstLineAscent); @@ -48,35 +43,14 @@ public record DialogGlyphPositions(GuiBackground guiBackground, } public record AnswerText(int lineWidth, int maxLines, int fontHeight, int leftLineX, - int rightLineX, int topFirstLineAscent, int bottomFirstLineAscent, - String textColorHex) { - - public TextColor textColor() { - return TextColor.fromHexString(textColorHex); - } - } + int rightLineX, int topFirstLineAscent, int bottomFirstLineAscent) {} public record AnswerField(int topFieldY, int bottomFieldY, int leftFieldX, int rightFieldX, int height) {} public record AnswerButton(int topButtonY, int bottomButtonY, int leftButtonX, - int rightButtonX, int height, - String loreHeadingTextColorHex, - String loreFallbackTextColorHex) { + int rightButtonX, int height) {} - public Style loreHeadingTextStyle() { - return Style.style(TextColor.fromHexString(loreHeadingTextColorHex), TextDecoration.ITALIC.withState(false)); - } + public record ScrollPhraseButton(int scrollUpButtonX, int scrollDownButtonX, int buttonY, int height) {} - public Style loreFallbackTextStyle() { - return Style.style(TextColor.fromHexString(loreFallbackTextColorHex), TextDecoration.ITALIC.withState(false)); - } - } - - public record ScrollPhraseButton(int scrollUpButtonX, int scrollDownButtonX, int buttonY, int height, String textColorHex) { - - public Style textStyle() { - return Style.style(TextColor.fromHexString(textColorHex), - TextDecoration.ITALIC.withState(false)); - } - } + public record ChestSlotsButtons(int[] scrollUp, int[] scrollDown, int[] answer1, int[] answer2, int[] answer3, int[] answer4) {} } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueRenderer.java b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueRenderer.java index b186cbd..550bee5 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueRenderer.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueRenderer.java @@ -1,38 +1,46 @@ package ru.dragonestia.msb3.api.talk.dialogue; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.extern.log4j.Log4j2; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.minimessage.MiniMessage; import net.minestom.server.entity.Player; import net.minestom.server.event.EventListener; import net.minestom.server.event.inventory.InventoryCloseEvent; +import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.InventoryType; import net.minestom.server.item.ItemStack; +import net.minestom.server.tag.Tag; +import org.apache.commons.text.WordUtils; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import ru.dragonestia.msb3.api.ServerBootstrap; import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph; import ru.dragonestia.msb3.api.glyph.glyph.GlyphComponentBuilder; import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties; import ru.dragonestia.msb3.api.glyph.pack.GlyphResourcePack; +import ru.dragonestia.msb3.api.item.BlankSlotItem; +import ru.dragonestia.msb3.api.item.ItemUtil; import ru.dragonestia.msb3.api.resource.dialog.ButtonNumber; import ru.dragonestia.msb3.api.util.StringUtil; -import ru.dragonestia.msb3.api.util.UncheckedRunnable; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; +import java.util.function.Consumer; @Log4j2 public class DialogueRenderer extends Inventory { public static final int CHEST_GUI_WIDTH = 176; + private static final Tag TAG_CLICK_TYPE = Tag.String("msb3_dialogue_click_type"); @Getter private final GlyphResourcePack glyphResourcePack = ServerBootstrap.getInstance().getResourcePackManager().getGlyphResourcePack(); private final Player player; @@ -41,10 +49,12 @@ public class DialogueRenderer extends Inventory { private int shifted = 0; private int maxLines = 0; private final EnumMap buttonsText = new EnumMap<>(ButtonNumber.class); + private final EnumMap> onAnswerClick = new EnumMap<>(ButtonNumber.class); private ItemStack[] itemBackup; private EventListener onCloseListener; - @Getter @Setter private UncheckedRunnable onClose; + private EventListener onClickListener; + @Getter @Setter private OnCloseDialog onClose; public DialogueRenderer(Player player, DialogueTheme theme) { super(InventoryType.CHEST_6_ROW, Component.empty()); @@ -57,11 +67,6 @@ public class DialogueRenderer extends Inventory { this.shifted = 0; } - public void setButtonText(ButtonNumber number, @Nullable String text) { - if (text == null) buttonsText.remove(number); - else buttonsText.put(number, text); - } - public void scrollUp() { if (shifted > 0) { shifted = Math.max(0, shifted - 3); @@ -76,22 +81,109 @@ public class DialogueRenderer extends Inventory { public void rerender() { setTitle(render()); + + var slots = getTheme().getPositions().chestSlotsButtons(); + + for (var slot: slots.scrollUp()) { + if (shifted != 0) { + setSlotClickable(slot, null, ClickType.SCROLL_UP); + } else { + resetClickableSlot(slot); + } + } + + for (var slot: slots.scrollDown()) { + if (maxLines > shifted + theme.getPositions().phraseText().maxLines()) { + setSlotClickable(slot, null, ClickType.SCROLL_DOWN); + } else { + resetClickableSlot(slot); + } + } + + for (var slot: slots.answer1()) { + if (buttonsText.containsKey(ButtonNumber.BUTTON_1)) { + setSlotClickable(slot, splitAnswerText(buttonsText.get(ButtonNumber.BUTTON_1)), ClickType.ANSWER_1); + } else { + resetClickableSlot(slot); + } + } + + for (var slot: slots.answer2()) { + if (buttonsText.containsKey(ButtonNumber.BUTTON_2)) { + setSlotClickable(slot, splitAnswerText(buttonsText.get(ButtonNumber.BUTTON_2)), ClickType.ANSWER_2); + } else { + resetClickableSlot(slot); + } + } + + for (var slot: slots.answer3()) { + if (buttonsText.containsKey(ButtonNumber.BUTTON_3)) { + setSlotClickable(slot, splitAnswerText(buttonsText.get(ButtonNumber.BUTTON_3)), ClickType.ANSWER_3); + } else { + resetClickableSlot(slot); + } + } + + for (var slot: slots.answer4()) { + if (buttonsText.containsKey(ButtonNumber.BUTTON_4)) { + setSlotClickable(slot, splitAnswerText(buttonsText.get(ButtonNumber.BUTTON_4)), ClickType.ANSWER_4); + } else { + resetClickableSlot(slot); + } + } + } + + private void resetClickableSlot(int slot) { + if (slot < getSize()) { + setItemStack(slot, ItemStack.AIR); + } else { + player.getInventory().setItemStack(slot - getSize(), ItemStack.AIR); + } + } + + private void setSlotClickable(int slot, List component, ClickType clickType) { + var item = BlankSlotItem.getItem().builder() + .set(ItemUtil.TAG_UNDROPPABLE, true) + .set(TAG_CLICK_TYPE, clickType.name()); + + Component text = null; + switch (clickType) { + case SCROLL_UP -> text = getTheme().getTextScrollUp(); + case SCROLL_DOWN -> text = getTheme().getTextScrollDown(); + case ANSWER_1, ANSWER_2, ANSWER_3, ANSWER_4 -> { + text = getTheme().getTextPrefixAnswer(); + for (var line: component) { + text = text.append(line); + } + } + } + var lines = new ArrayList<>(text.children()); + if (lines.isEmpty()) throw new IllegalStateException("Button have zero lines"); + + item.customName(lines.removeFirst()); + if (!lines.isEmpty()) item.lore(lines); + + if (slot < getSize()) { + setItemStack(slot, item.build()); + } else { + player.getInventory().setItemStack(slot - getSize(), item.build()); + } } public void show() { try { - onOpen(); - player.openInventory(this); - } catch (Exception e) { - onClose(); + onOpen(); + } catch (Exception ex) { + onClose(false); + player.sendMessage(Component.text("[ERROR] " + ex.getMessage(), NamedTextColor.RED)); - log.error(e.getMessage(), e); + log.error(ex.getMessage(), ex); } } - public void close() { - onClose(); + public void close(boolean closedByPlayer) { + onClose(closedByPlayer); } private void onOpen() { @@ -103,15 +195,56 @@ public class DialogueRenderer extends Inventory { onCloseListener = EventListener.of(InventoryCloseEvent.class, event -> { if (event.getInventory() instanceof DialogueRenderer renderer) { - renderer.close(); + renderer.close(true); } }); player.eventNode().addListener(onCloseListener); + + onClickListener = EventListener.of(InventoryPreClickEvent.class, event -> { + var player = event.getPlayer(); + var item = event.getClickedItem(); + + event.setCancelled(true); + + if (item.isAir()) return; + + var type = ClickType.valueOf(item.getTag(TAG_CLICK_TYPE)); + + switch (type) { + case SCROLL_UP -> { + scrollUp(); + rerender(); + getTheme().getOnScrollText().accept(player); + } + case SCROLL_DOWN -> { + scrollDown(); + rerender(); + getTheme().getOnScrollText().accept(player); + } + + case ANSWER_1, ANSWER_2, ANSWER_3, ANSWER_4 -> { + var buttonNumber = type.buttonNumber; + if (onAnswerClick.containsKey(buttonNumber)) { + var ctx = new AnswerClickContext( + player, + this, + buttonNumber, + buttonsText.get(buttonNumber) + ); + + onAnswerClick.get(buttonNumber).accept(ctx); + } + } + } + }); + player.eventNode().addListener(onClickListener); } } - private void onClose() { + private void onClose(boolean closedByPlayer) { synchronized (this) { + if (onCloseListener == null) return; + if (itemBackup != null) { var inv = player.getInventory(); for (int i = 0; i < itemBackup.length; i++) { @@ -123,13 +256,14 @@ public class DialogueRenderer extends Inventory { player.closeInventory(); - if (onCloseListener != null) { - player.eventNode().removeListener(onCloseListener); - onCloseListener = null; - } + player.eventNode().removeListener(onCloseListener); + onCloseListener = null; + + player.eventNode().removeListener(onClickListener); + onClickListener = null; } - if (onClose != null) onClose.run(); + if (onClose != null) onClose.onClose(closedByPlayer); } private Component render() { @@ -167,7 +301,7 @@ public class DialogueRenderer extends Inventory { // Answers for (var number: ButtonNumber.values()) { - if (buttonsText.containsKey(number)) { //TODO: checking answer exists + if (buttonsText.containsKey(number)) { builder.append(number.getIndex() % 2 == 0 ? theme.getPositions().answerField().leftFieldX() : theme.getPositions().answerField().rightFieldX(), @@ -204,7 +338,12 @@ public class DialogueRenderer extends Inventory { number.getIndex() % 2 == 0 ? theme.getPositions().answerText().leftLineX() : theme.getPositions().answerText().rightLineX(), - line.toGlyphList(line.textureProperties(), 0, endWithDots, theme.getPositions().answerText().textColor()) + line.toGlyphList(line.textureProperties(), 0, endWithDots, switch (number) { + case BUTTON_1 -> theme.getColorAnswerText1(); + case BUTTON_2 -> theme.getColorAnswerText2(); + case BUTTON_3 -> theme.getColorAnswerText3(); + case BUTTON_4 -> theme.getColorAnswerText4(); + }) ); } } else { @@ -263,11 +402,40 @@ public class DialogueRenderer extends Inventory { line.textureProperties(), shift, textLines.size() - lineIdx > 0 && lineIdx - shift == positions.phraseText().maxLines() - 1, - positions.phraseText().textColor() + getTheme().getColorText() )); } } + private List splitAnswerText(String text) { + var style = Style.style() + .decoration(TextDecoration.ITALIC, false) + .color(getTheme().getColorAnswerItemText()) + .build(); + + var lines = new ArrayList(); + for (var line: text.split("\n")) { + for (var subLine: WordUtils.wrap(line, 45, "\n", false).split("\n")) { + lines.add(Component.text() + .resetStyle() + .append(Component.text(subLine, style)) + .build()); + } + } + return lines; + } + + public void setButton(ButtonNumber buttonNumber, String text, Consumer onClick) { + if (text == null) { + buttonsText.remove(buttonNumber); + onAnswerClick.remove(buttonNumber); + return; + } + + buttonsText.put(buttonNumber, text); + onAnswerClick.put(buttonNumber, onClick); + } + private record TextLine(DialogueTheme theme, Component text, TextureProperties textureProperties) { public List<@NotNull AppendableGlyph> toGlyphList(TextureProperties parentProperties, int lineShift, boolean cutEnding, TextColor color) { @@ -287,4 +455,16 @@ public class DialogueRenderer extends Inventory { return theme.getFont().translate(properties.height(), properties.ascent(), text); } } + + @RequiredArgsConstructor + private enum ClickType { + ANSWER_1(ButtonNumber.BUTTON_1), + ANSWER_2(ButtonNumber.BUTTON_2), + ANSWER_3(ButtonNumber.BUTTON_3), + ANSWER_4(ButtonNumber.BUTTON_4), + SCROLL_UP(null), + SCROLL_DOWN(null); + + private final ButtonNumber buttonNumber; + } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueTheme.java b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueTheme.java index caac92d..ee321c4 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueTheme.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/DialogueTheme.java @@ -5,12 +5,20 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; +import net.minestom.server.entity.Player; +import net.minestom.server.sound.SoundEvent; import ru.dragonestia.msb3.api.ServerBootstrap; import ru.dragonestia.msb3.api.glyph.glyph.image.ImageGlyph; import ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter.LanguageGlyphCollection; import ru.dragonestia.msb3.api.resource.DialogueResources; import ru.dragonestia.msb3.api.resource.dialog.*; +import java.util.function.Consumer; + @Log4j2 @Getter @RequiredArgsConstructor(access = AccessLevel.PRIVATE) @@ -38,6 +46,16 @@ public class DialogueTheme { private final ImageGlyph button3; private final ImageGlyph button4; private final LanguageGlyphCollection font; + private final Component textScrollUp; + private final Component textScrollDown; + private final Component textPrefixAnswer; + private final TextColor colorAnswerItemText; + private final TextColor colorText; + private final TextColor colorAnswerText1; + private final TextColor colorAnswerText2; + private final TextColor colorAnswerText3; + private final TextColor colorAnswerText4; + private final Consumer onScrollText; public Builder toBuilder() { return new Builder( @@ -61,7 +79,17 @@ public class DialogueTheme { button2, button3, button4, - font + font, + textScrollUp, + textScrollDown, + textPrefixAnswer, + colorAnswerItemText, + colorText, + colorAnswerText1, + colorAnswerText2, + colorAnswerText3, + colorAnswerText4, + onScrollText ); } @@ -98,6 +126,16 @@ public class DialogueTheme { private ImageGlyph button3; private ImageGlyph button4; private LanguageGlyphCollection font; + private Component textScrollUp; + private Component textScrollDown; + private Component textPrefixAnswer; + private TextColor colorAnswerItemText; + private TextColor colorText; + private TextColor colorAnswerText1; + private TextColor colorAnswerText2; + private TextColor colorAnswerText3; + private TextColor colorAnswerText4; + private Consumer onScrollText; private Builder(DialogGlyphPositions positions) { resources = ServerBootstrap.getInstance().getResourcePackManager().getDialogueResources(); @@ -124,6 +162,37 @@ public class DialogueTheme { if (button2 == null) setButton(ButtonNumber.BUTTON_2, resources.getButton(DialogueResources.DEFAULT + 2).orElseThrow()); if (button3 == null) setButton(ButtonNumber.BUTTON_3, resources.getButton(DialogueResources.DEFAULT + 3).orElseThrow()); if (button4 == null) setButton(ButtonNumber.BUTTON_4, resources.getButton(DialogueResources.DEFAULT + 4).orElseThrow()); + if (textScrollUp == null) setTextScrollUp( + Component.text() + .append(Component.text("Нажмите сюда чтобы пролистать", NamedTextColor.YELLOW)) + .append(Component.text("текст диалога вверх.", NamedTextColor.YELLOW)) + .build() + ); + if (textScrollDown == null) setTextScrollDown( + Component.text() + .append(Component.text("Нажмите сюда чтобы пролистать", NamedTextColor.YELLOW)) + .append(Component.text("текст диалога вниз.", NamedTextColor.YELLOW)) + .build() + ); + if (textPrefixAnswer == null) setTextPrefixAnswer( + Component.text() + .append(Component.text("Нажмите сюда, чтобы выбрать", NamedTextColor.GRAY)) + .append(Component.text("этот вариант ответа:", NamedTextColor.GRAY)) + .append(Component.text(" ")) + .build() + ); + if (colorAnswerItemText == null) setColorAnswerItemText(NamedTextColor.WHITE); + if (colorText == null) setColorText(TextColor.fromHexString("#000000")); + if (colorAnswerText1 == null) setColorAnswerText(ButtonNumber.BUTTON_1, TextColor.fromHexString("#000000")); + if (colorAnswerText2 == null) setColorAnswerText(ButtonNumber.BUTTON_2, TextColor.fromHexString("#000000")); + if (colorAnswerText3 == null) setColorAnswerText(ButtonNumber.BUTTON_3, TextColor.fromHexString("#000000")); + if (colorAnswerText4 == null) setColorAnswerText(ButtonNumber.BUTTON_4, TextColor.fromHexString("#000000")); + if (onScrollText == null) { + setOnScrollText(player -> { + var sound = Sound.sound(SoundEvent.ITEM_BOOK_PAGE_TURN, Sound.Source.NEUTRAL, 1f, 0.7f); + player.playSound(sound); + }); + } return new DialogueTheme( positions, @@ -145,7 +214,17 @@ public class DialogueTheme { button2, button3, button4, - font + font, + textScrollUp, + textScrollDown, + textPrefixAnswer, + colorAnswerItemText, + colorText, + colorAnswerText1, + colorAnswerText2, + colorAnswerText3, + colorAnswerText4, + onScrollText ); } @@ -213,5 +292,45 @@ public class DialogueTheme { } return this; } + + public Builder setTextScrollUp(Component text) { + this.textScrollUp = text; + return this; + } + + public Builder setTextScrollDown(Component text) { + this.textScrollDown = text; + return this; + } + + public Builder setTextPrefixAnswer(Component text) { + this.textPrefixAnswer = text; + return this; + } + + public Builder setColorAnswerItemText(TextColor color) { + this.colorAnswerItemText = color; + return this; + } + + public Builder setColorText(TextColor color) { + this.colorText = color; + return this; + } + + public Builder setOnScrollText(Consumer onScrollText) { + this.onScrollText = onScrollText; + return this; + } + + public Builder setColorAnswerText(ButtonNumber buttonNumber, TextColor color) { + switch (buttonNumber) { + case BUTTON_1 -> colorAnswerText1 = color; + case BUTTON_2 -> colorAnswerText2 = color; + case BUTTON_3 -> colorAnswerText3 = color; + case BUTTON_4 -> colorAnswerText4 = color; + } + return this; + } } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/OnCloseDialog.java b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/OnCloseDialog.java new file mode 100644 index 0000000..4ec79ff --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/talk/dialogue/OnCloseDialog.java @@ -0,0 +1,6 @@ +package ru.dragonestia.msb3.api.talk.dialogue; + +public interface OnCloseDialog { + + void onClose(boolean closedByPlayer); +}