feat: fully implemented dialog renderer
This commit is contained in:
parent
fb04fbe692
commit
399857a7b5
@ -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'
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {}
|
||||
@ -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) {}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
package ru.dragonestia.msb3.api.talk.dialogue;
|
||||
|
||||
public interface OnCloseDialog {
|
||||
|
||||
void onClose(boolean closedByPlayer);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user