feat: implemented interlocutors and NPCClickEvent

This commit is contained in:
Andrey Terentev 2025-03-13 02:11:53 +07:00
parent f082b3b9f6
commit a6fc0924a7
9 changed files with 170 additions and 8 deletions

View File

@ -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.AlwaysDialogConditionHandler;
import ru.dragonestia.msb3.api.dialog.condition.NeverDialogConditionHandler; import ru.dragonestia.msb3.api.dialog.condition.NeverDialogConditionHandler;
import ru.dragonestia.msb3.api.entity.PickableItem; 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.item.ItemUtil;
import ru.dragonestia.msb3.api.player.MsbPlayer; import ru.dragonestia.msb3.api.player.MsbPlayer;
import ru.dragonestia.msb3.api.player.PlayerContextManager; import ru.dragonestia.msb3.api.player.PlayerContextManager;
@ -96,6 +97,8 @@ public final class ServerBootstrap {
initDefaultSkins(); initDefaultSkins();
initDefaultDialogActionsAndConditions(); initDefaultDialogActionsAndConditions();
NPCClickEvent.init();
} }
private void initDefaultModules() { private void initDefaultModules() {

View File

@ -7,6 +7,7 @@ import lombok.Setter;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.minestom.server.entity.Player; 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.PlayerContext;
import ru.dragonestia.msb3.api.player.defaults.TalksContext; import ru.dragonestia.msb3.api.player.defaults.TalksContext;
import ru.dragonestia.msb3.api.resource.dialog.ButtonNumber; 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 ru.dragonestia.msb3.api.util.DebugMessage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
@Log4j2 @Log4j2
@ -32,7 +32,7 @@ public class Dialog {
private String themeId; private String themeId;
private List<DialogButton> buttons; private List<DialogButton> buttons;
public void switchDialog(Player player, DialogueRenderer renderer) { public void switchDialog(Player player, DialogueRenderer renderer, Interlocutor interlocutor) {
var ctx = PlayerContext.of(player, TalksContext.class); var ctx = PlayerContext.of(player, TalksContext.class);
if (rememberId) { if (rememberId) {
ctx.getOpenedDialogues().add(id.asString()); ctx.getOpenedDialogues().add(id.asString());
@ -49,7 +49,9 @@ public class Dialog {
log.error("Unknown theme: {}", themeId); log.error("Unknown theme: {}", themeId);
} }
} }
renderer.setTheme(theme); renderer.setTheme(theme.toBuilder()
.setAvatar(interlocutor.getDialogAvatar())
.build());
renderer.setText(text); renderer.setText(text);
@ -60,16 +62,16 @@ public class Dialog {
if (buttons.isEmpty()) break; if (buttons.isEmpty()) break;
var button = buttons.removeFirst(); var button = buttons.removeFirst();
renderer.setButton(buttonNumber, button.getText(), buttonCtx -> { 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); button.onClick(click);
}); });
} }
renderer.rerender(); 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())); var renderer = DialogueRenderer.getRenderer(player).orElseGet(() -> new DialogueRenderer(player, DialogueTheme.builder().build()));
switchDialog(player, renderer); switchDialog(player, renderer, interlocutor);
renderer.show(); renderer.show();
} }
} }

View File

@ -1,13 +1,15 @@
package ru.dragonestia.msb3.api.dialog; package ru.dragonestia.msb3.api.dialog;
import net.minestom.server.entity.Player; 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.resource.dialog.ButtonNumber;
import ru.dragonestia.msb3.api.ui.dialogue.DialogueRenderer; import ru.dragonestia.msb3.api.ui.dialogue.DialogueRenderer;
public record DialogButtonClick( public record DialogButtonClick(
Player player, Player player,
Interlocutor interlocutor,
Dialog dialog, Dialog dialog,
DialogButton dialogButton, DialogButton dialogButton,
ButtonNumber buttonNumber, ButtonNumber buttonNumber,
DialogueRenderer renderer DialogueRenderer renderer
) { } ) {}

View File

@ -27,6 +27,6 @@ public class DialogDialogActionHandler implements DialogActionHandler {
return; return;
} }
dialog.get().switchDialog(player, click.renderer()); dialog.get().switchDialog(player, click.renderer(), click.interlocutor());
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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