summaryrefslogtreewikicommitdiff
path: root/bukkit/src/event
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2026-03-26 23:15:33 -0400
committerFreya Murphy <freya@freyacat.org>2026-03-27 23:09:23 -0400
commitf8322cd21cde68a72b05efbad3a05b8e67c0bdd0 (patch)
treed7e60bc8fedadc8fa7ae725571cad1f398eaf6dc /bukkit/src/event
downloadkenshinshideandseek2-f8322cd21cde68a72b05efbad3a05b8e67c0bdd0.tar.gz
kenshinshideandseek2-f8322cd21cde68a72b05efbad3a05b8e67c0bdd0.tar.bz2
kenshinshideandseek2-f8322cd21cde68a72b05efbad3a05b8e67c0bdd0.zip
initial
Diffstat (limited to 'bukkit/src/event')
-rw-r--r--bukkit/src/event/BreakListener.kt56
-rw-r--r--bukkit/src/event/ChatListener.kt29
-rw-r--r--bukkit/src/event/CommandListener.kt29
-rw-r--r--bukkit/src/event/DamageListener.kt56
-rw-r--r--bukkit/src/event/InteractListener.kt50
-rw-r--r--bukkit/src/event/InventoryListener.kt61
-rw-r--r--bukkit/src/event/JoinLeaveListener.kt52
-rw-r--r--bukkit/src/event/MovementListener.kt71
-rw-r--r--bukkit/src/event/PacketListener.kt110
-rw-r--r--bukkit/src/event/PlayerListener.kt59
-rw-r--r--bukkit/src/event/RespawnListener.kt41
11 files changed, 614 insertions, 0 deletions
diff --git a/bukkit/src/event/BreakListener.kt b/bukkit/src/event/BreakListener.kt
new file mode 100644
index 0000000..832aa72
--- /dev/null
+++ b/bukkit/src/event/BreakListener.kt
@@ -0,0 +1,56 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.BreakEvent
+import cat.freya.khs.event.onBreak
+import org.bukkit.entity.Player as BukkitPlayer
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.BlockBreakEvent
+import org.bukkit.event.entity.EntityBreakDoorEvent
+import org.bukkit.event.hanging.HangingBreakByEntityEvent
+
+class BreakListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onBlockBreak(event: BlockBreakEvent) {
+ val bukkitPlayer = event.player ?: return
+ val block = event.block?.type?.name ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = BreakEvent(plugin.khs, khsPlayer, block)
+ onBreak(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onEntityBreakDoor(event: EntityBreakDoorEvent) {
+ val bukkitPlayer = event.entity as? BukkitPlayer ?: return
+ val block = event.block?.type?.name ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = BreakEvent(plugin.khs, khsPlayer, block)
+ onBreak(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onHangingBreakByEntity(event: HangingBreakByEntityEvent) {
+ val bukkitPlayer = event.remover as? BukkitPlayer ?: return
+ val block = event.entity?.type?.name ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = BreakEvent(plugin.khs, khsPlayer, block)
+ onBreak(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+}
diff --git a/bukkit/src/event/ChatListener.kt b/bukkit/src/event/ChatListener.kt
new file mode 100644
index 0000000..530fa25
--- /dev/null
+++ b/bukkit/src/event/ChatListener.kt
@@ -0,0 +1,29 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.ChatEvent
+import cat.freya.khs.event.onChat
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.AsyncPlayerChatEvent
+
+class ChatListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ fun onChat(event: AsyncPlayerChatEvent) {
+ val bukkitPlayer = event.player ?: return
+ val message = event.message ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = ChatEvent(plugin.khs, khsPlayer, message)
+ onChat(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+}
diff --git a/bukkit/src/event/CommandListener.kt b/bukkit/src/event/CommandListener.kt
new file mode 100644
index 0000000..7ed25ca
--- /dev/null
+++ b/bukkit/src/event/CommandListener.kt
@@ -0,0 +1,29 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.CommandEvent
+import cat.freya.khs.event.onCommand
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerCommandPreprocessEvent
+
+class CommandListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerCommand(event: PlayerCommandPreprocessEvent) {
+ val bukkitPlayer = event.player ?: return
+ val message = event.message ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = CommandEvent(plugin.khs, khsPlayer, message)
+ onCommand(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+}
diff --git a/bukkit/src/event/DamageListener.kt b/bukkit/src/event/DamageListener.kt
new file mode 100644
index 0000000..81d5d12
--- /dev/null
+++ b/bukkit/src/event/DamageListener.kt
@@ -0,0 +1,56 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.DamageEvent
+import cat.freya.khs.event.onDamage
+import org.bukkit.entity.Player as BukkitPlayer
+import org.bukkit.entity.Projectile
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.EntityDamageEvent
+
+class DamageListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onEntityDamageByEntity(event: EntityDamageByEntityEvent) {
+ val bukkitPlayer = (event.entity as? BukkitPlayer) ?: return
+
+ // get attacker
+ val damager = event.damager
+ val attackerEntity: BukkitPlayer? =
+ when {
+ damager is Projectile -> damager.shooter as? BukkitPlayer
+ else -> damager as? BukkitPlayer
+ }
+
+ if (attackerEntity == null) {
+ onEntityDamage(event)
+ return
+ }
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsAttacker = BukkitKhsPlayer(plugin.shim, attackerEntity)
+ val khsEvent = DamageEvent(plugin.khs, khsPlayer, khsAttacker, event.damage)
+ onDamage(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+
+ @EventHandler(priority = EventPriority.HIGH)
+ fun onEntityDamage(event: EntityDamageEvent) {
+ val bukkitPlayer = (event.entity as? BukkitPlayer) ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = DamageEvent(plugin.khs, khsPlayer, null, event.damage)
+ onDamage(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+}
diff --git a/bukkit/src/event/InteractListener.kt b/bukkit/src/event/InteractListener.kt
new file mode 100644
index 0000000..cc9b2a7
--- /dev/null
+++ b/bukkit/src/event/InteractListener.kt
@@ -0,0 +1,50 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.bukkit.toKhsItem
+import cat.freya.khs.event.InteractEvent
+import cat.freya.khs.event.UseEvent
+import cat.freya.khs.event.onInteract
+import cat.freya.khs.event.onUse
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.block.Action
+import org.bukkit.event.player.PlayerInteractEvent
+
+class InteractListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerInteract(event: PlayerInteractEvent) {
+ val bukkitPlayer = event.player ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+
+ val block = event.clickedBlock?.type?.name
+ if (event.action == Action.RIGHT_CLICK_BLOCK && block != null) {
+ val khsEvent = InteractEvent(plugin.khs, khsPlayer, block)
+ onInteract(khsEvent)
+
+ if (khsEvent.cancelled) {
+ event.setCancelled(true)
+ return
+ }
+ }
+
+ val item = toKhsItem(event.item)
+ if (item != null) {
+ val khsEvent = UseEvent(plugin.khs, khsPlayer, item)
+ onUse(khsEvent)
+
+ if (khsEvent.cancelled) {
+ event.setCancelled(true)
+ return
+ }
+ }
+ }
+}
diff --git a/bukkit/src/event/InventoryListener.kt b/bukkit/src/event/InventoryListener.kt
new file mode 100644
index 0000000..4ec0a83
--- /dev/null
+++ b/bukkit/src/event/InventoryListener.kt
@@ -0,0 +1,61 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsInventory
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.bukkit.toKhsItem
+import cat.freya.khs.event.ClickEvent
+import cat.freya.khs.event.CloseEvent
+import cat.freya.khs.event.onClick
+import cat.freya.khs.event.onClose
+import org.bukkit.entity.Player as BukkitPlayer
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.inventory.InventoryClickEvent
+import org.bukkit.event.inventory.InventoryCloseEvent
+import org.bukkit.event.inventory.InventoryEvent
+import org.bukkit.inventory.Inventory
+
+class InventoryListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ private fun getInv(event: InventoryEvent): Pair<Inventory, String?> {
+ if (plugin.shim.supports(14)) {
+ var inv = event.view.topInventory
+ return inv to event.view.title
+ } else {
+ var inv = event.inventory
+ var title = inv::class.java.getMethod("getName").invoke(inv) as String
+ return inv to title
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onInventoryClick(event: InventoryClickEvent) {
+ val (inventory, title) = getInv(event)
+ val bukkitPlayer = event.whoClicked as? BukkitPlayer ?: return
+ val item = toKhsItem(event.currentItem) ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsInventory = BukkitKhsInventory(plugin.shim, inventory, title)
+ val khsEvent = ClickEvent(plugin.khs, khsPlayer, khsInventory, item)
+ onClick(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onInventoryClose(event: InventoryCloseEvent) {
+ val (inventory, title) = getInv(event)
+ val bukkitPlayer = event.player as? BukkitPlayer ?: return
+
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsInventory = BukkitKhsInventory(plugin.shim, inventory, title)
+ val khsEvent = CloseEvent(plugin.khs, khsPlayer, khsInventory)
+ onClose(khsEvent)
+ }
+}
diff --git a/bukkit/src/event/JoinLeaveListener.kt b/bukkit/src/event/JoinLeaveListener.kt
new file mode 100644
index 0000000..3bb2832
--- /dev/null
+++ b/bukkit/src/event/JoinLeaveListener.kt
@@ -0,0 +1,52 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.JoinEvent
+import cat.freya.khs.event.KickEvent
+import cat.freya.khs.event.LeaveEvent
+import cat.freya.khs.event.onJoin
+import cat.freya.khs.event.onKick
+import cat.freya.khs.event.onLeave
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+import org.bukkit.event.player.PlayerKickEvent
+import org.bukkit.event.player.PlayerQuitEvent
+
+class JoinLeaveListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerJoin(event: PlayerJoinEvent) {
+ val bukkitPlayer = event.player ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = JoinEvent(plugin.khs, khsPlayer)
+ onJoin(khsEvent)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerQuit(event: PlayerQuitEvent) {
+ val bukkitPlayer = event.player ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = LeaveEvent(plugin.khs, khsPlayer)
+ onLeave(khsEvent)
+
+ // remove player from disguiser
+ plugin.entityHider.removePlayer(bukkitPlayer)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerKick(event: PlayerKickEvent) {
+ val bukkitPlayer = event.player ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = KickEvent(plugin.khs, khsPlayer, event.reason ?: "")
+ onKick(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+}
diff --git a/bukkit/src/event/MovementListener.kt b/bukkit/src/event/MovementListener.kt
new file mode 100644
index 0000000..9b80415
--- /dev/null
+++ b/bukkit/src/event/MovementListener.kt
@@ -0,0 +1,71 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.JumpEvent
+import cat.freya.khs.event.MoveEvent
+import cat.freya.khs.event.onJump
+import cat.freya.khs.event.onMove
+import cat.freya.khs.world.Position as KhsPosition
+import java.util.UUID
+import java.util.concurrent.ConcurrentHashMap
+import org.bukkit.Material
+import org.bukkit.entity.Player as BukkitPlayer
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerMoveEvent
+
+class MovementListener(val plugin: KhsPlugin) : Listener {
+
+ private val prevPlayersOnGround: MutableSet<UUID> = ConcurrentHashMap.newKeySet<UUID>()
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ private fun isOnGround(player: BukkitPlayer): Boolean {
+ if (plugin.shim.supports(16, 1)) {
+ val below = player.location.clone().subtract(0.0, 0.1, 0.0).block
+ return below.type.isSolid
+ } else {
+ @Suppress("DEPRECATION")
+ return player.isOnGround()
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerMove(event: PlayerMoveEvent) {
+ val bukkitPlayer = event.player ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+
+ // check jumping
+ if (bukkitPlayer.velocity.y > 0.0) {
+ val block = bukkitPlayer.location?.block?.type
+ if (
+ block != Material.LADDER &&
+ prevPlayersOnGround.contains(bukkitPlayer.uniqueId) &&
+ isOnGround(bukkitPlayer)
+ ) {
+ // trigger jump event
+ val khsEvent = JumpEvent(plugin.khs, khsPlayer)
+ onJump(khsEvent)
+ }
+ // update set
+ if (isOnGround(bukkitPlayer)) prevPlayersOnGround.add(bukkitPlayer.uniqueId)
+ else prevPlayersOnGround.remove(bukkitPlayer.uniqueId)
+ }
+
+ val to = event.to?.let { KhsPosition(it.x, it.y, it.z) } ?: return
+ val khsEvent = MoveEvent(plugin.khs, khsPlayer, to)
+ onMove(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+
+ // update disguise (if exists)
+ val disguise = plugin.disguiser.getDisguise(bukkitPlayer) ?: return
+ val dest = event.to ?: return
+ if (!khsEvent.cancelled && event.from.distance(dest) > 0.1) disguise.shouldBeSolid = false
+ disguise.startSolidifying()
+ }
+}
diff --git a/bukkit/src/event/PacketListener.kt b/bukkit/src/event/PacketListener.kt
new file mode 100644
index 0000000..d49af60
--- /dev/null
+++ b/bukkit/src/event/PacketListener.kt
@@ -0,0 +1,110 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.bukkit.disguise.Disguise
+import cat.freya.khs.event.DamageEvent
+import cat.freya.khs.event.onDamage
+import com.github.retrooper.packetevents.PacketEvents
+import com.github.retrooper.packetevents.event.PacketListener as PacketListenerPE
+import com.github.retrooper.packetevents.event.PacketListenerPriority
+import com.github.retrooper.packetevents.event.PacketReceiveEvent
+import com.github.retrooper.packetevents.event.PacketSendEvent
+import com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Client.INTERACT_ENTITY
+import com.github.retrooper.packetevents.protocol.packettype.PacketType.Play.Server.*
+import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity
+import com.github.retrooper.packetevents.wrapper.play.server.*
+import java.util.UUID
+import org.bukkit.GameMode
+import org.bukkit.attribute.Attribute
+import org.bukkit.entity.Player as BukkitPlayer
+
+class PacketListener(val plugin: KhsPlugin) : PacketListenerPE {
+ private val debounce = mutableSetOf<UUID>()
+
+ init {
+ PacketEvents.getAPI().eventManager.registerListener(this, PacketListenerPriority.NORMAL)
+ }
+
+ // intercept entity-related packets of entities that
+ // are supposed to be hidden
+ override fun onPacketSend(event: PacketSendEvent) {
+ val player = event.getPlayer() as? BukkitPlayer ?: return
+ val entityId =
+ when (event.packetType) {
+ ENTITY_EQUIPMENT -> WrapperPlayServerEntityEquipment(event).entityId
+ ENTITY_ANIMATION -> WrapperPlayServerEntityAnimation(event).entityId
+ SPAWN_ENTITY -> WrapperPlayServerSpawnEntity(event).entityId
+ ENTITY_VELOCITY -> WrapperPlayServerEntityVelocity(event).entityId
+ ENTITY_HEAD_LOOK -> WrapperPlayServerEntityHeadLook(event).entityId
+ ENTITY_TELEPORT -> WrapperPlayServerEntityTeleport(event).entityId
+ ENTITY_STATUS -> WrapperPlayServerEntityStatus(event).entityId
+ ENTITY_METADATA -> WrapperPlayServerEntityMetadata(event).entityId
+ ENTITY_EFFECT -> WrapperPlayServerEntityEffect(event).entityId
+ REMOVE_ENTITY_EFFECT -> WrapperPlayServerRemoveEntityEffect(event).entityId
+ else -> return
+ }
+
+ if (!plugin.entityHider.isVisible(player, entityId)) {
+ event.setCancelled(true)
+ }
+ }
+
+ // check when a player is trying to attack a disguise
+ override fun onPacketReceive(event: PacketReceiveEvent) {
+ val player = event.getPlayer() as? BukkitPlayer ?: return
+
+ // we want interact event
+ if (event.packetType != INTERACT_ENTITY) return
+
+ val packet = WrapperPlayClientInteractEntity(event)
+
+ // attacking only
+ val action = packet.action ?: return
+ if (action != WrapperPlayClientInteractEntity.InteractAction.ATTACK) return
+
+ val disguise =
+ plugin.disguiser.getByEntityId(packet.entityId)
+ ?: plugin.disguiser.getByHitboxId(packet.entityId)
+ ?: return
+
+ if (disguise.player.gameMode == GameMode.CREATIVE) return
+
+ event.setCancelled(true)
+ handleAttack(disguise, player)
+ }
+
+ private fun handleAttack(disguise: Disguise, seeker: BukkitPlayer) {
+ if (disguise.player.uniqueId == seeker.uniqueId) return
+
+ val fallbackAmount = 7.0
+ val amount =
+ if (plugin.shim.supports(9)) {
+ val attribName =
+ if (plugin.shim.supports(21)) "ATTACK_DAMAGE" else "GENERIC_ATTACK_DAMAGE"
+ val attrib = Attribute.valueOf(attribName)
+ seeker.getAttribute(attrib)?.value ?: fallbackAmount
+ } else {
+ fallbackAmount // uhhh i dunno how to do this for 1.8
+ }
+
+ val debounceUUID = disguise.player.uniqueId
+
+ disguise.shouldBeSolid = false
+ if (debounce.contains(debounceUUID)) return
+
+ // trigger an attack event
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, disguise.player)
+ val khsSeeker = BukkitKhsPlayer(plugin.shim, seeker)
+ val khsEvent = DamageEvent(plugin.khs, khsPlayer, khsSeeker, amount)
+ onDamage(khsEvent)
+
+ // set and soon turn off debounce
+ debounce.add(debounceUUID)
+ plugin.server.scheduler.scheduleSyncDelayedTask(
+ plugin,
+ { debounce.remove(debounceUUID) },
+ 10,
+ )
+ }
+}
diff --git a/bukkit/src/event/PlayerListener.kt b/bukkit/src/event/PlayerListener.kt
new file mode 100644
index 0000000..23b0a91
--- /dev/null
+++ b/bukkit/src/event/PlayerListener.kt
@@ -0,0 +1,59 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.bukkit.toKhsItem
+import cat.freya.khs.event.DropEvent
+import cat.freya.khs.event.HungerEvent
+import cat.freya.khs.event.RegenEvent
+import cat.freya.khs.event.onDrop
+import cat.freya.khs.event.onHunger
+import cat.freya.khs.event.onRegen
+import org.bukkit.entity.Player as BukkitPlayer
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityRegainHealthEvent
+import org.bukkit.event.entity.FoodLevelChangeEvent
+import org.bukkit.event.player.PlayerDropItemEvent
+
+class PlayerListener(val plugin: KhsPlugin) : Listener {
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onFoodLevelChange(event: FoodLevelChangeEvent) {
+ val bukkitPlayer = event.entity as? BukkitPlayer ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = HungerEvent(plugin.khs, khsPlayer)
+ onHunger(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onEntityRegainHealth(event: EntityRegainHealthEvent) {
+ val bukkitPlayer = event.entity as? BukkitPlayer ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val natural =
+ event.regainReason == EntityRegainHealthEvent.RegainReason.SATIATED ||
+ event.regainReason == EntityRegainHealthEvent.RegainReason.REGEN
+ val khsEvent = RegenEvent(plugin.khs, khsPlayer, natural)
+ onRegen(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerDropItem(event: PlayerDropItemEvent) {
+ val bukkitPlayer = event.player ?: return
+ val item = toKhsItem(event.itemDrop?.itemStack) ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = DropEvent(plugin.khs, khsPlayer, item)
+ onDrop(khsEvent)
+
+ if (khsEvent.cancelled) event.setCancelled(true)
+ }
+}
diff --git a/bukkit/src/event/RespawnListener.kt b/bukkit/src/event/RespawnListener.kt
new file mode 100644
index 0000000..a2b4bc5
--- /dev/null
+++ b/bukkit/src/event/RespawnListener.kt
@@ -0,0 +1,41 @@
+package cat.freya.khs.bukkit.event
+
+import cat.freya.khs.bukkit.BukkitKhsPlayer
+import cat.freya.khs.bukkit.KhsPlugin
+import cat.freya.khs.event.DeathEvent
+import cat.freya.khs.event.onDeath
+import cat.freya.khs.world.Location
+import java.util.UUID
+import java.util.concurrent.ConcurrentHashMap
+import org.bukkit.event.EventHandler
+import org.bukkit.event.EventPriority
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.PlayerDeathEvent
+import org.bukkit.event.player.PlayerRespawnEvent
+
+class RespawnListener(val plugin: KhsPlugin) : Listener {
+
+ private val respawnLocation: MutableMap<UUID, Location> = ConcurrentHashMap<UUID, Location>()
+
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerDeath(event: PlayerDeathEvent) {
+ val bukkitPlayer = event.entity ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val khsEvent = DeathEvent(plugin.khs, khsPlayer)
+ onDeath(khsEvent)
+
+ if (khsEvent.cancelled) respawnLocation[khsPlayer.uuid] = khsPlayer.location
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ fun onPlayerRespawn(event: PlayerRespawnEvent) {
+ val bukkitPlayer = event.player ?: return
+ val khsPlayer = BukkitKhsPlayer(plugin.shim, bukkitPlayer)
+ val location = respawnLocation.remove(khsPlayer.uuid) ?: return
+ khsPlayer.teleport(location)
+ }
+}