Skip to main content

๐Ÿ’ฌ Dialogue Service

DialogueService lets addons start, inspect, and cancel EventForge dialogue sequences.

Dialogues are configured in event files and can be triggered by addons, custom objectives, NPC plugins, or Skript.

EventForge provides the dialogue engine. Your addon decides when a dialogue should start.


When to use dialogues

Dialogues are useful for:

NPC tutorials
quest steps
relic hunts
story events
task chains
custom objective instructions
guided server events
tip

Use dialogues when players need short, timed instructions or NPC-style messages during an event.


Getting the service

DialogueService dialogueService = EventForgeAPI.getDialogueService();

Always check the API first:

if (!EventForgeAPI.isAvailable()) {
return;
}

Event config

Dialogues are configured inside an event file.

dialogues:
guide_intro:
npc-id: "guide"
display-name: "Guide Introduction"
cancel-existing: true
lines:
- speaker: "&eGuide"
text: "&fHello {player}."
title: "&eGuide"
subtitle: "&fWelcome."
sound: ENTITY_VILLAGER_AMBIENT
delay: 3

The dialogue ID here is:

guide_intro

Simple dialogue format

Server owners can also use a simple line list:

dialogues:
guide_intro:
lines:
- "&eGuide: &fHello there!"
- "&eGuide: &fBring me 5 relics."

This is good for small events.


Start an event dialogue

Use:

EventForgeAPI.getDialogueService()
.startEventDialogue(player, "relic_hunt", "guide_intro");

This starts the guide_intro dialogue from the relic_hunt event for that player.


Handling completion

startEventDialogue(...) returns a future so you can continue your addon logic after the dialogue ends.

EventForgeAPI.getDialogueService()
.startEventDialogue(player, "relic_hunt", "guide_intro")
.thenAccept(session -> {
if (session.isCompleted()) {
player.sendMessage("Dialogue complete!");
}
});
info

Dialogue start/cancel operations are main-thread safe for addon developers.


Check whether a dialogue exists

boolean exists = EventForgeAPI.getDialogueService()
.hasDialogue("relic_hunt", "guide_intro");

Example:

DialogueService dialogueService = EventForgeAPI.getDialogueService();

if (!dialogueService.hasDialogue("relic_hunt", "guide_intro")) {
player.sendMessage("That dialogue is not configured.");
return;
}

dialogueService.startEventDialogue(player, "relic_hunt", "guide_intro");

Get dialogue IDs

Set<String> dialogueIds = EventForgeAPI.getDialogueService()
.getDialogueIds("relic_hunt");

Example:

for (String dialogueId : dialogueService.getDialogueIds("relic_hunt")) {
plugin.getLogger().info("Dialogue: " + dialogueId);
}

Get dialogue info

Optional<DialogueSequenceInfo> dialogue = EventForgeAPI.getDialogueService()
.getDialogue("relic_hunt", "guide_intro");

Example:

dialogue.ifPresent(sequence -> {
String id = sequence.getId();
String displayName = sequence.getDisplayName();
int lineCount = sequence.getLines().size();
});

Check if player is in dialogue

boolean inDialogue = EventForgeAPI.getDialogueService().isInDialogue(player);

Example:

if (dialogueService.isInDialogue(player)) {
player.sendMessage("You are already in a dialogue.");
return;
}

Get active session

Optional<DialogueSessionInfo> activeSession = EventForgeAPI
.getDialogueService()
.getActiveSession(player);

Example:

dialogueService.getActiveSession(player).ifPresent(session -> {
player.sendMessage("Current dialogue: " + session.getDialogueId());
});

Cancel dialogue

EventForgeAPI.getDialogueService().cancelDialogue(player);

Use this if your addon needs to stop an active dialogue.

Example:

if (dialogueService.isInDialogue(player)) {
dialogueService.cancelDialogue(player);
}

Start a custom sequence

Most addons should use startEventDialogue(...).

If you are building a completely custom dialogue sequence in code, you can use:

dialogueService.startDialogue(player, sequence);

For normal event-driven addons, prefer configured event dialogues so server owners can edit them in YAML.


Dialogue placeholders

Dialogues support placeholders such as:

{player}
{uuid}
{dialogue}
{dialogue_display}
{npc}
{event}
{event_display}
{var:key}

Example:

variables:
guide_name: "&eRelic Guide"
arena_name: "Spawn Ruins"

dialogues:
guide_intro:
npc-id: "relic_guide"
display-name: "{var:guide_name} Introduction"
lines:
- speaker: "{var:guide_name}"
text: "&fWelcome to {var:arena_name}, {player}."

Dialogue sequence info

DialogueSequenceInfo represents a configured dialogue.

Common methods include:

getId();
getNpcId();
getDisplayName();
shouldCancelExisting();
getLines();
getCompleteCommands();

Example:

DialogueSequenceInfo sequence = dialogue.get();

String id = sequence.getId();
String npcId = sequence.getNpcId();
String displayName = sequence.getDisplayName();
boolean cancelExisting = sequence.shouldCancelExisting();
int lineCount = sequence.getLines().size();

