diff --git a/api/src/main/java/ru/dragonestia/msb3/api/boot/ServerBootstrap.java b/api/src/main/java/ru/dragonestia/msb3/api/boot/ServerBootstrap.java index 72220be..1f6fe26 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/boot/ServerBootstrap.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/boot/ServerBootstrap.java @@ -14,6 +14,7 @@ import ru.dragonestia.msb3.api.dialog.action.DialogDialogActionHandler; import ru.dragonestia.msb3.api.dialog.condition.AlwaysDialogConditionHandler; import ru.dragonestia.msb3.api.dialog.condition.NeverDialogConditionHandler; import ru.dragonestia.msb3.api.entity.PickableItem; +import ru.dragonestia.msb3.api.event.NPCClickEvent; import ru.dragonestia.msb3.api.item.ItemUtil; import ru.dragonestia.msb3.api.player.MsbPlayer; import ru.dragonestia.msb3.api.player.PlayerContextManager; @@ -96,6 +97,8 @@ public final class ServerBootstrap { initDefaultSkins(); initDefaultDialogActionsAndConditions(); + + NPCClickEvent.init(); } private void initDefaultModules() { diff --git a/api/src/main/java/ru/dragonestia/msb3/api/dialog/Dialog.java b/api/src/main/java/ru/dragonestia/msb3/api/dialog/Dialog.java index c83b861..18da16e 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/dialog/Dialog.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/dialog/Dialog.java @@ -7,6 +7,7 @@ import lombok.Setter; import lombok.extern.log4j.Log4j2; import net.kyori.adventure.key.Key; import net.minestom.server.entity.Player; +import ru.dragonestia.msb3.api.dialog.interlocutor.Interlocutor; import ru.dragonestia.msb3.api.player.PlayerContext; import ru.dragonestia.msb3.api.player.defaults.TalksContext; import ru.dragonestia.msb3.api.resource.dialog.ButtonNumber; @@ -16,7 +17,6 @@ import ru.dragonestia.msb3.api.ui.dialogue.DialogueTheme; import ru.dragonestia.msb3.api.util.DebugMessage; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; @Log4j2 @@ -32,7 +32,7 @@ public class Dialog { private String themeId; private List buttons; - public void switchDialog(Player player, DialogueRenderer renderer) { + public void switchDialog(Player player, DialogueRenderer renderer, Interlocutor interlocutor) { var ctx = PlayerContext.of(player, TalksContext.class); if (rememberId) { ctx.getOpenedDialogues().add(id.asString()); @@ -49,7 +49,9 @@ public class Dialog { log.error("Unknown theme: {}", themeId); } } - renderer.setTheme(theme); + renderer.setTheme(theme.toBuilder() + .setAvatar(interlocutor.getDialogAvatar()) + .build()); renderer.setText(text); @@ -60,16 +62,16 @@ public class Dialog { if (buttons.isEmpty()) break; var button = buttons.removeFirst(); renderer.setButton(buttonNumber, button.getText(), buttonCtx -> { - var click = new DialogButtonClick(buttonCtx.player(), this, button, buttonCtx.buttonNumber(), buttonCtx.renderer()); + var click = new DialogButtonClick(buttonCtx.player(), interlocutor, this, button, buttonCtx.buttonNumber(), buttonCtx.renderer()); button.onClick(click); }); } renderer.rerender(); } - public synchronized void open(Player player) { + public synchronized void open(Player player, Interlocutor interlocutor) { var renderer = DialogueRenderer.getRenderer(player).orElseGet(() -> new DialogueRenderer(player, DialogueTheme.builder().build())); - switchDialog(player, renderer); + switchDialog(player, renderer, interlocutor); renderer.show(); } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/dialog/DialogButtonClick.java b/api/src/main/java/ru/dragonestia/msb3/api/dialog/DialogButtonClick.java index fee5f29..2d8df81 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/dialog/DialogButtonClick.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/dialog/DialogButtonClick.java @@ -1,13 +1,15 @@ package ru.dragonestia.msb3.api.dialog; import net.minestom.server.entity.Player; +import ru.dragonestia.msb3.api.dialog.interlocutor.Interlocutor; import ru.dragonestia.msb3.api.resource.dialog.ButtonNumber; import ru.dragonestia.msb3.api.ui.dialogue.DialogueRenderer; public record DialogButtonClick( Player player, + Interlocutor interlocutor, Dialog dialog, DialogButton dialogButton, ButtonNumber buttonNumber, DialogueRenderer renderer -) { } +) {} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/dialog/action/DialogDialogActionHandler.java b/api/src/main/java/ru/dragonestia/msb3/api/dialog/action/DialogDialogActionHandler.java index 8d11262..780fe74 100644 --- a/api/src/main/java/ru/dragonestia/msb3/api/dialog/action/DialogDialogActionHandler.java +++ b/api/src/main/java/ru/dragonestia/msb3/api/dialog/action/DialogDialogActionHandler.java @@ -27,6 +27,6 @@ public class DialogDialogActionHandler implements DialogActionHandler { return; } - dialog.get().switchDialog(player, click.renderer()); + dialog.get().switchDialog(player, click.renderer(), click.interlocutor()); } } diff --git a/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/AnonymousInterlocutor.java b/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/AnonymousInterlocutor.java new file mode 100644 index 0000000..b0ad076 --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/AnonymousInterlocutor.java @@ -0,0 +1,15 @@ +package ru.dragonestia.msb3.api.dialog.interlocutor; + +import ru.dragonestia.msb3.api.resource.DialogueResources; +import ru.dragonestia.msb3.api.resource.MonologueResources; + +public class AnonymousInterlocutor extends SimpleInterlocutor { + + public AnonymousInterlocutor(String name) { + super( + name, + DialogueResources.getAvatar(DialogueResources.DEFAULT).orElseThrow(), + MonologueResources.getAvatar(MonologueResources.DEFAULT).orElseThrow() + ); + } +} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/Interlocutor.java b/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/Interlocutor.java new file mode 100644 index 0000000..28445d4 --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/Interlocutor.java @@ -0,0 +1,43 @@ +package ru.dragonestia.msb3.api.dialog.interlocutor; + +import net.minestom.server.entity.Player; +import ru.dragonestia.msb3.api.dialog.Dialog; +import ru.dragonestia.msb3.api.ui.dialogue.DialogueRenderer; +import ru.dragonestia.msb3.api.ui.monologue.Monologue; +import ru.dragonestia.msb3.api.ui.monologue.MonologueTheme; +import ru.dragonestia.msb3.resource.glyph.GlyphImage; + +public interface Interlocutor { + + String getInterlocutorName(); + + GlyphImage getDialogAvatar(); + + GlyphImage getMonologAvatar(); + + default MonologueTheme getMonologueTheme() { + return MonologueTheme.builder().build(); + } + + default void sendMonolog(Player receiver, String message) { + sendMonolog(receiver, message, getMonologueTheme()); + } + + default void sendMonolog(Player receiver, String message, MonologueTheme theme) { + Monologue.create(receiver, getInterlocutorName(), message).show(theme); + } + + default void sendDialog(Player receiver, Dialog dialog) { + sendDialog(receiver, dialog, false); + } + + default void sendDialog(Player receiver, Dialog dialog, boolean inDialogueWindowNow) { + if (inDialogueWindowNow) { + var renderer = DialogueRenderer.getRenderer(receiver).orElseThrow(); + dialog.switchDialog(receiver, renderer, this); + renderer.rerender(); + } else { + dialog.open(receiver, this); + } + } +} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/SimpleInterlocutor.java b/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/SimpleInterlocutor.java new file mode 100644 index 0000000..62d0f93 --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/dialog/interlocutor/SimpleInterlocutor.java @@ -0,0 +1,29 @@ +package ru.dragonestia.msb3.api.dialog.interlocutor; + +import lombok.AllArgsConstructor; +import lombok.Setter; +import ru.dragonestia.msb3.resource.glyph.GlyphImage; + +@Setter +@AllArgsConstructor +public class SimpleInterlocutor implements Interlocutor { + + private String name; + private GlyphImage dialogAvatar; + private GlyphImage monologAvatar; + + @Override + public String getInterlocutorName() { + return name; + } + + @Override + public GlyphImage getDialogAvatar() { + return dialogAvatar; + } + + @Override + public GlyphImage getMonologAvatar() { + return monologAvatar; + } +} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/entity/NPC.java b/api/src/main/java/ru/dragonestia/msb3/api/entity/NPC.java new file mode 100644 index 0000000..39a4bc0 --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/entity/NPC.java @@ -0,0 +1,13 @@ +package ru.dragonestia.msb3.api.entity; + +import net.minestom.server.entity.Player; +import ru.dragonestia.msb3.api.event.NPCClickEvent; + +public interface NPC { + + default boolean supportedClickType(NPCClickEvent.ClickType clickType) { + return true; + } + + void onClickByPlayer(Player player, NPCClickEvent.ClickType clickType); +} diff --git a/api/src/main/java/ru/dragonestia/msb3/api/event/NPCClickEvent.java b/api/src/main/java/ru/dragonestia/msb3/api/event/NPCClickEvent.java new file mode 100644 index 0000000..9e3e270 --- /dev/null +++ b/api/src/main/java/ru/dragonestia/msb3/api/event/NPCClickEvent.java @@ -0,0 +1,55 @@ +package ru.dragonestia.msb3.api.event; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.minestom.server.MinecraftServer; +import net.minestom.server.entity.Entity; +import net.minestom.server.entity.Player; +import net.minestom.server.entity.PlayerHand; +import net.minestom.server.event.entity.EntityAttackEvent; +import net.minestom.server.event.player.PlayerEntityInteractEvent; +import net.minestom.server.event.trait.EntityEvent; +import net.minestom.server.event.trait.InstanceEvent; +import net.minestom.server.instance.Instance; +import org.jetbrains.annotations.NotNull; +import ru.dragonestia.msb3.api.entity.NPC; + +import java.util.Objects; + +@RequiredArgsConstructor +public class NPCClickEvent implements EntityEvent, InstanceEvent { + + @Getter private final Player player; + private final NPC npcEntity; + private final ClickType clickType; + + @Override + public @NotNull Entity getEntity() { + return (Entity) npcEntity; + } + + @Override + public @NotNull Instance getInstance() { + return Objects.requireNonNull(player.getInstance()); + } + + public enum ClickType { + ATTACK, + INTERACT + } + + public static void init() { + MinecraftServer.getGlobalEventHandler().addListener(PlayerEntityInteractEvent.class, event -> { + if (event.getHand() != PlayerHand.MAIN) return; + if (event.getEntity() instanceof NPC npc) { + if (!npc.supportedClickType(ClickType.INTERACT)) return; + MinecraftServer.getGlobalEventHandler().call(new NPCClickEvent(event.getPlayer(), npc, ClickType.INTERACT)); + } + }).addListener(EntityAttackEvent.class, event -> { + if (event.getTarget() instanceof NPC npc && event.getEntity() instanceof Player player) { + if (!npc.supportedClickType(ClickType.ATTACK)) return; + MinecraftServer.getGlobalEventHandler().call(new NPCClickEvent(player, npc, ClickType.ATTACK)); + } + }); + } +}