feat: Add onToggleSneak event to CustomComponent and refactor GliderComponent activation to use it with a global ticker.
This commit is contained in:
parent
ee4ac4467e
commit
d4e84fea1b
|
|
@ -17,4 +17,5 @@ interface CustomComponent {
|
||||||
fun onInteract(event: org.bukkit.event.player.PlayerInteractEvent) {}
|
fun onInteract(event: org.bukkit.event.player.PlayerInteractEvent) {}
|
||||||
fun onEntityDamage(event: org.bukkit.event.entity.EntityDamageEvent) {}
|
fun onEntityDamage(event: org.bukkit.event.entity.EntityDamageEvent) {}
|
||||||
fun onPlayerMove(event: org.bukkit.event.player.PlayerMoveEvent) {}
|
fun onPlayerMove(event: org.bukkit.event.player.PlayerMoveEvent) {}
|
||||||
|
fun onToggleSneak(player: org.bukkit.entity.Player, item: org.bukkit.inventory.ItemStack, event: org.bukkit.event.player.PlayerToggleSneakEvent) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,16 @@ import org.bukkit.block.data.Lightable
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.inventory.ItemStack
|
import org.bukkit.inventory.ItemStack
|
||||||
import org.bukkit.inventory.meta.Damageable
|
import org.bukkit.inventory.meta.Damageable
|
||||||
import org.bukkit.util.Vector
|
|
||||||
import org.bukkit.persistence.PersistentDataType
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.util.Vector
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component"), EquippableComponent {
|
class GliderComponent(private val plugin: App) : AbstractComponent(plugin, "glider_component"), EquippableComponent {
|
||||||
|
|
||||||
override val displayName: String = "Glider"
|
override val displayName: String = "Glider"
|
||||||
// Custom maxTier for Glider
|
|
||||||
override val maxTier: Int = 10
|
override val maxTier: Int = 10
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
@ -39,138 +38,134 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic Tier attributes
|
|
||||||
private fun getMaxDurability(tier: Tier): Int = (64 * 2.0.pow(tier.level - 1)).toInt()
|
|
||||||
|
|
||||||
private fun getFallSpeed(tier: Tier): Double {
|
|
||||||
// -0.08 base, getting closer to 0 by 0.015~ per level, capped at -0.01
|
|
||||||
// Simulating the map: 1->-0.08, 2->-0.065, 3->-0.05, 4->-0.04, 5->-0.03
|
|
||||||
return when (tier.level) {
|
|
||||||
1 -> -0.08
|
|
||||||
2 -> -0.065
|
|
||||||
3 -> -0.05
|
|
||||||
4 -> -0.04
|
|
||||||
5 -> -0.03
|
|
||||||
else -> (-0.03 + (tier.level - 5) * 0.005).coerceAtMost(-0.005)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getHungerInterval(tier: Tier): Int = 40 + (tier.level - 1) * 20 // 1->40, 5->120... close approximation or simplier formula
|
|
||||||
|
|
||||||
data class GliderState(
|
data class GliderState(
|
||||||
var ticksGliding: Int = 0,
|
var ticksGliding: Int = 0,
|
||||||
var lastTickTime: Long = System.currentTimeMillis()
|
var lastTickTime: Long = System.currentTimeMillis()
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun onInteract(event: org.bukkit.event.player.PlayerInteractEvent) {
|
init {
|
||||||
val player = event.player
|
// Global Ticker for active gliders
|
||||||
val item = event.item ?: return
|
plugin.server.scheduler.runTaskTimer(plugin, Runnable {
|
||||||
|
if (activeGliders.isEmpty()) return@Runnable
|
||||||
// Only handle Right Click
|
|
||||||
if (event.action != org.bukkit.event.block.Action.RIGHT_CLICK_AIR && event.action != org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK) return
|
|
||||||
|
|
||||||
val tier = getTier(item) ?: Tier.ONE
|
|
||||||
|
|
||||||
if (!canDeploy(player)) {
|
|
||||||
player.sendActionBar(Component.text("✗ ", NamedTextColor.RED).append(Component.text("空中にいる必要があります!", NamedTextColor.YELLOW)))
|
|
||||||
player.playSound(player.location, Sound.ENTITY_VILLAGER_NO, 0.5f, 1.0f)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBroken(item)) {
|
|
||||||
player.sendActionBar(Component.text("⚠ ", NamedTextColor.RED).append(Component.text("グライダーが壊れています!", NamedTextColor.YELLOW)))
|
|
||||||
player.playSound(player.location, Sound.ENTITY_ITEM_BREAK, 0.5f, 0.8f)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val isEnabled = isGliderEnabled(item)
|
|
||||||
|
|
||||||
if (isEnabled) {
|
|
||||||
disableGlider(player, item)
|
|
||||||
player.sendActionBar(Component.text("⬇ ", NamedTextColor.GRAY).append(Component.text("グライダー収納", NamedTextColor.YELLOW)))
|
|
||||||
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 0.8f, 0.8f)
|
|
||||||
} else {
|
|
||||||
enableGlider(player, item)
|
|
||||||
player.sendActionBar(Component.text("⬆ ", NamedTextColor.GREEN).append(Component.text("グライダー展開!", NamedTextColor.AQUA)).append(Component.text(" [Tier ${tier.level}]", tier.color)))
|
|
||||||
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 1.0f, 1.2f)
|
|
||||||
}
|
|
||||||
// event.isCancelled = true // Maybe? GliderItem did it.
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPlayerMove(event: org.bukkit.event.player.PlayerMoveEvent) {
|
|
||||||
val player = event.player
|
|
||||||
val item = player.inventory.itemInMainHand
|
|
||||||
|
|
||||||
// Safety check if method called correctly
|
|
||||||
if (!has(item)) return
|
|
||||||
if (!isGliderEnabled(item)) return
|
|
||||||
|
|
||||||
if (isFlyingBlocked(player)) {
|
|
||||||
disableGlider(player, item, silent = true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEntityDamage(event: org.bukkit.event.entity.EntityDamageEvent) {
|
|
||||||
if (event.cause == org.bukkit.event.entity.EntityDamageEvent.DamageCause.FALL) {
|
|
||||||
val entity = event.entity
|
|
||||||
if (entity is Player && activeGliders.containsKey(entity.uniqueId)) {
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTick(player: Player, item: ItemStack) {
|
|
||||||
if (activeGliders.containsKey(player.uniqueId)) {
|
|
||||||
val state = activeGliders[player.uniqueId]!!
|
|
||||||
// Try to get Tier from Component, fallback to Tier.ONE
|
|
||||||
val tier = getTier(item) ?: Tier.ONE
|
|
||||||
|
|
||||||
if (isFlyingBlocked(player)) {
|
|
||||||
disableGlider(player, item, silent = true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
state.ticksGliding++
|
|
||||||
player.fallDistance = 0f
|
|
||||||
|
|
||||||
if (checkAndApplyUpdraft(player)) {
|
|
||||||
spawnUpdraftParticles(player)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
applyGlidingPhysics(player, tier)
|
|
||||||
|
|
||||||
if (state.ticksGliding % 5 == 0) spawnGlidingParticles(player)
|
|
||||||
if (state.ticksGliding % 10 == 0) updateGliderActionBar(player, item, tier, state)
|
|
||||||
|
|
||||||
val hungerInterval = getHungerInterval(tier)
|
// Validate and Tick
|
||||||
if (state.ticksGliding % hungerInterval == 0) consumeHunger(player)
|
val iterator = activeGliders.iterator()
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val entry = iterator.next()
|
||||||
|
val uuid = entry.key
|
||||||
|
val state = entry.value
|
||||||
|
val player = plugin.server.getPlayer(uuid)
|
||||||
|
|
||||||
if (state.ticksGliding % DURABILITY_TICK_INTERVAL == 0) consumeDurability(player, item, tier)
|
if (player == null) {
|
||||||
} else {
|
iterator.remove()
|
||||||
// Activation Logic for Equippable (Sneak + Jump/Drop)
|
continue
|
||||||
if (player.isSneaking && canDeploy(player)) {
|
}
|
||||||
enableGlider(player, item)
|
|
||||||
|
val item = findGliderItem(player)
|
||||||
|
|
||||||
|
// Validation: Must have item equipped, not be grounded/blocked
|
||||||
|
if (item == null) {
|
||||||
|
disableGliderMemoryOnly(player) // Removed without item reference
|
||||||
|
iterator.remove() // Remove from map
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFlyingBlocked(player)) {
|
||||||
|
disableGlider(player, item, silent = true)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physics and Logic
|
||||||
|
tickGliderPhysics(player, item, state)
|
||||||
|
}
|
||||||
|
}, 1L, 1L)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(item: ItemStack, tier: Tier?) {
|
||||||
|
if (isEquipment(item.type)) {
|
||||||
|
super.apply(item, tier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onToggleSneak(player: Player, item: ItemStack, event: org.bukkit.event.player.PlayerToggleSneakEvent) {
|
||||||
|
// Only trigger when STARTING to sneak
|
||||||
|
if (event.isSneaking) {
|
||||||
|
if (activeGliders.containsKey(player.uniqueId)) {
|
||||||
|
// If already gliding, stow it
|
||||||
|
disableGlider(player, item)
|
||||||
|
} else {
|
||||||
|
// If not gliding, verify conditions to deploy
|
||||||
|
if (canDeploy(player) && !isBroken(item)) {
|
||||||
|
enableGlider(player, item)
|
||||||
|
} else if (isBroken(item)) {
|
||||||
|
player.sendActionBar(Component.text("⚠ ", NamedTextColor.RED).append(Component.text("グライダーが壊れています!", NamedTextColor.YELLOW)))
|
||||||
|
player.playSound(player.location, Sound.ENTITY_ITEM_BREAK, 0.5f, 0.8f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableGlider(player: Player, item: ItemStack, silent: Boolean = false) {
|
// Logic handled in global ticker now, but required by interface
|
||||||
|
override fun onTick(player: Player, item: ItemStack) {}
|
||||||
|
|
||||||
|
// Only allow attaching to equipment types
|
||||||
|
private fun isEquipment(material: Material): Boolean {
|
||||||
|
val name = material.name
|
||||||
|
return name.endsWith("_HELMET") || name.endsWith("_CHESTPLATE") ||
|
||||||
|
name.endsWith("_LEGGINGS") || name.endsWith("_BOOTS") ||
|
||||||
|
material == Material.ELYTRA || material == Material.SHIELD ||
|
||||||
|
material == Material.CARVED_PUMPKIN || material == Material.TURTLE_HELMET
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the itemStack that has this component in user's equipment
|
||||||
|
private fun findGliderItem(player: Player): ItemStack? {
|
||||||
|
val equipment = player.equipment ?: return null
|
||||||
|
val candidates = mutableListOf<ItemStack>()
|
||||||
|
candidates.addAll(equipment.armorContents.filterNotNull())
|
||||||
|
candidates.add(equipment.itemInMainHand)
|
||||||
|
candidates.add(equipment.itemInOffHand)
|
||||||
|
|
||||||
|
return candidates.find { has(it) && isGliderEnabled(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tickGliderPhysics(player: Player, item: ItemStack, state: GliderState) {
|
||||||
|
val tier = getTier(item) ?: Tier.ONE
|
||||||
|
|
||||||
|
state.ticksGliding++
|
||||||
|
player.fallDistance = 0f
|
||||||
|
|
||||||
|
// Updraft
|
||||||
|
if (checkAndApplyUpdraft(player)) {
|
||||||
|
spawnUpdraftParticles(player)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physics
|
||||||
|
applyGlidingPhysics(player, tier)
|
||||||
|
|
||||||
|
// Effects
|
||||||
|
if (state.ticksGliding % 5 == 0) spawnGlidingParticles(player)
|
||||||
|
if (state.ticksGliding % 10 == 0) updateGliderActionBar(player, item, tier)
|
||||||
|
|
||||||
|
// Hunger
|
||||||
|
val hungerInterval = getHungerInterval(tier)
|
||||||
|
if (state.ticksGliding % hungerInterval == 0) consumeHunger(player)
|
||||||
|
|
||||||
|
// Durability
|
||||||
|
if (state.ticksGliding % DURABILITY_TICK_INTERVAL == 0) consumeDurability(player, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enableGlider(player: Player, item: ItemStack) {
|
||||||
val meta = item.itemMeta ?: return
|
val meta = item.itemMeta ?: return
|
||||||
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, true)
|
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, true)
|
||||||
item.itemMeta = meta
|
item.itemMeta = meta
|
||||||
|
|
||||||
// Memory update
|
|
||||||
if (!activeGliders.containsKey(player.uniqueId)) {
|
if (!activeGliders.containsKey(player.uniqueId)) {
|
||||||
val tier = getTier(item) ?: Tier.ONE
|
val tier = getTier(item) ?: Tier.ONE
|
||||||
activeGliders[player.uniqueId] = GliderState()
|
activeGliders[player.uniqueId] = GliderState()
|
||||||
|
|
||||||
// Visuals
|
player.sendActionBar(Component.text("⬆ ", NamedTextColor.GREEN).append(Component.text("グライダー展開!", NamedTextColor.AQUA)).append(Component.text(" [Tier ${tier.level}]", tier.color)))
|
||||||
if (!silent) {
|
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 1.0f, 1.2f)
|
||||||
player.sendActionBar(Component.text("⬆ ", NamedTextColor.GREEN).append(Component.text("グライダー展開!", NamedTextColor.AQUA)).append(Component.text(" [Tier ${tier.level}]", tier.color)))
|
|
||||||
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 1.0f, 1.2f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,11 +174,9 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, false)
|
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, false)
|
||||||
item.itemMeta = meta
|
item.itemMeta = meta
|
||||||
|
|
||||||
// Memory update
|
|
||||||
if (activeGliders.containsKey(player.uniqueId)) {
|
if (activeGliders.containsKey(player.uniqueId)) {
|
||||||
activeGliders.remove(player.uniqueId)
|
activeGliders.remove(player.uniqueId)
|
||||||
|
|
||||||
// Visuals
|
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
player.sendActionBar(Component.text("⬇ ", NamedTextColor.GRAY).append(Component.text("グライダー収納", NamedTextColor.YELLOW)))
|
player.sendActionBar(Component.text("⬇ ", NamedTextColor.GRAY).append(Component.text("グライダー収納", NamedTextColor.YELLOW)))
|
||||||
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 0.8f, 0.8f)
|
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 0.8f, 0.8f)
|
||||||
|
|
@ -191,13 +184,14 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if item has 'enabled' state in PDC
|
private fun disableGliderMemoryOnly(player: Player) {
|
||||||
private fun isGliderEnabled(item: ItemStack): Boolean {
|
if (activeGliders.containsKey(player.uniqueId)) {
|
||||||
if (item.type.isAir) return false
|
player.sendActionBar(Component.text("⬇ ", NamedTextColor.GRAY).append(Component.text("グライダー収納 (装備解除)", NamedTextColor.YELLOW)))
|
||||||
val meta = item.itemMeta ?: return false
|
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 0.8f, 0.8f)
|
||||||
return meta.persistentDataContainer.get(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN) ?: false
|
// Removal from map happens in caller
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canDeploy(player: Player): Boolean {
|
private fun canDeploy(player: Player): Boolean {
|
||||||
if (player.isInsideVehicle) return false
|
if (player.isInsideVehicle) return false
|
||||||
val loc = player.location
|
val loc = player.location
|
||||||
|
|
@ -206,41 +200,17 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
val isInAir = !player.isOnGround && belowOne.type.isAir && belowTwo.type.isAir
|
val isInAir = !player.isOnGround && belowOne.type.isAir && belowTwo.type.isAir
|
||||||
val isFalling = player.fallDistance > 1.5
|
val isFalling = player.fallDistance > 1.0
|
||||||
|
|
||||||
return isInAir || isFalling
|
return isInAir || isFalling
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isBroken(item: ItemStack): Boolean {
|
|
||||||
// Simple check: is it broken based on our custom max durability?
|
|
||||||
// Actually for now false is safe default if we don't strictly track custom durability item destruction
|
|
||||||
// Users might want custom durability handling -> consuming durability updates the item damage.
|
|
||||||
// If item is fully damaged (vanilla), it might break.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private fun isFlyingBlocked(player: Player): Boolean {
|
private fun isFlyingBlocked(player: Player): Boolean {
|
||||||
return player.isOnGround || player.isInWater || player.isSwimming || (player.isGliding && !activeGliders.containsKey(player.uniqueId))
|
return player.isOnGround || player.isInWater || player.isSwimming || (player.isGliding && !activeGliders.containsKey(player.uniqueId))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAndApplyUpdraft(player: Player): Boolean {
|
// Physics Helpers
|
||||||
val location = player.location
|
|
||||||
for (y in 0 until 10) {
|
|
||||||
val checkLoc = location.clone().subtract(0.0, y.toDouble(), 0.0)
|
|
||||||
val block = checkLoc.block
|
|
||||||
if (UPDRAFT_BLOCKS.contains(block.type)) {
|
|
||||||
val blockData = block.blockData
|
|
||||||
if (blockData is Lightable && !blockData.isLit) continue
|
|
||||||
|
|
||||||
player.velocity = Vector(player.velocity.x, UPDRAFT_BOOST, player.velocity.z)
|
|
||||||
player.playSound(player.location, Sound.BLOCK_FIRE_AMBIENT, 0.3f, 1.5f)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyGlidingPhysics(player: Player, tier: Tier) {
|
private fun applyGlidingPhysics(player: Player, tier: Tier) {
|
||||||
val velocity = player.velocity
|
val velocity = player.velocity
|
||||||
val fallSpeed = getFallSpeed(tier)
|
val fallSpeed = getFallSpeed(tier)
|
||||||
|
|
@ -266,7 +236,6 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
horizontalDir.z * newHorizontalSpeed
|
horizontalDir.z * newHorizontalSpeed
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun spawnGlidingParticles(player: Player) {
|
private fun spawnGlidingParticles(player: Player) {
|
||||||
player.world.spawnParticle(Particle.CLOUD, player.location.add(0.0, 2.0, 0.0), 1, 0.3, 0.0, 0.3, 0.01)
|
player.world.spawnParticle(Particle.CLOUD, player.location.add(0.0, 2.0, 0.0), 1, 0.3, 0.0, 0.3, 0.01)
|
||||||
}
|
}
|
||||||
|
|
@ -275,16 +244,55 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
player.world.spawnParticle(Particle.FLAME, player.location.add(0.0, 1.0, 0.0), 5, 0.3, 0.5, 0.3, 0.02)
|
player.world.spawnParticle(Particle.FLAME, player.location.add(0.0, 1.0, 0.0), 5, 0.3, 0.5, 0.3, 0.02)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateGliderActionBar(player: Player, item: ItemStack, tier: Tier, state: GliderState) {
|
private fun checkAndApplyUpdraft(player: Player): Boolean {
|
||||||
|
val location = player.location
|
||||||
|
for (y in 0 until 10) {
|
||||||
|
val checkLoc = location.clone().subtract(0.0, y.toDouble(), 0.0)
|
||||||
|
val block = checkLoc.block
|
||||||
|
if (UPDRAFT_BLOCKS.contains(block.type)) {
|
||||||
|
val blockData = block.blockData
|
||||||
|
if (blockData is Lightable && !blockData.isLit) continue
|
||||||
|
|
||||||
|
player.velocity = Vector(player.velocity.x, UPDRAFT_BOOST, player.velocity.z)
|
||||||
|
player.playSound(player.location, Sound.BLOCK_FIRE_AMBIENT, 0.3f, 1.5f)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun consumeHunger(player: Player) {
|
||||||
|
player.exhaustion += HUNGER_EXHAUSTION
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun consumeDurability(player: Player, item: ItemStack) {
|
||||||
|
val meta = item.itemMeta ?: return
|
||||||
|
if (meta is Damageable) {
|
||||||
|
val maxDurability = item.type.maxDurability
|
||||||
|
if (maxDurability <= 0) return
|
||||||
|
|
||||||
|
val currentDamage = meta.damage
|
||||||
|
if (currentDamage >= maxDurability - 1) {
|
||||||
|
meta.damage = maxDurability.toInt()
|
||||||
|
disableGlider(player, item)
|
||||||
|
player.playSound(player.location, Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f)
|
||||||
|
} else {
|
||||||
|
meta.damage = currentDamage + 1
|
||||||
|
}
|
||||||
|
item.itemMeta = meta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateGliderActionBar(player: Player, item: ItemStack, tier: Tier) {
|
||||||
val speed = player.velocity.length() * 20
|
val speed = player.velocity.length() * 20
|
||||||
val altitude = player.location.y
|
val altitude = player.location.y
|
||||||
|
|
||||||
val meta = item.itemMeta
|
val meta = item.itemMeta
|
||||||
val durabilityText = if (meta is Damageable) {
|
val durabilityText = if (meta is Damageable) {
|
||||||
val maxDurability = getMaxDurability(tier)
|
val maxDurability = item.type.maxDurability
|
||||||
val currentDamage = meta.damage
|
val currentDamage = meta.damage
|
||||||
val remaining = maxDurability - currentDamage
|
val remaining = (maxDurability - currentDamage).coerceAtLeast(0)
|
||||||
"$remaining/$maxDurability"
|
if (maxDurability > 0) "$remaining/$maxDurability" else "∞"
|
||||||
} else {
|
} else {
|
||||||
"∞"
|
"∞"
|
||||||
}
|
}
|
||||||
|
|
@ -299,23 +307,38 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun consumeHunger(player: Player) {
|
private fun getFallSpeed(tier: Tier): Double {
|
||||||
player.exhaustion += HUNGER_EXHAUSTION
|
return when (tier.level) {
|
||||||
}
|
1 -> -0.08
|
||||||
|
2 -> -0.065
|
||||||
private fun consumeDurability(player: Player, item: ItemStack, tier: Tier) {
|
3 -> -0.05
|
||||||
val meta = item.itemMeta ?: return
|
4 -> -0.04
|
||||||
if (meta is Damageable) {
|
5 -> -0.03
|
||||||
val maxDamage = getMaxDurability(tier)
|
else -> (-0.03 + (tier.level - 5) * 0.005).coerceAtMost(-0.005)
|
||||||
val currentDamage = meta.damage
|
|
||||||
if (currentDamage >= maxDamage - 1) {
|
|
||||||
meta.damage = maxDamage
|
|
||||||
disableGlider(player, item) // Use item aware disable
|
|
||||||
player.playSound(player.location, Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f)
|
|
||||||
} else {
|
|
||||||
meta.damage = currentDamage + 1
|
|
||||||
}
|
|
||||||
item.itemMeta = meta
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getHungerInterval(tier: Tier): Int = 40 + (tier.level - 1) * 20
|
||||||
|
|
||||||
|
override fun onEntityDamage(event: org.bukkit.event.entity.EntityDamageEvent) {
|
||||||
|
if (event.cause == org.bukkit.event.entity.EntityDamageEvent.DamageCause.FALL) {
|
||||||
|
val entity = event.entity
|
||||||
|
if (entity is Player && activeGliders.containsKey(entity.uniqueId)) {
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isGliderEnabled(item: ItemStack): Boolean {
|
||||||
|
if (item.type.isAir) return false
|
||||||
|
val meta = item.itemMeta ?: return false
|
||||||
|
return meta.persistentDataContainer.get(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isBroken(item: ItemStack): Boolean {
|
||||||
|
val meta = item.itemMeta as? Damageable ?: return false
|
||||||
|
val maxDurability = item.type.maxDurability
|
||||||
|
if (maxDurability <= 0) return false
|
||||||
|
return meta.damage >= maxDurability
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,4 +119,24 @@ class EventListener(private val plugin: App) : Listener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onToggleSneak(event: org.bukkit.event.player.PlayerToggleSneakEvent) {
|
||||||
|
val player = event.player
|
||||||
|
val equipment = player.equipment ?: return
|
||||||
|
|
||||||
|
val itemsToCheck = mutableListOf<org.bukkit.inventory.ItemStack>()
|
||||||
|
itemsToCheck.addAll(equipment.armorContents.filterNotNull())
|
||||||
|
itemsToCheck.add(equipment.itemInMainHand)
|
||||||
|
itemsToCheck.add(equipment.itemInOffHand)
|
||||||
|
|
||||||
|
for (item in itemsToCheck) {
|
||||||
|
if (item.type.isAir) continue
|
||||||
|
for (component in net.hareworks.hcu.items.registry.ComponentRegistry.getAll()) {
|
||||||
|
if (component.has(item)) {
|
||||||
|
component.onToggleSneak(player, item, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user