Skip to content

Events

In: Developer · Same group: QinhRuinsAPI · Affix Scripts · Data Storage Back: Core Concepts

QR fires Bukkit events at key points in a ruin's lifecycle, for you to listen to, intercept, and rewrite. All live under the package com.qinhuai.ruins.api. This page lists each one: when it fires, its fields, and whether it's cancellable.


Event quick reference

EventWhenCancellableUse
RuinPreSpawnEventAfter site selection, before pasting the structureIntercept generation at a place / for a template
RuinSpawnEventAfter the anchor is generatedNotify, register, external integration
RuinClearEventWhen a ruin is clearedGive rewards, broadcast, record
RuinLootEventBefore dispatching container lootModify / intercept loot

Cancellation (setCancelled(true)) only works on cancellable events. RuinSpawnEvent / RuinClearEvent are notification-type (the Event has no Cancellable) and can't change the outcome.


1. RuinPreSpawnEvent — cancellable (intercept generation)

Fires before the coordinates have been chosen and the structure is about to be pasted. Cancelling = this generation is voided. Use it to forbid ruin generation in protected areas / player claims / specific dimensions.

kotlin
class RuinPreSpawnEvent(
    val templateId: String,  // The template about to be generated
    val location: Location,  // The chosen spawn point (cloned)
) : Event(), Cancellable
  • isCancelled() / setCancelled(cancel): cancelling intercepts it, the structure won't be pasted and no anchor is produced.

2. RuinSpawnEvent — not cancellable (post-spawn notification)

Fires once an anchor has finished generating. Carries the dimensions so you can compute the bounding box.

kotlin
class RuinSpawnEvent(
    val templateId: String,
    val anchorId: String,    // New anchor id
    val location: Location,  // Anchor origin (minimum corner)
    val width: Int = 0,
    val height: Int = 0,
    val depth: Int = 0,
) : Event() {
    fun minPoint(): Location  // = clone of location (bounding box minimum corner)
    fun maxPoint(): Location  // = location + (w-1, h-1, d-1) (bounding box maximum corner)
}
  • minPoint() / maxPoint(): return the two corners of the ruin's bounding box, convenient for region registration (WorldGuard regions, protection, PVP flags, etc.). When the dimensions are 0, treat as a single point.

3. RuinClearEvent — not cancellable (clear notification)

Fires when a ruin is cleared. Use it to give extra rewards, broadcast, write statistics.

kotlin
class RuinClearEvent(
    val templateId: String,
    val anchorId: String,
    val location: Location,
) : Event()

4. RuinLootEvent — cancellable (modify / intercept loot)

Fires before container loot is dispatched to the player. items is a mutable list; add/remove/modify it directly to rewrite the drops; cancelling intercepts the whole batch (nothing is given).

kotlin
class RuinLootEvent(
    val player: Player,               // The recipient
    val anchorId: String,             // Which ruin it comes from
    val tableName: String,            // The loot table name
    val items: MutableList<ItemStack>,// The items about to be given (mutable)
) : Event(), Cancellable
  • To add extras: add to items.
  • To filter / replace: modify the elements of items or removeIf.
  • To intercept the whole batch: setCancelled(true).

For loot tables and growth scaling see Loot System.


5. Listener examples

Kotlin: intercept generation by region

kotlin
import com.qinhuai.ruins.api.RuinPreSpawnEvent
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener

object MyRuinGuard : Listener {
    @EventHandler
    fun onPreSpawn(e: RuinPreSpawnEvent) {
        // No ruins allowed within 200 blocks of spawn
        val spawn = e.location.world?.spawnLocation ?: return
        if (e.location.distanceSquared(spawn) < 200.0 * 200.0) {
            e.isCancelled = true
        }
    }
}

Java: rewrite loot

java
@EventHandler
public void onLoot(RuinLootEvent e) {
    // Tower ruins get an extra diamond
    if (e.getAnchorId().startsWith("ancient_tower")) {
        e.getItems().add(new ItemStack(Material.DIAMOND, 1));
    }
    // Filter out dangerous drops in the noob protection area
    if (isNoob(e.getPlayer())) {
        e.getItems().removeIf(it -> it.getType() == Material.TNT);
    }
}

Java: register a protection region after spawn

java
@EventHandler
public void onSpawn(RuinSpawnEvent e) {
    Location min = e.minPoint();
    Location max = e.maxPoint();
    myProtectionPlugin.protect(e.getAnchorId(), min, max);
}

6. Registering listeners

java
Bukkit.getPluginManager().registerEvents(new MyListener(), myPlugin);
kotlin
server.pluginManager.registerEvents(MyRuinGuard, myPlugin)

All events provide a static getHandlerList(), conforming to the Bukkit event spec.


Next

  • QinhRuinsAPI — programmatically generate / query ruins
  • Affix Scripts — run JS when a realm activates (another extension point beyond events)