← Roadmap

EffectiveZone

Zones

Why

Spawn, arena, team base, marketplace — all are "an area where something happens on enter/exit". In Bukkit that is manual coordinate checks on every PlayerMoveEvent plus your own storage of borders.

EffectiveZone is a kind of area. Concrete regions (boxes by two corners) are selected in-game, stored in the world, and as entities move the framework fires regular Bukkit enter, exit and inside events.

Minimal example

Zone and events
object ArenaZone : EffectiveZone() {
    override fun getNamespacedData() = MyPlugin.instance to "arena"
    override fun doRememberOwner() = false
    override fun getZoneColor() = Color.RED

    fun init() {
        MyPlugin.instance.event<EffectiveZoneEnterEvent> {
            if (it.zone !== this@ArenaZone) return@event
            it.entity.sendMessage(Component.text("Arena"))
        }
    }
}
Working with regions
val box = EffectiveZone.registerSelection(
    Triple(EffectiveBlockPos(0, 60, 0), EffectiveBlockPos(20, 80, 20), world.uid),
    ArenaZone.getNamespacedName(),
)

box.isInside(player.location)
box.getEntitiesInside()
EffectiveZone.deleteZoneBoxById(box.id)

In-game /ezone does the same: take ZONE_SELECTOR, click two corners, /ezone add arena.

Events and regions

Zone events
event<EffectiveZoneEnterEvent> {
    if (it.zone !== ArenaZone) return@event
    it.entity.sendMessage(Component.text("entered box " + it.zoneBox.id))
}

event<EffectiveZoneExitEvent> { … }

event<EffectiveZoneInsideEvent> {
    if (it.zone === LavaZone && it.entity is Player) it.entity.fireTicks = 20
}

event<EffectiveZoneRegisteredEvent> {
    it.zone; it.zoneBox
}

Enter/Exit fire once on crossing the border, Inside on every move inside. All carry entity (LivingEntity), zone, zoneBox. Registered — when a new region is added in-game or from code.

ZoneBox
val boxes = EffectiveZone.getZoneBoxesByOwner(player.uniqueId)
val box = EffectiveZone.getZoneBoxById(3) ?: return

box.isInside(location)
box.getCenter()
box.getBlocksInside().filter { it.material == Material.CHEST }
box.getEntitiesInside().filterIsInstance<Player>()

EffectiveZone.deleteZoneBoxById(box.id)

A region stores id, two corners, the world and (if doRememberOwner) the owner. getBlocksInside returns EffectiveBlockData (x, y, z, material) without touching chunks.

What to override

  • getNamespacedData() *
    Plugin and zone id
  • doRememberOwner() *
    Remember who created a region
  • getZoneColor() *
    Border particle colour

* required

Pitfalls

  • Events fire for all zones at once — compare it.zone with yours in the handler.
  • EffectiveZoneInsideEvent fires on every move inside — keep it light.
  • getBlocksInside relies on the internal world block cache (EffectiveWorld), which has known bugs — the result may lag behind the real world. Verify with world.getBlockAt when precision matters.
  • Regions live in the world PDC: delete the world folder and the regions are gone.