-
Notifications
You must be signed in to change notification settings - Fork 0
Custom Events
Zeroknights edited this page Mar 14, 2026
·
13 revisions
This page explains how to run Athena custom events for your AthenaBot plugin.
Assumption: you already know how regular Discord event listeners work.
- Create a new event file in /plugins/<plugin_name>/src/events/.
- Name the file with a unique event listener name (example: myLevelUpListener.js).
- Set event.discord to the Athena custom event name you want to listen to (example: athena:levelUp).
Example:
const event = require('../../../../main/discord/core/events/event.js');
module.exports = class myLevelUpListener extends event {
constructor(heart) {
super(heart, { name: 'myLevelUpListener', event: { discord: 'athena:levelUp', bypassManager: false, dm: false, bypassRestrictions: true, permissionLevel: null } });
}
async execute(userId, newLevel) {
try {
this.heart.core.console.log(this.heart.core.console.type.log,`${userId} reached level ${newLevel}`);
}
catch (err) {
this.heart.core.console.log(this.heart.core.console.type.error, `An issue occurred while executing event ${this.getName()}`);
new this.heart.core.error.interface(this.heart, err);
}
}
};- name: Unique identifier for your listener file.
- discord: The Athena custom event name (example: athena:levelUp).
- bypassManager: Keep false unless you fully understand the side effects.
- dm: Only relevant for Discord interaction events. Keep false for Athena custom events.
- bypassRestrictions: Keep true.
- permissionLevel: Only relevant for Discord interaction events. Keep null for Athena custom events.
(!) For custom events, the important value is event.discord. It must exactly match the emitted event name.
Custom events are not fired by Discord.js. You run them by calling Athena eventManager.emitSafe from your feature logic.
Example emitter:
// Example: after level-up logic is completed
const didEmit = await this.heart.manager.discord.eventManager.emitSafe('athena:levelUp', userId, newLevel);
if (!didEmit) {
this.heart.core.console.log(this.heart.core.console.type.warn, 'Event emitted but no listener was registered');
}What happens when emitSafe is called:
- Athena finds listeners where event.discord matches the event name.
- Athena executes each listener with the payload in the same argument order.
- Athena skips disabled listeners/plugins.
- Athena catches and logs errors per listener.
- Athena returns true when at least one listener existed, otherwise false.
(!) Payload order must match exactly.
If you emit:
emitSafe('athena:levelUp', userId, newLevel)Your listener should be:
async execute(userId, newLevel) {
// ...
}- Event names are case-sensitive.
- Do not rename athena:* events unless all emitters and listeners are updated together.
- IDs are Discord snowflakes (string) unless the event signature states otherwise.
- Object payloads (ticket/application/errorInterface) should be treated as internal APIs that may evolve.
Signatures are shown as:
- EventName(arg1, arg2, ...)
- athena:error(errorInterface)
- athena:levelUp(userId, level)
- athena:bankUpgrade(userId, bankLevel)
- athena:shopPurchase(userId, itemId, cost)
- athena:jobUpgrade(userId, jobKey, jobLevel)
- athena:lootboxRollPurchase(userId, purchasedRolls)
- athena:lootboxOpen(userId, rewardType, rewardAmount)
- athena:questClaim(userId, period, finishedQuestCount, rewards)
- athena:rankUpgrade(userId, newRank)
- athena:countingGameSuccess(userId, counterValue)
- athena:countingGameFail(userId, evaluatedInput, expectedCounter)
- athena:hangmanEnd(userId, won, streak, winStreakCurrent)
- athena:higherLowerEnd(userId, streak, highscore)
- athena:starboardSend(userId, messageId, reactionCount)
- athena:starboardReaction(userId, messageId, reactionCount)
- athena:giveawayEnter(userId, giveawayMessageId, entryCount)
- athena:giveawayLeave(userId, giveawayMessageId, entryCount)
- athena:tempVoiceCreate(voiceChannelId, ownerUserId, sourceChannelId)
- athena:tempVoiceDelete(voiceChannelId, ownerUserId)
- athena:tempVoiceOwnerChange(voiceChannelId, previousOwnerUserId, newOwnerUserId)
- athena:tempVoiceOwnerSet(voiceChannelId, executorUserId, newOwnerUserId)
- athena:tempVoiceName(voiceChannelId, executorUserId, newName)
- athena:tempVoiceLimit(voiceChannelId, executorUserId, newLimit)
- athena:tempVoiceVisibility(voiceChannelId, executorUserId, visibility)
- athena:tempVoiceKick(voiceChannelId, executorUserId, targetUserId)
- athena:tempVoiceBlacklist(voiceChannelId, executorUserId, targetUserId)
- athena:tempVoiceUnblacklist(voiceChannelId, executorUserId, targetUserId)
- athena:applySavedRoles(userId, roleCount)
- athena:autoRole(userId, roleCount)
- athena:saveRoles(userId, roleCount)
- athena:pollVote(userId, pollId, optionId)
- athena:pollVoteRevoke(userId, pollId, optionId)
- athena:suggestionCreate(userId, suggestionNumber)
- athena:suggestionStatus(staffUserId, suggestionId, status)
- athena:suggestionReview(staffUserId, suggestionId, approved)
- athena:blacklist(type, targetUserId, executorUserId, punishmentId)
- athena:unblacklist(type, targetUserId, executorUserId, punishmentId)
- athena:ban(targetUserId, executorUserId, punishmentId, manual)
- athena:unban(targetUserId, executorUserId, punishmentId, manual)
- athena:kick(targetUserId, executorUserId, punishmentId, manual)
- athena:mute(targetUserId, executorUserId, punishmentId, manual)
- athena:unmute(targetUserId, executorUserId, punishmentId, manual)
- athena:warn(targetUserId, executorUserId, punishmentId)
- athena:unwarn(targetUserId, executorUserId, punishmentId)
- athena:strike(targetUserId, executorUserId, punishmentId, strikeAmount)
- athena:automodAction(userId, ruleName, warning)
- athena:nodeConnect(nodeName)
- athena:nodeDisconnect(nodeName, disconnectCount)
- athena:nodeError(nodeName, errorMessageOrNull)
- athena:playerCreate(guildIdOrNull, defaultVolume)
- athena:trackStart(guildId, requesterUserId, title)
- athena:trackEnd(guildId, titleOrNull, remainingQueueLength)
- athena:queueEnd(guildId, textChannelId)
- athena:autoVerify(userId)
- athena:verifyFail(userId, remainingAttempts)
- athena:verifySuccess(userId)
- athena:twitchInitialize()
- athena:twitchLive(username, messageId, viewerCount)
- athena:twitchOffline(username)
- athena:youtubeNotification(authorName, videoId, discordChannelId)
- athena:verifyStaffRoles()
- athena:verifyStaffRolesFail(invalidRoleIds)
- athena:strikelistView(viewerUserId, targetMemberId, punishmentId, page)
- athena:taskClaim(userId, taskId)
- athena:taskEditOpen(userId, taskId, type)
- athena:taskEdit(userId, taskId, type)
- athena:ticketCreate(ticket)
- athena:ticketAdd(ticket, addedUserId)
- athena:ticketRemove(ticket, removedUserId)
- athena:ticketRename(ticket, newName)
- athena:ticketClaim(ticket, claimerUserId)
- athena:ticketUnclaim(ticket, unclaimerUserId)
- athena:ticketClose(ticket)
- athena:ticketLower(ticket, level)
- athena:ticketElevate(ticket, level)
- athena:applicationStart(userId, applicationIndex)
- athena:applicationSubmit(userId, applicationIndex, answersCount, submitted)
- athena:applicationCancel(userId, applicationIndex)
- athena:applicationChannelCreate(application)
- athena:applicationChatAllow(applicantUserId, staffUserId, appChannelId)
- athena:applicationChatDeny(applicantUserId, staffUserId, appChannelId)
- athena:applicationHistoryView(staffUserId, applicantUserId, appChannelId)
- athena:applicationAccept(application, roleName, staffUserId)
- athena:applicationDeny(application, staffUserId, reason, timeoutMs)
- athena:applicationAutoClose(application)