-
Notifications
You must be signed in to change notification settings - Fork 0
3. Event System and Behaviors
Monolith API features a robust, hierarchical event system designed to handle interactions with custom blocks efficiently. It distinguishes between global events and block-specific behaviors.
When an interaction occurs (e.g., a player breaks a block), the API dispatches an event. The dispatch process follows a specific order:
-
Global Event Bus: The event is first dispatched to all listeners registered on the global
MonolithAPI.api().events()bus. This allows plugins to monitor or intercept all block interactions globally. -
Block Behavior Node: If the event implements
MonolithBlockEvent(meaning it pertains to a specificPlacedBlock), it is subsequently dispatched to theBlockBehaviornode associated with that block'sBlockDefinition.
This architecture ensures that global systems (like logging or protection plugins) can process events before block-specific logic executes.
The BlockBehavior node is a localized event bus specific to a BlockDefinition. Listeners registered here will only receive events related to instances of that specific block type. This eliminates the need for manual identifier checks within event handlers, leading to cleaner and more performant code.
This example demonstrates handling block placement, interaction, and destruction for the IndustrialGenerator.
package com.example.industrial.blocks;
import org.bukkit.entity.Player;
import io.github.zawarka03.monolithAPI.api.block.PlacedBlock;
import io.github.zawarka03.monolithAPI.api.event.MonolithEventHandler;
import io.github.zawarka03.monolithAPI.api.event.events.MonolithBlockBreakEvent;
import io.github.zawarka03.monolithAPI.api.event.events.MonolithBlockInteractEvent;
import io.github.zawarka03.monolithAPI.api.event.events.MonolithBlockPlaceEvent;
import io.github.zawarka03.monolithAPI.api.event.listener.MonolithListener;
public class GeneratorBehavior implements MonolithListener {
private final IndustrialGenerator definition;
public GeneratorBehavior(IndustrialGenerator definition) {
this.definition = definition;
}
@MonolithEventHandler
public void onPlace(MonolithBlockPlaceEvent event) {
PlacedBlock block = event.getPlacedBlock();
Player player = event.getPlayer();
// Initialize persistent data upon placement
block.getData().set(definition.STORED_ENERGY, 0);
block.getData().set(definition.OWNER_UUID, player.getUniqueId().toString());
player.sendMessage("Industrial Generator placed successfully.");
}
@MonolithEventHandler
public void onInteract(MonolithBlockInteractEvent event) {
PlacedBlock block = event.getPlacedBlock();
Player player = event.getPlayer();
// Retrieve persistent data
int currentEnergy = block.getData().getOrDefault(definition.STORED_ENERGY, 0);
String ownerId = block.getData().get(definition.OWNER_UUID);
if (player.isSneaking()) {
// Simulate charging the generator
int newEnergy = currentEnergy + 100;
block.getData().set(definition.STORED_ENERGY, newEnergy);
player.sendMessage("Generator charged. Current energy: " + newEnergy);
} else {
player.sendMessage("Generator Status - Energy: " + currentEnergy + ", Owner: " + ownerId);
}
}
@MonolithEventHandler
public void onBreak(MonolithBlockBreakEvent event) {
PlacedBlock block = event.getPlacedBlock();
int finalEnergy = block.getData().getOrDefault(definition.STORED_ENERGY, 0);
if (event.getEntity() instanceof Player player) {
player.sendMessage("Generator destroyed. Lost energy: " + finalEnergy);
}
}
}This example demonstrates handling entity movement over the ArcaneInfuser.
package com.example.magic.blocks
import org.bukkit.Particle
import org.bukkit.Sound
import io.github.zawarka03.monolithAPI.api.event.events.MonolithEntityOnBlockMoveEvent
import io.github.zawarka03.monolithAPI.api.event.listener.MonolithListener
import io.github.zawarka03.monolithAPI.api.event.MonolithEventHandler
class InfuserBehavior(private val definition: ArcaneInfuser) : MonolithListener {
@MonolithEventHandler
fun onEntityMove(event: MonolithEntityOnBlockMoveEvent) {
val block = event.placedBlock
val entity = event.entity
// Retrieve the current charge count
val currentCharge = block.data.getOrDefault(definition.chargeCount, 0)
if (currentCharge > 0) {
// Apply a magical effect to the entity
entity.world.spawnParticle(Particle.SPELL_WITCH, entity.location, 20)
entity.world.playSound(entity.location, Sound.BLOCK_ENCHANTMENT_TABLE_USE, 1.0f, 1.0f)
// Decrement the charge
block.data[definition.chargeCount] = currentCharge - 1
}
}
}Global listeners are registered directly on the MonolithAPI.api().events() bus. They are useful for cross-cutting concerns, such as logging, custom protection integrations, or managing API lifecycle events.
Java Global Listener
import io.github.zawarka03.monolithAPI.MonolithAPI;
import io.github.zawarka03.monolithAPI.api.event.MonolithEventHandler;
import io.github.zawarka03.monolithAPI.api.event.events.MonolithBlockCreateEvent;
import io.github.zawarka03.monolithAPI.api.event.listener.MonolithListener;
public class GlobalLoggingListener implements MonolithListener {
@MonolithEventHandler
public void onBlockCreate(MonolithBlockCreateEvent event) {
System.out.println("[Monolith Log] Block created: " + event.getPlacedBlock().getIdentifier() +
" at " + event.getPlacedBlock().getPosition());
}
}
// Registration in onEnable():
// MonolithAPI.api().events().register(new GlobalLoggingListener());Kotlin Global Listener
import io.github.zawarka03.monolithAPI.MonolithAPI
import io.github.zawarka03.monolithAPI.api.event.events.MonolithBlockCreateEvent
// Registration in onEnable():
MonolithAPI.api.events.register<MonolithBlockCreateEvent> { event ->
println("[Monolith Log] Block created: ${event.placedBlock.identifier} at ${event.placedBlock.position}")
}Monolith API supports event cancellation and prioritization, similar to Bukkit.
-
Cancellation: Events implementing
CancellableEvent(e.g.,MonolithBlockBreakEvent,MonolithBlockPlaceEvent) can be cancelled by settingisCancelled = true. If a global listener cancels an event, subsequent global listeners and the block's behavior listeners will still receive the event unless they are configured to ignore cancelled events. -
Priority: Listeners can specify an
EventPriority(LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR). Listeners with lower priority execute first, allowing higher priority listeners to override their decisions (e.g., un-cancelling an event). -
Ignore Cancelled: By default, listeners ignore cancelled events (
ignoreCancelled = true). If you need a listener to execute even if the event has been cancelled by a previous listener, you must explicitly setignoreCancelled = falseduring registration.