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-instrumentation-jvm: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;
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", "<gradient:#ff0059:#e06806><bold>msb3 server</bold></gradient>");
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);

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

View File

@ -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<String> 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<ButtonNumber, String> buttonsText = new EnumMap<>(ButtonNumber.class);
private final EnumMap<ButtonNumber, Consumer<AnswerClickContext>> onAnswerClick = new EnumMap<>(ButtonNumber.class);
private ItemStack[] itemBackup;
private EventListener<InventoryCloseEvent> onCloseListener;
@Getter @Setter private UncheckedRunnable onClose;
private EventListener<InventoryPreClickEvent> 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> 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<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) {
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;
}
}

View File

@ -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<Player> 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<Player> 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<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);
}