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
| Event | When | Cancellable | Use |
|---|---|---|---|
RuinPreSpawnEvent | After site selection, before pasting the structure | ✅ | Intercept generation at a place / for a template |
RuinSpawnEvent | After the anchor is generated | ❌ | Notify, register, external integration |
RuinClearEvent | When a ruin is cleared | ❌ | Give rewards, broadcast, record |
RuinLootEvent | Before dispatching container loot | ✅ | Modify / intercept loot |
Cancellation (
setCancelled(true)) only works on cancellable events.RuinSpawnEvent/RuinClearEventare notification-type (theEventhas noCancellable) 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.
class RuinPreSpawnEvent(
val templateId: String, // The template about to be generated
val location: Location, // The chosen spawn point (cloned)
) : Event(), CancellableisCancelled()/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.
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.
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).
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:
addtoitems. - To filter / replace: modify the elements of
itemsorremoveIf. - To intercept the whole batch:
setCancelled(true).
For loot tables and growth scaling see Loot System.
5. Listener examples
Kotlin: intercept generation by region
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
@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
@EventHandler
public void onSpawn(RuinSpawnEvent e) {
Location min = e.minPoint();
Location max = e.maxPoint();
myProtectionPlugin.protect(e.getAnchorId(), min, max);
}6. Registering listeners
Bukkit.getPluginManager().registerEvents(new MyListener(), myPlugin);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)