Events

HyCitizens fires custom events when players interact with citizens or citizens die. You can listen to these events to add custom logic — or cancel them entirely to prevent the default behavior from running.

Register all event listeners through CitizensManager:

CitizensManager manager = HyCitizensPlugin.get().getCitizensManager();

CitizenInteractEvent

package com.electro.hycitizens.events;

Fired whenever a player interacts with a citizen — either by pressing F (Use) or left-clicking — before any messages, commands, or animations are processed. Cancelling this event prevents the entire interaction pipeline from running.

Event Pipeline Order

  1. CitizenInteractEvent fires — if cancelled, everything below is skipped
  2. Permission check against citizen.getRequiredPermission()
  3. Interaction source filtering (F_KEY vs LEFT_CLICK vs BOTH)
  4. ON_INTERACT animations trigger
  5. Messages are delivered using the configured selection mode
  6. Commands execute sequentially with their configured delays

getCitizen

@Nonnull CitizenData getCitizen()

The citizen that was interacted with.

getPlayerRef

@Nonnull PlayerRef getPlayerRef()

Reference to the player who triggered the interaction.

isCancelled / setCancelled

boolean isCancelled()
void setCancelled(boolean cancelled)

If set to true, the interaction pipeline stops immediately. No messages, commands, or animations will run for this interaction.

Registering a Listener

manager.addCitizenInteractListener(event -> {
    CitizenData citizen = event.getCitizen();
    PlayerRef player = event.getPlayerRef();

    System.out.println(player.getUsername() + " interacted with " + citizen.getName());
});

Cancelling Interactions Conditionally

manager.addCitizenInteractListener(event -> {
    CitizenData citizen = event.getCitizen();
    PlayerRef player = event.getPlayerRef();

    // Block interaction with the quest giver if player isn't level 10+
    if (citizen.getName().equals("Elder Soryn")) {
        int playerLevel = getPlayerLevel(player.getUuid());
        if (playerLevel < 10) {
            event.setCancelled(true);
            player.sendMessage(Message.raw("You need to be level 10 to speak with this elder."));
        }
    }
});

Removing a Listener

// Store a reference to remove it later
CitizenInteractListener myListener = event -> {
    // ... your logic
};

manager.addCitizenInteractListener(myListener);

// Later, when you're done:
manager.removeCitizenInteractListener(myListener);

CitizenDeathEvent

package com.electro.hycitizens.events;

Fired when a citizen is killed, before death drops, death messages, and death commands are processed. You can cancel this event to prevent all death effects from running (drops, messages, commands, and respawn scheduling).

getCitizen

@Nonnull CitizenData getCitizen()

The citizen that died.

getKillerRef

@Nullable PlayerRef getKillerRef()

The player who killed the citizen, or null if they were killed by a non-player source (environment, another NPC, etc.).

isCancelled / setCancelled

boolean isCancelled()
void setCancelled(boolean cancelled)

Cancelling this event suppresses all death effects: no drops, no death messages, no death commands, and no respawn timer will be scheduled.

Registering a Listener

manager.addCitizenDeathListener(event -> {
    CitizenData citizen = event.getCitizen();
    PlayerRef killer = event.getKillerRef();

    if (killer != null) {
        System.out.println(killer.getUsername() + " killed " + citizen.getName());
    } else {
        System.out.println(citizen.getName() + " died to a non-player source");
    }
});

Adding Custom Death Logic

manager.addCitizenDeathListener(event -> {
    CitizenData citizen = event.getCitizen();
    PlayerRef killer = event.getKillerRef();

    // Award bonus XP for killing a boss
    if ("boss".equals(citizen.getGroup()) && killer != null) {
        givePlayerXP(killer.getUuid(), 500);
        killer.sendMessage(Message.raw("{GOLD}You defeated " + citizen.getName() + "! +500 XP").color(Color.YELLOW));
    }
});

Preventing a Citizen from Dying (Conditional Cancellation)

manager.addCitizenDeathListener(event -> {
    CitizenData citizen = event.getCitizen();

    // "Immortal" boss — don't actually die, just drop to low health
    if ("immortal-boss".equals(citizen.getGroup())) {
        event.setCancelled(true); // Suppress drops, messages, respawn
        // Trigger a special phase-change animation instead
        manager.playAnimationForCitizen(citizen, "Emote_Rage", 4);
    }
});

Manually Firing an Interaction

You can trigger the full interaction pipeline on a citizen from your own code, as if a player had pressed F or left-clicked. This fires CitizenInteractEvent, runs permission checks, delivers messages, and executes commands — exactly like a real player interaction.

// Trigger as F key interaction (default)
CitizenInteraction.handleInteraction(citizen, playerRef);

// Trigger as left-click
CitizenInteraction.handleInteraction(citizen, playerRef, CitizenInteraction.SOURCE_LEFT_CLICK);

// Trigger as F key explicitly
CitizenInteraction.handleInteraction(citizen, playerRef, CitizenInteraction.SOURCE_F_KEY);

See CitizenInteraction for more details on the interaction pipeline and color parsing utilities.

Full Example: Gated Quest System

This example combines both events to create a quest NPC that only talks to players who meet a requirement, and awards loot on death of the associated boss.

CitizensManager manager = HyCitizensPlugin.get().getCitizensManager();

// Gate the quest giver — only players with a quest token can interact
manager.addCitizenInteractListener(event -> {
    if (!"quest-givers".equals(event.getCitizen().getGroup())) return;

    if (!playerHasQuestToken(event.getPlayerRef().getUuid())) {
        event.setCancelled(true);
        event.getPlayerRef().sendMessage(
            Message.raw("You need a Guild Token to speak with quest givers.").color(Color.RED)
        );
    }
});

// Award special loot when a boss is killed by a player
manager.addCitizenDeathListener(event -> {
    if (!"bosses".equals(event.getCitizen().getGroup())) return;
    if (event.getKillerRef() == null) return;

    // Add custom loot on top of configured drops
    givePlayerItem(event.getKillerRef().getUuid(), "legendary_sword");
    broadcastMessage(event.getKillerRef().getUsername() + " has slain " + event.getCitizen().getName() + "!");
});