-
Notifications
You must be signed in to change notification settings - Fork 0
Events & Hooks
Samuel De Oliveira edited this page Sep 30, 2026
·
3 revisions
DreamVoice provides an event system across both Paper / Purpur and Fabric.
- On Paper, all events extend
ToolsEvent(informational) andToolsCancelEvent(cancellable) and are dispatched via Bukkit's event bus. - On Fabric, all events extend
VoiceEventand are dispatched via theDreamVoiceEvents.VOICE_EVENTFabric callback hook.
This allows plugins and mods to monitor, restrict, or modify voice behaviors in real time.
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
SpeakerRegisterEvent |
Yes | Before speaker is registered | Fired when a speaker is registered. getSpeaker(). |
SpeakerUnregisterEvent |
No | When speaker is removed | Fired when a speaker is deleted. getSpeaker(). |
SpeakerLinkPlayerEvent |
Yes | When player is linked | Fired when a player is authorized to broadcast speech. getSpeaker(), getPlayerUuid(). |
SpeakerUnlinkPlayerEvent |
No | When player is unlinked | Fired when speech authorization is revoked. getSpeaker(), getPlayerUuid(). |
SpeakerPlaySoundEvent |
Yes | Before audio starts | Fired when playing an audio file, URL, or recording. getSpeaker(), getSource(), isLoop(). |
SpeakerStopSoundEvent |
No | When audio is stopped | Fired when audio playback is stopped. getSpeaker(). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
WiretapRegisterEvent |
Yes | Before wiretap is registered | Fired when a listening bug is created. getWiretap(). |
WiretapRemoveEvent |
No | When wiretap is removed | Fired when a listening bug is deleted. getWiretap(). |
WiretapSubscribeEvent |
Yes | When player listens | Fired when a player starts eavesdropping (/wiretap listen). getWiretap(), getPlayerUuid(). |
WiretapUnsubscribeEvent |
No | When player stops listening | Fired when a player stops eavesdropping. getWiretap(), getPlayerUuid(). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
RadioChannelJoinEvent |
Yes | Before tuning into radio | Fired when a player joins a frequency. getChannel(), getPlayerUuid(). |
RadioChannelLeaveEvent |
No | When leaving frequency | Fired when a player disconnects from radio. getChannel(), getPlayerUuid(). |
RadioChannelCreateEvent |
Yes | Before new channel is created | Fired when a new frequency channel is allocated. getChannel(). |
TransmitterToggleEvent |
Yes | When toggling transmitter | Fired when transmitter mode is activated or deactivated. getPlayerUuid(), isEnabled(). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
VoiceRecordingStartEvent |
Yes | Before recording starts | Fired when voice capture begins. getSpeakerUuid(). |
VoiceRecordingStopEvent |
No | When recording ends | Fired when recording finishes and .dv is saved. getRecording(). |
CassetteCreateEvent |
Yes | When creating cassette item | Fired when generating an interactive item. getRecording(), getItemStack(), setItemStack(...). |
CassettePlayEvent |
Yes | When player uses cassette | Fired when playing tape in personal headphones. getPlayer(), getRecording(), getItemStack(). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
VoiceFilterApplyEvent |
Yes | Before filter is applied | Fired when attaching a filter (e.g. disguise). getPlayerUuid(), getFilter(). |
VoiceFilterRemoveEvent |
No | When filter is removed | Fired when detaching a filter. getPlayerUuid(), getFilter(). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
VoiceWallOcclusionEvent |
Yes | During acoustic raycast | Asynchronous event fired when calculating wall occlusion. Canceling bypasses occlusion (0 dB). getSender(), getReceiver(), getLossDb(), setLossDb(double), isBlocked(), setBlocked(boolean). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
VoiceKeywordSpokenEvent |
No | Realtime keyword detected | Fired when a player speaks a registered keyword matching Vosk grammar. getPlayer(), getKeyword(), getMatchedWord(), getConfidence(). |
TranscriptionStationStartEvent |
Yes | Player interacts with station | Fired when an audio cassette is placed on a transcription block. getPlayer(), getBlock(), getRecording(). |
TranscriptionCompleteEvent |
No | Transcription finished | Fired when speech-to-text finishes (local or sidecar). getRecordingId(), getResult(). |
| Event Class | Cancellable | Trigger Point | Description / Parameters |
|---|---|---|---|
PlayerJoinVoiceEvent |
No | Player connects to SVC | Fired when wrapped into a VPlayer. getVPlayer(). |
PlayerLeaveVoiceEvent |
No | Player disconnects from SVC | Fired on voice disconnect. getVPlayer(). |
PlayerStateChangeEvent |
Yes | Voice state change | Fired when mute/deafen/whisper changes. getOldState(), getNewState(). |
MicrophonePacketEvent |
Yes | Raw microphone packet received | Asynchronous event fired per 20ms Opus frame from client. |
EntitySoundPacketEvent |
Yes | Positional 3D sound dispatched | Asynchronous event dispatched before playing sound relative to an entity. |
On Fabric, register a listener with DreamVoiceEvents.VOICE_EVENT:
import fr.dreamin.dreamvoice.fabric.event.DreamVoiceEvents;
import fr.dreamin.dreamvoice.api.speaker.event.SpeakerLinkPlayerEvent;
import fr.dreamin.dreamvoice.api.speech.event.VoiceKeywordSpokenEvent;
import net.fabricmc.api.ModInitializer;
public class MyFabricVoiceMod implements ModInitializer {
@Override
public void onInitialize() {
DreamVoiceEvents.VOICE_EVENT.register(event -> {
// Pattern matching on event types:
if (event instanceof SpeakerLinkPlayerEvent speakerEvent) {
if (speakerEvent.getSpeaker().getName().startsWith("VIP_")) {
speakerEvent.setCancelled(true);
}
} else if (event instanceof VoiceKeywordSpokenEvent keywordEvent) {
System.out.println("Keyword detected: " + keywordEvent.getKeyword().getId());
}
});
}
}Cancel unauthorized players attempting to link to public auditorium speakers:
import fr.dreamin.dreamvoice.api.speaker.event.SpeakerLinkPlayerEvent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class SpeakerSecurityListener implements Listener {
@EventHandler
public void onSpeakerLink(SpeakerLinkPlayerEvent event) {
Player player = Bukkit.getPlayer(event.getPlayerUuid());
if (player == null) return;
// If the speaker name starts with "Stage_", require staff permission:
if (event.getSpeaker().getName().startsWith("Stage_") && !player.hasPermission("event.host")) {
event.setCancelled(true);
player.sendMessage("§cYou do not have permission to link to the stage speakers!");
}
}
}Prevent players from joining a radio frequency unless they hold a physical Radio item:
import fr.dreamin.dreamvoice.api.radio.event.RadioChannelJoinEvent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class RadioInventoryListener implements Listener {
@EventHandler
public void onRadioJoin(RadioChannelJoinEvent event) {
Player player = Bukkit.getPlayer(event.getPlayerUuid());
if (player == null) return;
// Check if player has an iron nugget named "Walkie-Talkie" in inventory:
boolean hasRadio = player.getInventory().contains(Material.IRON_NUGGET);
if (!hasRadio && !player.isOp()) {
event.setCancelled(true);
player.sendMessage("§cYou need a Walkie-Talkie device in your inventory to tune in!");
}
}
}Customize the display name, custom model data, and lore of physical Cassette items when created:
import fr.dreamin.dreamvoice.api.recording.event.CassetteCreateEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class CassetteLoreListener implements Listener {
@EventHandler
public void onCassetteCreate(CassetteCreateEvent event) {
ItemStack item = event.getItemStack();
ItemMeta meta = item.getItemMeta();
if (meta == null) return;
// Add custom evidence tag for investigation minigame:
meta.displayName(Component.text("Classified Tape", NamedTextColor.RED));
meta.setCustomModelData(105);
item.setItemMeta(meta);
// Replace modified stack back into event:
event.setItemStack(item);
}
}Allow a psychic role or ghost to speak through solid soundproof walls by canceling VoiceWallOcclusionEvent:
import fr.dreamin.dreamvoice.api.wall.event.VoiceWallOcclusionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class PsychicAcousticListener implements Listener {
@EventHandler
public void onOcclusion(VoiceWallOcclusionEvent event) {
// If the sender is tagged with "ghost_whisper" metadata, completely bypass wall loss:
if (event.getSender().hasTag("ghost_whisper")) {
// Canceling the event sets acoustic attenuation to 0 dB (direct line of sight):
event.setCancelled(true);
} else if (event.getSender().hasTag("megaphone")) {
// Cut wall dampening in half:
event.setLossDb(event.getLossDb() * 0.5);
event.setBlocked(false);
}
}
}