Dialogue line info

DialogueLineInfo represents one dialogue line.

Common methods include:

getSpeaker();
getText();
getTitle();
getSubtitle();
getSound();
getDelaySeconds();

Example:

for (DialogueLineInfo line : sequence.getLines()) {
String speaker = line.getSpeaker();
String text = line.getText();
int delay = line.getDelaySeconds();
}

Dialogue session info

DialogueSessionInfo represents an active or completed dialogue session.

Common methods include:

getEventId();
getDialogueId();
getPlayerUuid();
getPlayerName();
isCompleted();
isCancelled();

Example:

dialogueService.startEventDialogue(player, "relic_hunt", "guide_intro")
.thenAccept(session -> {
if (session.isCompleted()) {
plugin.getLogger().info(session.getPlayerName()
+ " completed "
+ session.getDialogueId());
}
});

Starting dialogue from a custom objective

A common use case is starting a dialogue when a player reaches a task step.

@Override
public void onPlayerMove(
EventObjectiveSession session,
RelicHuntObjectiveData data,
Player player,
PlayerMoveEvent event
) {
if (!playerReachedRelic(player)) {
return;
}

DialogueService dialogueService = EventForgeAPI.getDialogueService();

if (!dialogueService.hasDialogue(session.getEventId(), "guide_intro")) {
return;
}

dialogueService.startEventDialogue(player, session.getEventId(), "guide_intro");
}

Starting dialogue from an NPC plugin

Your addon can listen to an NPC interaction from another plugin, then start the configured dialogue.

Example idea:

public void handleNpcClick(Player player, String npcId) {
if (!npcId.equalsIgnoreCase("relic_guide")) {
return;
}

EventForgeAPI.getDialogueService()
.startEventDialogue(player, "relic_hunt", "guide_intro");
}

EventForge does not require a specific NPC plugin.


Bukkit dialogue events

EventForge fires Bukkit events for dialogue completion and cancellation.

@EventHandler
public void onDialogueComplete(EventForgeDialogueCompleteEvent event) {
String eventId = event.getEventId();
String dialogueId = event.getDialogueId();
String playerName = event.getPlayerName();
}
@EventHandler
public void onDialogueCancel(EventForgeDialogueCancelEvent event) {
String eventId = event.getEventId();
String dialogueId = event.getDialogueId();
String playerName = event.getPlayerName();
}

Use these for quest progression, logs, or cleanup.


Full event config example

id: relic_hunt
enabled: true
display-name: "{var:event_color}Relic Hunt"
duration: 5m

variables:
event_color: "&6"
guide_name: "&eRelic Guide"
arena_name: "Spawn Ruins"

dialogues:
guide_intro:
npc-id: "relic_guide"
display-name: "{var:guide_name} Introduction"
cancel-existing: true
lines:
- speaker: "{var:guide_name}"
text: "&fWelcome to {var:arena_name}, {player}. Ancient relics are hidden nearby."
title: "{var:event_color}Relic Hunt"
subtitle: "&fSearch the ruins for clues."
sound: ENTITY_VILLAGER_AMBIENT
delay: 3

- speaker: "{var:guide_name}"
text: "&fInteract with ancient blocks and recover fragments to earn points."
sound: ENTITY_EXPERIENCE_ORB_PICKUP
delay: 3

complete-commands:
- "say {player} completed the {dialogue_display} dialogue."

Example addon command

public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage("Players only.");
return true;
}

if (args.length < 2) {
sender.sendMessage("/startdialogue <event> <dialogue>");
return true;
}

String eventId = args[0];
String dialogueId = args[1];

DialogueService dialogueService = EventForgeAPI.getDialogueService();

if (!dialogueService.hasDialogue(eventId, dialogueId)) {
player.sendMessage("Unknown dialogue.");
return true;
}

dialogueService.startEventDialogue(player, eventId, dialogueId)
.thenAccept(session -> {
if (session.isCompleted()) {
player.sendMessage("Dialogue complete.");
}
});

return true;
}

Recommended addon structure

src/main/java/com/example/dialogueaddon/
โ”œโ”€ DialogueAddonPlugin.java
โ”œโ”€ command/
โ”‚ โ””โ”€ StartDialogueCommand.java
โ”œโ”€ listener/
โ”‚ โ””โ”€ NpcClickListener.java
โ””โ”€ util/
โ””โ”€ TextUtil.java

Common mistakes

Starting a missing dialogueโ€‹

Check first:

dialogueService.hasDialogue(eventId, dialogueId);

Assuming the player is not already in dialogueโ€‹

Use:

dialogueService.isInDialogue(player);

or let the configured cancel-existing behaviour handle replacement.

Hardcoding all dialogue text in Javaโ€‹

Prefer event config dialogues when possible.

That lets server owners edit text without recompiling the addon.

Forgetting that EventForge is not an NPC pluginโ€‹

EventForge provides the dialogue engine.

Your addon, NPC plugin, Skript, or objective logic needs to decide when to start a dialogue.