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
CitizenInteractEventfires — if cancelled, everything below is skipped- Permission check against
citizen.getRequiredPermission() - Interaction source filtering (F_KEY vs LEFT_CLICK vs BOTH)
ON_INTERACTanimations trigger- Messages are delivered using the configured selection mode
- 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() + "!");
});