Skip to main content

API Reference

Technical reference for plugin developers. Provides programmatic access to the Citizen and Dialog systems through the unified CoreAPI facade.

Module

The CoreAPI is provided by kyuubisoft-core.jar. Ensure the Core mod is loaded before calling any API methods.

Getting the API Instance

import com.kyuubisoft.core.api.CoreAPI;

// Availability check (recommended)
if (CoreAPI.isAvailable()) {
CoreAPI api = CoreAPI.getInstance();
// ...
}

// Or direct (returns null if Core is not loaded)
CoreAPI api = CoreAPI.getInstance();
if (api == null) {
// Core plugin not loaded
return;
}

Citizen Methods

MethodReturn TypeDescription
getCitizen(String id)CitizenDataGet CitizenData by ID, or null if not found
getAllCitizens()Collection<CitizenData>Get all registered citizens (never null)
getCitizensByGroup(String group)List<CitizenData>Get citizens matching a group (never null)
addCitizenListener(CitizenListener)voidAdd a citizen lifecycle listener
removeCitizenListener(CitizenListener)voidRemove a citizen lifecycle listener
addDialogInterceptor(CitizenDialogInterceptor)voidAdd a dialog interceptor (checked before default dialogs)
removeDialogInterceptor(CitizenDialogInterceptor)voidRemove a dialog interceptor
dispatchCitizenInteract(Player, String citizenId)voidTrigger a citizen interaction event programmatically
pauseCitizenMovement(CitizenData, Player)voidPause NPC movement (e.g., during dialog)
resumeCitizenMovement(String citizenId)voidResume NPC movement after interaction
isCitizenPaused(String citizenId)booleanCheck if an NPC is currently paused

Dialog Methods

MethodReturn TypeDescription
openDialog(Player, PlayerRef, Ref, Store, String dialogId, String citizenId)voidOpen a dialog by its ID
openDialogFromTree(Player, PlayerRef, Ref, Store, DialogTree, String citizenId)voidOpen a dialog from a pre-built DialogTree object
addDialogConditionProvider(DialogConditionProvider)voidRegister a custom condition provider for dialog branching
removeDialogConditionProvider(DialogConditionProvider)voidRemove a condition provider

Interfaces

CitizenListener

Implement this interface to receive citizen lifecycle events. All methods have default no-op implementations, so you only need to override what you need.

import com.kyuubisoft.core.citizen.CitizenListener;

public interface CitizenListener {
/** Player interacts with an NPC (before dialog opens) */
default void onCitizenInteract(Player player, String citizenId) {}

/** Player selects a dialog choice */
default void onDialogChoice(Player player, String dialogId, int choiceIndex, String choiceText) {}

/** Dialog chain is fully completed */
default void onDialogComplete(Player player, String dialogId) {}

/** Player enters text input during a dialog */
default void onDialogInput(Player player, String dialogId, String input) {}
}

CitizenDialogInterceptor

Implement this interface to intercept NPC interactions before the default dialog system runs. If your interceptor returns true, no further dialog processing occurs.

import com.kyuubisoft.core.citizen.CitizenDialogInterceptor;

public interface CitizenDialogInterceptor {
/**
* Attempt to intercept the dialog for a citizen.
*
* @return true if this interceptor handled the interaction (no further dialog will open)
*/
boolean interceptDialog(Player player, PlayerRef playerRef,
Ref<EntityStore> ref, Store<EntityStore> store,
String citizenId);
}

DialogConditionProvider

Implement this interface to provide custom conditions for dialog branching. Used by the Quest mod, Achievement mod, and others to enable conditional dialog flows.

import com.kyuubisoft.core.dialog.DialogConditionProvider;

public interface DialogConditionProvider {
/** Whether this provider handles the given condition type. */
boolean handles(String conditionType);

/** Evaluate the condition for a player. */
boolean evaluate(Player player, String conditionType, String value, boolean negate);
}

Usage Examples

Get Citizen Data

CoreAPI api = CoreAPI.getInstance();

CitizenData citizen = api.getCitizen("blacksmith_npc");
if (citizen != null) {
String name = citizen.getDisplayName();
boolean hasShop = citizen.shopId != null;
LOGGER.info("Citizen: " + name + ", shop: " + hasShop);
}

// Get all citizens in a group
List<CitizenData> guards = api.getCitizensByGroup("town_guards");
LOGGER.info("Found " + guards.size() + " town guards");

React to Citizen Interactions (Interceptor)

CoreAPI api = CoreAPI.getInstance();

api.addDialogInterceptor((player, playerRef, ref, store, citizenId) -> {
if ("quest_giver".equals(citizenId)) {
// Open custom quest UI instead of default dialog
openQuestUI(player, playerRef, ref, store);
return true; // Intercepted — no default dialog
}
return false; // Let default dialog system handle it
});

Open a Dialog Programmatically

CoreAPI api = CoreAPI.getInstance();

// Open a specific dialog for a citizen
// (typically called from within a command or event handler that has access to PlayerRef/Ref/Store)
api.openDialog(player, playerRef, ref, store, "greeting_dialog", "merchant_npc");

Pause and Resume NPC Movement

CoreAPI api = CoreAPI.getInstance();

CitizenData npc = api.getCitizen("patrol_guard");
if (npc != null && !api.isCitizenPaused("patrol_guard")) {
// Pause the NPC while player interacts
api.pauseCitizenMovement(npc, player);

// ... do interaction ...

// Resume movement when done
api.resumeCitizenMovement("patrol_guard");
}

Register a Dialog Condition Provider

CoreAPI api = CoreAPI.getInstance();

api.addDialogConditionProvider(new DialogConditionProvider() {
@Override
public boolean handles(String type) {
return "quest_active".equals(type) || "quest_completed".equals(type);
}

@Override
public boolean evaluate(Player player, String type, String value, boolean negate) {
boolean result = switch (type) {
case "quest_active" -> questService.isQuestActive(player, value);
case "quest_completed" -> questService.isQuestCompleted(player, value);
default -> false;
};
return negate ? !result : result;
}
});

Thread Safety

  • The API uses CopyOnWriteArrayList for all listener and interceptor lists (thread-safe registration/removal)
  • All query methods (getCitizen, getAllCitizens, getCitizensByGroup, isCitizenPaused) can be called from any thread
  • pauseCitizenMovement and resumeCitizenMovement involve entity operations and should be called within world.execute() when possible
  • Dialog opening methods (openDialog, openDialogFromTree) involve UI operations and should be called from the main thread or within world.execute()

Java Package Structure

com.kyuubisoft.core.citizen/
├── CitizenData.java - NPC data model
├── CitizenService.java - Citizen lifecycle management
├── CitizenListener.java - Lifecycle event interface
├── CitizenDialogInterceptor.java - Dialog intercept interface

com.kyuubisoft.core.dialog/
├── DialogService.java - Dialog management
├── DialogTree.java - Dialog tree model
├── DialogNode.java - Dialog node model
├── DialogConditionProvider.java - Condition provider interface