Skip to content

Developer API

KoraQuest provides a runtime API and Bukkit quest lifecycle events.

Add KoraQuest as a dependency

Place the API JAR in your local project library and use it as a compile-only dependency. Do not bundle the KoraQuest API classes inside your plugin JAR.

plugin.yml:

depend:
  - KoraQuest

For an optional integration:

softdepend:
  - KoraQuest

Check availability

import dev.ipseucz.koraquest.api.KoraQuestAPI;

if (!KoraQuestAPI.isAvailable()) {
    getLogger().warning("KoraQuest API is not available.");
    return;
}

Query quests and progress

import dev.ipseucz.koraquest.api.KoraQuestAPI;
import dev.ipseucz.koraquest.model.QuestDefinition;

KoraQuestAPI.getQuest("daily_break_stone").ifPresent(quest -> {
    getLogger().info("Quest cycle: " + quest.cycle());
    getLogger().info("Required: " + quest.required());
});

int progress = KoraQuestAPI.getProgress(player.getUniqueId(), "daily_break_stone");
String status = KoraQuestAPI.getStatus(player.getUniqueId(), "daily_break_stone");

Available query methods:

Optional<QuestDefinition> getQuest(String id);
Collection<QuestDefinition> getActiveQuests(UUID uuid);
Collection<QuestDefinition> getActiveQuests(UUID uuid, String cycle);
int getProgress(UUID uuid, String questId);
int getProgress(UUID uuid, String cycle, String questId);
String getStatus(UUID uuid, String questId);

Mutate player quests

boolean accepted = KoraQuestAPI.acceptQuest(player, "daily_break_stone");
boolean cancelled = KoraQuestAPI.cancelQuest(player, "daily_break_stone");
boolean completed = KoraQuestAPI.completeQuest(player, "daily_break_stone");
boolean rerolled = KoraQuestAPI.rerollQuest(player, "daily_break_stone");

Warning

Player mutation methods must run on the player's owning thread when the server uses Folia.

Progress objectives

Progress one specific quest:

KoraQuestAPI.progressQuest(player, "daily_break_stone", 10);

Progress every matching objective:

import dev.ipseucz.koraquest.model.ObjectiveType;

KoraQuestAPI.progress(player, ObjectiveType.CUSTOM, "MY_EVENT", 1);
KoraQuestAPI.progressCustom(player, "MY_EVENT", 1);

Custom objective providers

KoraQuestAPI.registerObjectiveProvider("myplugin", (player, target, amount) -> {
    KoraQuestAPI.progress(player, ObjectiveType.CUSTOM, target, amount);
});

Dispatch to the provider:

KoraQuestAPI.dispatchObjectiveProvider("myplugin", player, "BOSS_DEFEATED", 1);

Remove the provider on plugin shutdown:

KoraQuestAPI.unregisterObjectiveProvider("myplugin");

Custom reward providers

KoraQuestAPI.registerRewardProvider("tokens", (player, quest, value) -> {
    int amount = Integer.parseInt(value);
    // Add tokens with your plugin API.
    return true;
});

The provider returns true only when delivery succeeds. Returning false keeps the reward claim available for retry.

Bukkit events

KoraQuest includes these lifecycle events:

QuestAcceptEvent
QuestCancelEvent
QuestProgressEvent
QuestReadyEvent
QuestCompleteEvent
QuestRewardEvent
QuestCycleResetEvent
QuestRerollEvent

Example listener:

import dev.ipseucz.koraquest.event.QuestCompleteEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

public final class QuestListener implements Listener {
    @EventHandler
    public void onQuestComplete(QuestCompleteEvent event) {
        getLogger().info(event.getPlayer().getName()
                + " completed " + event.getQuest().id());
    }
}

Register the listener normally through Bukkit/Paper.

Threading guidance

  • Query already-loaded data without blocking the main thread.
  • Run player mutations on the correct entity thread.
  • Do not access Bukkit entities from asynchronous database callbacks.
  • Return false from a reward provider when the external reward service is unavailable.
  • Unregister providers in onDisable().