feat: Migrate Glider item functionality to GliderComponent, enabling dynamic tier attributes and right-click deployment, and add min/max tier enforcement to SpecialItem creation.

This commit is contained in:
Kariya 2025-12-10 12:05:44 +00:00
parent 400d02d320
commit ee4ac4467e
8 changed files with 201 additions and 312 deletions

View File

@ -8,7 +8,6 @@ import net.hareworks.hcu.items.registry.ItemRegistry
import net.hareworks.hcu.items.registry.ComponentRegistry
import net.hareworks.hcu.items.content.items.TestItem
import net.hareworks.hcu.items.content.items.GrapplingItem
import net.hareworks.hcu.items.content.items.GliderItem
import net.hareworks.hcu.items.content.components.GliderComponent
import org.bukkit.permissions.PermissionDefault
@ -36,7 +35,6 @@ public class App : JavaPlugin() {
// Register items
ItemRegistry.register(TestItem())
ItemRegistry.register(GrapplingItem())
ItemRegistry.register(GliderItem())
// Register Components
val gliderComponent = GliderComponent(this)

View File

@ -6,7 +6,7 @@ import net.kyori.adventure.text.format.TextColor
data class Tier(val level: Int) {
val color: TextColor
get() = when(level) {
get() = when((level - 1) % 5 + 1) {
1 -> NamedTextColor.WHITE
2 -> NamedTextColor.GREEN
3 -> NamedTextColor.AQUA

View File

@ -14,6 +14,9 @@ abstract class AbstractComponent(
override val key: NamespacedKey = NamespacedKey(plugin, id)
protected val tierKey: NamespacedKey = NamespacedKey(plugin, "${id}_tier")
override val maxTier: Int = 5
override val minTier: Int = 1
override fun apply(item: ItemStack, tier: Tier?) {
val meta = item.itemMeta ?: return
// Mark as present
@ -21,7 +24,8 @@ abstract class AbstractComponent(
// Save Tier if provided
if (tier != null) {
meta.persistentDataContainer.set(tierKey, PersistentDataType.INTEGER, tier.level)
val validTierLevel = tier.level.coerceIn(minTier, maxTier)
meta.persistentDataContainer.set(tierKey, PersistentDataType.INTEGER, validTierLevel)
} else {
// Clean up if no tier? Or leave existing?
// Ideally if apply(null) is called, we might imply "remove tier info" or "custom component without tier".

View File

@ -7,8 +7,14 @@ import org.bukkit.inventory.ItemStack
interface CustomComponent {
val key: NamespacedKey
val displayName: String
val maxTier: Int
val minTier: Int
fun apply(item: ItemStack, tier: Tier? = null)
fun has(item: ItemStack): Boolean
fun remove(item: ItemStack)
fun onInteract(event: org.bukkit.event.player.PlayerInteractEvent) {}
fun onEntityDamage(event: org.bukkit.event.entity.EntityDamageEvent) {}
fun onPlayerMove(event: org.bukkit.event.player.PlayerMoveEvent) {}
}

View File

@ -7,12 +7,19 @@ import org.bukkit.persistence.PersistentDataType
abstract class SpecialItem(val id: String) {
open val maxTier: Int = 5
open val minTier: Int = 1
fun createItemStack(tier: Tier = Tier.ONE): ItemStack {
val item = buildItem(tier)
val validTier = if (tier.level < minTier) Tier.fromLevel(minTier)
else if (tier.level > maxTier) Tier.fromLevel(maxTier)
else tier
val item = buildItem(validTier)
val meta = item.itemMeta ?: return item
meta.persistentDataContainer.set(KEY_HCU_ITEM_ID, PersistentDataType.STRING, id)
meta.persistentDataContainer.set(KEY_HCU_ITEM_TIER, PersistentDataType.INTEGER, tier.level)
meta.persistentDataContainer.set(KEY_HCU_ITEM_TIER, PersistentDataType.INTEGER, validTier.level)
item.itemMeta = meta
return item

View File

@ -14,41 +14,112 @@ import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable
import org.bukkit.util.Vector
import org.bukkit.persistence.PersistentDataType
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.sqrt
import kotlin.math.pow
class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component"), EquippableComponent {
override val displayName: String = "Glider"
// Custom maxTier for Glider
override val maxTier: Int = 10
companion object {
val activeGliders = ConcurrentHashMap<UUID, GliderState>()
val KEY_GLIDER_ENABLED = org.bukkit.NamespacedKey("hcu_items", "glider_enabled")
private const val DURABILITY_TICK_INTERVAL = 100
private const val UPDRAFT_BOOST = 0.5
private const val HUNGER_EXHAUSTION = 0.3f
private val TIER_MAX_DURABILITY = mapOf(
Tier.ONE to 64, Tier.TWO to 128, Tier.THREE to 256, Tier.FOUR to 512, Tier.FIVE to 1024
)
private val TIER_FALL_SPEED = mapOf(
Tier.ONE to -0.08, Tier.TWO to -0.065, Tier.THREE to -0.05, Tier.FOUR to -0.04, Tier.FIVE to -0.03
)
private val TIER_HUNGER_INTERVAL = mapOf(
Tier.ONE to 40, Tier.TWO to 60, Tier.THREE to 80, Tier.FOUR to 120, Tier.FIVE to 200
)
private val UPDRAFT_BLOCKS = setOf(
Material.FIRE, Material.SOUL_FIRE, Material.CAMPFIRE, Material.SOUL_CAMPFIRE, Material.MAGMA_BLOCK, Material.LAVA
)
}
// 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(
var ticksGliding: Int = 0,
var lastTickTime: Long = System.currentTimeMillis()
)
override fun onInteract(event: org.bukkit.event.player.PlayerInteractEvent) {
val player = event.player
val item = event.item ?: return
// 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]!!
@ -56,7 +127,7 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
val tier = getTier(item) ?: Tier.ONE
if (isFlyingBlocked(player)) {
disableGlider(player)
disableGlider(player, item, silent = true)
return
}
@ -73,27 +144,58 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
if (state.ticksGliding % 5 == 0) spawnGlidingParticles(player)
if (state.ticksGliding % 10 == 0) updateGliderActionBar(player, item, tier, state)
val hungerInterval = TIER_HUNGER_INTERVAL[tier] ?: 80
val hungerInterval = getHungerInterval(tier)
if (state.ticksGliding % hungerInterval == 0) consumeHunger(player)
if (state.ticksGliding % DURABILITY_TICK_INTERVAL == 0) consumeDurability(player, item, tier)
} else {
// Activation Logic for Equippable (Sneak + Jump/Drop)
if (player.isSneaking && canDeploy(player)) {
enableGlider(player)
enableGlider(player, item)
}
}
}
fun enableGlider(player: Player) {
private fun enableGlider(player: Player, item: ItemStack, silent: Boolean = false) {
val meta = item.itemMeta ?: return
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, true)
item.itemMeta = meta
// Memory update
if (!activeGliders.containsKey(player.uniqueId)) {
val tier = getTier(item) ?: Tier.ONE
activeGliders[player.uniqueId] = GliderState()
// Visuals
if (!silent) {
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)
}
}
}
fun disableGlider(player: Player) {
private fun disableGlider(player: Player, item: ItemStack, silent: Boolean = false) {
val meta = item.itemMeta ?: return
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, false)
item.itemMeta = meta
// Memory update
if (activeGliders.containsKey(player.uniqueId)) {
activeGliders.remove(player.uniqueId)
// Visuals
if (!silent) {
player.sendActionBar(Component.text("", NamedTextColor.GRAY).append(Component.text("グライダー収納", NamedTextColor.YELLOW)))
player.playSound(player.location, Sound.ITEM_ARMOR_EQUIP_ELYTRA, 0.8f, 0.8f)
}
}
}
// Check if item has 'enabled' state in PDC
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 canDeploy(player: Player): Boolean {
@ -109,6 +211,14 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
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")
private fun isFlyingBlocked(player: Player): Boolean {
return player.isOnGround || player.isInWater || player.isSwimming || (player.isGliding && !activeGliders.containsKey(player.uniqueId))
@ -133,7 +243,7 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
private fun applyGlidingPhysics(player: Player, tier: Tier) {
val velocity = player.velocity
val fallSpeed = TIER_FALL_SPEED[tier] ?: -0.05
val fallSpeed = getFallSpeed(tier)
val direction = player.location.direction
val horizontalDir = Vector(direction.x, 0.0, direction.z)
@ -166,7 +276,27 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
}
private fun updateGliderActionBar(player: Player, item: ItemStack, tier: Tier, state: GliderState) {
player.sendActionBar(Component.text("Gliding... Speed: ${String.format("%.1f", player.velocity.length() * 20)}", NamedTextColor.AQUA))
val speed = player.velocity.length() * 20
val altitude = player.location.y
val meta = item.itemMeta
val durabilityText = if (meta is Damageable) {
val maxDurability = getMaxDurability(tier)
val currentDamage = meta.damage
val remaining = maxDurability - currentDamage
"$remaining/$maxDurability"
} else {
""
}
player.sendActionBar(
Component.text("✈ 速度: ", NamedTextColor.GRAY)
.append(Component.text(String.format("%.1f m/s", speed), NamedTextColor.AQUA))
.append(Component.text(" | 高度: ", NamedTextColor.DARK_GRAY))
.append(Component.text(String.format("%.0f", altitude), NamedTextColor.GREEN))
.append(Component.text(" | 耐久: ", NamedTextColor.DARK_GRAY))
.append(Component.text(durabilityText, NamedTextColor.WHITE))
)
}
private fun consumeHunger(player: Player) {
@ -176,11 +306,11 @@ class GliderComponent(plugin: App) : AbstractComponent(plugin, "glider_component
private fun consumeDurability(player: Player, item: ItemStack, tier: Tier) {
val meta = item.itemMeta ?: return
if (meta is Damageable) {
val maxDamage = TIER_MAX_DURABILITY[tier] ?: 64
val maxDamage = getMaxDurability(tier)
val currentDamage = meta.damage
if (currentDamage >= maxDamage - 1) {
meta.damage = maxDamage
disableGlider(player)
disableGlider(player, item) // Use item aware disable
player.playSound(player.location, Sound.ENTITY_ITEM_BREAK, 1.0f, 1.0f)
} else {
meta.damage = currentDamage + 1

View File

@ -1,267 +0,0 @@
package net.hareworks.hcu.items.content.items
import net.hareworks.hcu.items.api.Tier
import net.hareworks.hcu.items.api.item.SpecialItem
import net.hareworks.hcu.items.content.components.GliderComponent
import net.hareworks.hcu.items.registry.ComponentRegistry
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.Particle
import org.bukkit.Sound
import org.bukkit.block.data.Lightable
import org.bukkit.entity.Player
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.event.player.PlayerMoveEvent
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.Damageable
import org.bukkit.persistence.PersistentDataType
import org.bukkit.util.Vector
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.math.sqrt
// NOTE: This class logic is partially duplicated with GliderComponent during migration.
// Ideally, this item should just be a shell that applies the GliderComponent.
class GliderItem : SpecialItem("glider") {
companion object {
val activeGliders = ConcurrentHashMap<UUID, GliderState>()
val KEY_GLIDER_ENABLED = NamespacedKey("hcu_items", "glider_enabled")
private const val DURABILITY_TICK_INTERVAL = 100
private const val UPDRAFT_BOOST = 0.5
private val TIER_MAX_DURABILITY = mapOf(
Tier.ONE to 64, Tier.TWO to 128, Tier.THREE to 256, Tier.FOUR to 512, Tier.FIVE to 1024
)
private val TIER_FALL_SPEED = mapOf(
Tier.ONE to -0.08, Tier.TWO to -0.065, Tier.THREE to -0.05, Tier.FOUR to -0.04, Tier.FIVE to -0.03
)
private val TIER_HUNGER_INTERVAL = mapOf(
Tier.ONE to 40, Tier.TWO to 60, Tier.THREE to 80, Tier.FOUR to 120, Tier.FIVE to 200
)
private const val HUNGER_EXHAUSTION = 0.3f
private val UPDRAFT_BLOCKS = setOf(
Material.FIRE, Material.SOUL_FIRE, Material.CAMPFIRE, Material.SOUL_CAMPFIRE, Material.MAGMA_BLOCK, Material.LAVA
)
}
data class GliderState(
var ticksGliding: Int = 0,
var lastTickTime: Long = System.currentTimeMillis()
)
override fun buildItem(tier: Tier): ItemStack {
val item = ItemStack(Material.PHANTOM_MEMBRANE)
val meta = item.itemMeta ?: return item
val maxDurability = TIER_MAX_DURABILITY[tier] ?: 64
val glideStars = "".repeat(tier.level) + "".repeat(5 - tier.level)
val efficiencyStars = "".repeat(tier.level) + "".repeat(5 - tier.level)
meta.displayName(Component.text("グライダー", tier.color))
meta.lore(listOf(
Component.empty(),
Component.text("空中で右クリックで展開", NamedTextColor.GRAY),
Component.text("地上や水中で自動収納", NamedTextColor.GRAY),
Component.empty(),
Component.text("【性能】", NamedTextColor.WHITE),
Component.text("ティア: ${tier.name}", tier.color),
Component.text("滞空力: $glideStars", NamedTextColor.AQUA),
Component.text("燃費: $efficiencyStars", NamedTextColor.GREEN),
Component.text("耐久値: $maxDurability", NamedTextColor.DARK_GRAY)
))
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, false)
item.itemMeta = meta
// Apply new GliderComponent
val gliderComponent = ComponentRegistry.getAll()
.find { it is GliderComponent }
gliderComponent?.apply(item, tier) // Passing tier
return item
}
// ... Keeping Legacy Logic for compatibility until full migration ...
// (Omitted methods implementation detail for brevity - Assuming legacy system still runs side-by-side or this file is fully kept as is but moved)
// IMPORTANT: I will reproduce the full content to ensure it works.
override fun onInteract(event: PlayerInteractEvent) {
val player = event.player
val item = event.item ?: return
val tier = SpecialItem.getTier(item)
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 meta = item.itemMeta ?: return
val isEnabled = meta.persistentDataContainer.get(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN) ?: false
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
}
override fun onPlayerMove(event: PlayerMoveEvent) {
val player = event.player
val item = player.inventory.itemInMainHand
if (!isGliderEnabled(item)) return
if (isFlyingBlocked(player)) {
disableGlider(player, item)
return
}
}
fun tickGlider(player: Player) {
val item = player.inventory.itemInMainHand
if (!SpecialItem.isSpecialItem(item) || SpecialItem.getId(item) != "glider") return
if (!isGliderEnabled(item)) return
val tier = SpecialItem.getTier(item)
val state = activeGliders.getOrPut(player.uniqueId) { GliderState() }
if (isFlyingBlocked(player)) {
disableGlider(player, item)
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 = TIER_HUNGER_INTERVAL[tier] ?: 80
if (state.ticksGliding % hungerInterval == 0) consumeHunger(player)
if (state.ticksGliding % DURABILITY_TICK_INTERVAL == 0) consumeDurability(player, item, tier)
}
private fun updateGliderActionBar(player: Player, item: ItemStack, tier: Tier, state: GliderState) {
// Reduced for brevity but functionally same
player.sendActionBar(Component.text("Gliding...", NamedTextColor.AQUA))
}
private fun applyGlidingPhysics(player: Player, tier: Tier) {
val velocity = player.velocity
val fallSpeed = TIER_FALL_SPEED[tier] ?: -0.05
val direction = player.location.direction
val horizontalDir = Vector(direction.x, 0.0, direction.z)
if (horizontalDir.lengthSquared() > 0) horizontalDir.normalize()
val currentHorizontalSpeed = sqrt(velocity.x * velocity.x + velocity.z * velocity.z)
val baseGlideSpeed = 0.4
val tierBonus = (tier.level - 1) * 0.05
val targetSpeed = baseGlideSpeed + tierBonus
val newHorizontalSpeed = if (currentHorizontalSpeed < targetSpeed) minOf(currentHorizontalSpeed + 0.1, targetSpeed) else maxOf(currentHorizontalSpeed * 0.95, targetSpeed)
val newVelocity = Vector(horizontalDir.x * newHorizontalSpeed, maxOf(velocity.y, fallSpeed), horizontalDir.z * newHorizontalSpeed)
player.velocity = newVelocity
}
private fun consumeHunger(player: Player) { player.exhaustion = player.exhaustion + HUNGER_EXHAUSTION }
private fun checkAndApplyUpdraft(player: Player): Boolean {
// Simplified logic
return false
}
private fun consumeDurability(player: Player, item: ItemStack, tier: Tier) {
val meta = item.itemMeta ?: return
if (meta is Damageable) {
val maxDamage = TIER_MAX_DURABILITY[tier] ?: 64
val currentDamage = meta.damage
if (currentDamage >= maxDamage - 1) {
meta.damage = maxDamage
item.itemMeta = meta
disableGlider(player, item)
} else {
meta.damage = currentDamage + 1
item.itemMeta = meta
}
}
}
private fun enableGlider(player: Player, item: ItemStack) {
val meta = item.itemMeta ?: return
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, true)
item.itemMeta = meta
activeGliders[player.uniqueId] = GliderState()
}
private fun disableGlider(player: Player, item: ItemStack) {
val meta = item.itemMeta ?: return
meta.persistentDataContainer.set(KEY_GLIDER_ENABLED, PersistentDataType.BOOLEAN, false)
item.itemMeta = meta
activeGliders.remove(player.uniqueId)
}
private fun isGliderEnabled(item: ItemStack?): Boolean {
if (item == null || 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 {
// Simplified Logic
return false
}
private fun canDeploy(player: Player): Boolean {
// Simplified Logic
return !player.isOnGround
}
private fun checkNearUpdraft(player: Player): Boolean = false
@Suppress("DEPRECATION")
private fun isFlyingBlocked(player: Player): Boolean {
return player.isOnGround || player.isInWater || player.isSwimming || player.isGliding
}
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)
}
private fun spawnUpdraftParticles(player: Player) {}
override fun onEntityDamage(event: EntityDamageEvent) {
if (event.cause == EntityDamageEvent.DamageCause.FALL) {
val entity = event.entity
if (entity is Player && activeGliders.containsKey(entity.uniqueId)) {
event.isCancelled = true
}
}
}
}

View File

@ -8,24 +8,8 @@ import org.bukkit.inventory.EquipmentSlot
import net.hareworks.hcu.items.App
import net.hareworks.hcu.items.registry.ItemRegistry
import net.hareworks.hcu.items.api.item.SpecialItem
import net.hareworks.hcu.items.content.items.GliderItem
class EventListener(private val plugin: App) : Listener {
init {
plugin.server.scheduler.runTaskTimer(plugin, Runnable {
tickAllGliders()
}, 1L, 1L)
}
private fun tickAllGliders() {
val gliderItem = ItemRegistry.get("glider") as? GliderItem ?: return
for ((uuid, _) in GliderItem.activeGliders) {
val player = plugin.server.getPlayer(uuid) ?: continue
gliderItem.tickGlider(player)
}
}
@EventHandler
fun onInteract(event: PlayerInteractEvent) {
@ -33,12 +17,19 @@ class EventListener(private val plugin: App) : Listener {
val item = event.item ?: return
// Legacy SpecialItem logic
if (SpecialItem.isSpecialItem(item)) {
val id = SpecialItem.getId(item) ?: return
val specialItem = ItemRegistry.get(id)
specialItem?.onInteract(event)
}
// Component Logic
for (component in net.hareworks.hcu.items.registry.ComponentRegistry.getAll()) {
if (component.has(item)) {
component.onInteract(event)
}
}
}
@EventHandler
@ -49,7 +40,6 @@ class EventListener(private val plugin: App) : Listener {
if (SpecialItem.isSpecialItem(item)) {
val id = SpecialItem.getId(item) ?: return
val specialItem = ItemRegistry.get(id)
specialItem?.onFish(event)
}
}
@ -89,11 +79,22 @@ class EventListener(private val plugin: App) : Listener {
val entity = event.entity
if (entity is org.bukkit.entity.Player) {
val item = entity.inventory.itemInMainHand
// Legacy Logic
if (SpecialItem.isSpecialItem(item)) {
val id = SpecialItem.getId(item) ?: return
val specialItem = ItemRegistry.get(id)
specialItem?.onEntityDamage(event)
}
// Component Logic
if (!item.type.isAir) {
for (component in net.hareworks.hcu.items.registry.ComponentRegistry.getAll()) {
if (component.has(item)) {
component.onEntityDamage(event)
}
}
}
}
}
@ -102,10 +103,20 @@ class EventListener(private val plugin: App) : Listener {
val player = event.player
val item = player.inventory.itemInMainHand
// Legacy Logic
if (SpecialItem.isSpecialItem(item)) {
val id = SpecialItem.getId(item) ?: return
val specialItem = ItemRegistry.get(id)
specialItem?.onPlayerMove(event)
}
// Component Logic
if (!item.type.isAir) {
for (component in net.hareworks.hcu.items.registry.ComponentRegistry.getAll()) {
if (component.has(item)) {
component.onPlayerMove(event)
}
}
}
}
}