feat: fully implemented dialog renderer

This commit is contained in:
Andrey Terentev 2025-01-14 16:56:09 +07:00
parent fb04fbe692
commit 399857a7b5
7 changed files with 352 additions and 115 deletions

View File

@ -19,4 +19,6 @@ dependencies {
api 'io.prometheus:prometheus-metrics-core:1.3.1' api 'io.prometheus:prometheus-metrics-core:1.3.1'
api 'io.prometheus:prometheus-metrics-instrumentation-jvm:1.3.1' api 'io.prometheus:prometheus-metrics-instrumentation-jvm:1.3.1'
api 'io.prometheus:prometheus-metrics-exporter-httpserver:1.3.1' api 'io.prometheus:prometheus-metrics-exporter-httpserver:1.3.1'
implementation 'org.apache.commons:commons-text:1.10.0'
} }

View File

@ -1,15 +1,10 @@
package ru.dragonestia.msb3.api; package ru.dragonestia.msb3.api;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.GameMode; 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.FlatWorldModule;
import ru.dragonestia.msb3.api.module.MotdModule; import ru.dragonestia.msb3.api.module.MotdModule;
import ru.dragonestia.msb3.api.module.ResourcePackRepositoryModule; 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 @Log4j2
public class Bootstrap { public class Bootstrap {
@ -20,51 +15,6 @@ public class Bootstrap {
MotdModule.init("logo.png", "<gradient:#ff0059:#e06806><bold>msb3 server</bold></gradient>"); MotdModule.init("logo.png", "<gradient:#ff0059:#e06806><bold>msb3 server</bold></gradient>");
FlatWorldModule.init(GameMode.ADVENTURE); 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); ResourcePackRepositoryModule.init(boot, "0.0.0.0", 7270);
boot.start("0.0.0.0", 25565); boot.start("0.0.0.0", 25565);

View File

@ -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) {}

View File

@ -1,8 +1,5 @@
package ru.dragonestia.msb3.api.talk.dialogue; 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; import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
public record DialogGlyphPositions(GuiBackground guiBackground, public record DialogGlyphPositions(GuiBackground guiBackground,
@ -12,26 +9,24 @@ public record DialogGlyphPositions(GuiBackground guiBackground,
AnswerText answerText, AnswerText answerText,
AnswerField answerField, AnswerField answerField,
AnswerButton answerButton, AnswerButton answerButton,
ScrollPhraseButton scrollPhraseButton) { ScrollPhraseButton scrollPhraseButton,
ChestSlotsButtons chestSlotsButtons) {
public static final DialogGlyphPositions DEFAULT = new DialogGlyphPositions( public static final DialogGlyphPositions DEFAULT = new DialogGlyphPositions(
new GuiBackground(35, -96, 262), 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 PhraseSubstrate(-24, 19, 356, 116),
new Avatar(-144, 11, 100, 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 AnswerField(-117, -165, -153, 141, 44),
new AnswerButton(-124, -182, 41, 97, 20, "#a18262", "#ffd8a8"), new AnswerButton(-124, -182, 41, 97, 20),
new ScrollPhraseButton(0, 126, -100, 10, "#a18262") 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 GuiBackground(int topPartsY, int bottomPartsY, int height) {}
public record PhraseText(int maxLines, int lineX, int lineWidth, int fontHeight, int firstLineAscent, String textColorHex) { public record PhraseText(int maxLines, int lineX, int lineWidth, int fontHeight, int firstLineAscent) {
public TextColor textColor() {
return TextColor.fromHexString(textColorHex);
}
public TextureProperties firstLineProperties() { public TextureProperties firstLineProperties() {
return new TextureProperties(fontHeight, firstLineAscent); 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, public record AnswerText(int lineWidth, int maxLines, int fontHeight, int leftLineX,
int rightLineX, int topFirstLineAscent, int bottomFirstLineAscent, int rightLineX, int topFirstLineAscent, int bottomFirstLineAscent) {}
String textColorHex) {
public TextColor textColor() {
return TextColor.fromHexString(textColorHex);
}
}
public record AnswerField(int topFieldY, int bottomFieldY, int leftFieldX, int rightFieldX, int height) {} public record AnswerField(int topFieldY, int bottomFieldY, int leftFieldX, int rightFieldX, int height) {}
public record AnswerButton(int topButtonY, int bottomButtonY, int leftButtonX, public record AnswerButton(int topButtonY, int bottomButtonY, int leftButtonX,
int rightButtonX, int height, int rightButtonX, int height) {}
String loreHeadingTextColorHex,
String loreFallbackTextColorHex) {
public Style loreHeadingTextStyle() { public record ScrollPhraseButton(int scrollUpButtonX, int scrollDownButtonX, int buttonY, int height) {}
return Style.style(TextColor.fromHexString(loreHeadingTextColorHex), TextDecoration.ITALIC.withState(false));
}
public Style loreFallbackTextStyle() { public record ChestSlotsButtons(int[] scrollUp, int[] scrollDown, int[] answer1, int[] answer2, int[] answer3, int[] answer4) {}
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));
}
}
} }

View File

@ -1,38 +1,46 @@
package ru.dragonestia.msb3.api.talk.dialogue; package ru.dragonestia.msb3.api.talk.dialogue;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent; 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.Style;
import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener; import net.minestom.server.event.EventListener;
import net.minestom.server.event.inventory.InventoryCloseEvent; 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.Inventory;
import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.ItemStack; 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.NotNull;
import org.jetbrains.annotations.Nullable;
import ru.dragonestia.msb3.api.ServerBootstrap; import ru.dragonestia.msb3.api.ServerBootstrap;
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph; import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
import ru.dragonestia.msb3.api.glyph.glyph.GlyphComponentBuilder; import ru.dragonestia.msb3.api.glyph.glyph.GlyphComponentBuilder;
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties; import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
import ru.dragonestia.msb3.api.glyph.pack.GlyphResourcePack; 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.resource.dialog.ButtonNumber;
import ru.dragonestia.msb3.api.util.StringUtil; import ru.dragonestia.msb3.api.util.StringUtil;
import ru.dragonestia.msb3.api.util.UncheckedRunnable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
@Log4j2 @Log4j2
public class DialogueRenderer extends Inventory { public class DialogueRenderer extends Inventory {
public static final int CHEST_GUI_WIDTH = 176; public static final int CHEST_GUI_WIDTH = 176;
private static final Tag<String> TAG_CLICK_TYPE = Tag.String("msb3_dialogue_click_type");
@Getter private final GlyphResourcePack glyphResourcePack = ServerBootstrap.getInstance().getResourcePackManager().getGlyphResourcePack(); @Getter private final GlyphResourcePack glyphResourcePack = ServerBootstrap.getInstance().getResourcePackManager().getGlyphResourcePack();
private final Player player; private final Player player;
@ -41,10 +49,12 @@ public class DialogueRenderer extends Inventory {
private int shifted = 0; private int shifted = 0;
private int maxLines = 0; private int maxLines = 0;
private final EnumMap<ButtonNumber, String> buttonsText = new EnumMap<>(ButtonNumber.class); private final EnumMap<ButtonNumber, String> buttonsText = new EnumMap<>(ButtonNumber.class);
private final EnumMap<ButtonNumber, Consumer<AnswerClickContext>> onAnswerClick = new EnumMap<>(ButtonNumber.class);
private ItemStack[] itemBackup; private ItemStack[] itemBackup;
private EventListener<InventoryCloseEvent> onCloseListener; private EventListener<InventoryCloseEvent> onCloseListener;
@Getter @Setter private UncheckedRunnable onClose; private EventListener<InventoryPreClickEvent> onClickListener;
@Getter @Setter private OnCloseDialog onClose;
public DialogueRenderer(Player player, DialogueTheme theme) { public DialogueRenderer(Player player, DialogueTheme theme) {
super(InventoryType.CHEST_6_ROW, Component.empty()); super(InventoryType.CHEST_6_ROW, Component.empty());
@ -57,11 +67,6 @@ public class DialogueRenderer extends Inventory {
this.shifted = 0; 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() { public void scrollUp() {
if (shifted > 0) { if (shifted > 0) {
shifted = Math.max(0, shifted - 3); shifted = Math.max(0, shifted - 3);
@ -76,22 +81,109 @@ public class DialogueRenderer extends Inventory {
public void rerender() { public void rerender() {
setTitle(render()); 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> 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() { public void show() {
try { try {
onOpen();
player.openInventory(this); player.openInventory(this);
} catch (Exception e) { onOpen();
onClose(); } 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() { public void close(boolean closedByPlayer) {
onClose(); onClose(closedByPlayer);
} }
private void onOpen() { private void onOpen() {
@ -103,15 +195,56 @@ public class DialogueRenderer extends Inventory {
onCloseListener = EventListener.of(InventoryCloseEvent.class, event -> { onCloseListener = EventListener.of(InventoryCloseEvent.class, event -> {
if (event.getInventory() instanceof DialogueRenderer renderer) { if (event.getInventory() instanceof DialogueRenderer renderer) {
renderer.close(); renderer.close(true);
} }
}); });
player.eventNode().addListener(onCloseListener); 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) { synchronized (this) {
if (onCloseListener == null) return;
if (itemBackup != null) { if (itemBackup != null) {
var inv = player.getInventory(); var inv = player.getInventory();
for (int i = 0; i < itemBackup.length; i++) { for (int i = 0; i < itemBackup.length; i++) {
@ -123,13 +256,14 @@ public class DialogueRenderer extends Inventory {
player.closeInventory(); player.closeInventory();
if (onCloseListener != null) { player.eventNode().removeListener(onCloseListener);
player.eventNode().removeListener(onCloseListener); onCloseListener = null;
onCloseListener = null;
} player.eventNode().removeListener(onClickListener);
onClickListener = null;
} }
if (onClose != null) onClose.run(); if (onClose != null) onClose.onClose(closedByPlayer);
} }
private Component render() { private Component render() {
@ -167,7 +301,7 @@ public class DialogueRenderer extends Inventory {
// Answers // Answers
for (var number: ButtonNumber.values()) { for (var number: ButtonNumber.values()) {
if (buttonsText.containsKey(number)) { //TODO: checking answer exists if (buttonsText.containsKey(number)) {
builder.append(number.getIndex() % 2 == 0 builder.append(number.getIndex() % 2 == 0
? theme.getPositions().answerField().leftFieldX() ? theme.getPositions().answerField().leftFieldX()
: theme.getPositions().answerField().rightFieldX(), : theme.getPositions().answerField().rightFieldX(),
@ -204,7 +338,12 @@ public class DialogueRenderer extends Inventory {
number.getIndex() % 2 == 0 number.getIndex() % 2 == 0
? theme.getPositions().answerText().leftLineX() ? theme.getPositions().answerText().leftLineX()
: theme.getPositions().answerText().rightLineX(), : 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 { } else {
@ -263,11 +402,40 @@ public class DialogueRenderer extends Inventory {
line.textureProperties(), line.textureProperties(),
shift, shift,
textLines.size() - lineIdx > 0 && lineIdx - shift == positions.phraseText().maxLines() - 1, textLines.size() - lineIdx > 0 && lineIdx - shift == positions.phraseText().maxLines() - 1,
positions.phraseText().textColor() getTheme().getColorText()
)); ));
} }
} }
private List<Component> splitAnswerText(String text) {
var style = Style.style()
.decoration(TextDecoration.ITALIC, false)
.color(getTheme().getColorAnswerItemText())
.build();
var lines = new ArrayList<Component>();
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<AnswerClickContext> 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) { private record TextLine(DialogueTheme theme, Component text, TextureProperties textureProperties) {
public List<@NotNull AppendableGlyph> toGlyphList(TextureProperties parentProperties, int lineShift, boolean cutEnding, TextColor color) { 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); 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;
}
} }

View File

@ -5,12 +5,20 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; 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.ServerBootstrap;
import ru.dragonestia.msb3.api.glyph.glyph.image.ImageGlyph; import ru.dragonestia.msb3.api.glyph.glyph.image.ImageGlyph;
import ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter.LanguageGlyphCollection; import ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter.LanguageGlyphCollection;
import ru.dragonestia.msb3.api.resource.DialogueResources; import ru.dragonestia.msb3.api.resource.DialogueResources;
import ru.dragonestia.msb3.api.resource.dialog.*; import ru.dragonestia.msb3.api.resource.dialog.*;
import java.util.function.Consumer;
@Log4j2 @Log4j2
@Getter @Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@ -38,6 +46,16 @@ public class DialogueTheme {
private final ImageGlyph button3; private final ImageGlyph button3;
private final ImageGlyph button4; private final ImageGlyph button4;
private final LanguageGlyphCollection font; 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<Player> onScrollText;
public Builder toBuilder() { public Builder toBuilder() {
return new Builder( return new Builder(
@ -61,7 +79,17 @@ public class DialogueTheme {
button2, button2,
button3, button3,
button4, 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 button3;
private ImageGlyph button4; private ImageGlyph button4;
private LanguageGlyphCollection font; 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<Player> onScrollText;
private Builder(DialogGlyphPositions positions) { private Builder(DialogGlyphPositions positions) {
resources = ServerBootstrap.getInstance().getResourcePackManager().getDialogueResources(); 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 (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 (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 (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( return new DialogueTheme(
positions, positions,
@ -145,7 +214,17 @@ public class DialogueTheme {
button2, button2,
button3, button3,
button4, button4,
font font,
textScrollUp,
textScrollDown,
textPrefixAnswer,
colorAnswerItemText,
colorText,
colorAnswerText1,
colorAnswerText2,
colorAnswerText3,
colorAnswerText4,
onScrollText
); );
} }
@ -213,5 +292,45 @@ public class DialogueTheme {
} }
return this; 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<Player> 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;
}
} }
} }

View File

@ -0,0 +1,6 @@
package ru.dragonestia.msb3.api.talk.dialogue;
public interface OnCloseDialog {
void onClose(boolean closedByPlayer);
}