refactor: Extract common item scroll adjustment logic into ItemActionUtil and manage scroll states for items.
This commit is contained in:
parent
3b62b26273
commit
d4c8cd84fb
|
|
@ -18,6 +18,7 @@ import net.hareworks.hcu.items.content.components.AreaTillerComponent
|
|||
|
||||
import org.bukkit.permissions.PermissionDefault
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import net.hareworks.hcu.items.util.ItemActionUtil
|
||||
|
||||
public class App : JavaPlugin() {
|
||||
|
||||
|
|
@ -53,4 +54,9 @@ public class App : JavaPlugin() {
|
|||
|
||||
server.pluginManager.registerEvents(net.hareworks.hcu.items.listeners.EventListener(this), this)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
ItemActionUtil.clearAllScrollStates()
|
||||
logger.info("Items plugin disabled!")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import java.util.UUID
|
|||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.reflect.KClass
|
||||
import net.hareworks.hcu.items.util.ItemActionUtil
|
||||
|
||||
/**
|
||||
* AreaTillerComponent - 広範囲一括耕地化コンポーネント
|
||||
|
|
@ -302,24 +303,14 @@ class AreaTillerComponent(private val plugin: JavaPlugin) : ToolComponent {
|
|||
*/
|
||||
private fun handleItemHeld(event: PlayerItemHeldEvent, item: ItemStack) {
|
||||
val player = event.player
|
||||
val session = editSessions.getOrPut(player.uniqueId) { EditSession() }
|
||||
|
||||
// スニーク中のみ調整
|
||||
if (!player.isSneaking) return
|
||||
|
||||
val session = editSessions.getOrPut(player.uniqueId) { EditSession() }
|
||||
ItemActionUtil.handleScrollAdjustment(event) { delta ->
|
||||
val tier = getTier(item)
|
||||
val maxRange = getMaxRangeForTier(tier)
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
if (now - session.lastScrollTime < 50) return
|
||||
|
||||
session.lastScrollTime = now
|
||||
|
||||
// スクロール方向を判定
|
||||
val diff = event.newSlot - event.previousSlot
|
||||
val scrollUp = (diff == -1 || diff == 8)
|
||||
val delta = if (scrollUp) 1 else -1
|
||||
|
||||
// プレイヤーの向きから、どの方角の範囲を伸長するか決定
|
||||
val facing = getDirectionFacing(player.location.yaw)
|
||||
|
||||
|
|
@ -332,9 +323,7 @@ class AreaTillerComponent(private val plugin: JavaPlugin) : ToolComponent {
|
|||
}
|
||||
|
||||
player.playSound(player.location, Sound.UI_BUTTON_CLICK, 0.3f, 1.2f)
|
||||
|
||||
// イベントをキャンセルしてスロット切り替えを防ぐ
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import org.bukkit.entity.Item
|
|||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import net.hareworks.hcu.items.util.ItemActionUtil
|
||||
|
||||
class MagnetItem : AbstractItem("magnet_item") {
|
||||
|
||||
|
|
@ -109,23 +110,18 @@ class MagnetItem : AbstractItem("magnet_item") {
|
|||
val item = player.inventory.getItem(event.previousSlot) ?: return
|
||||
|
||||
if (!Config.magnet.allowScrollChange) return
|
||||
|
||||
if (!player.isSneaking) return
|
||||
|
||||
// 動いていない時のみ調整可能
|
||||
if (player.velocity.length() > 0.08) return // 完全な0は難しいため閾値を設定
|
||||
|
||||
ItemActionUtil.handleScrollAdjustment(event) { delta ->
|
||||
val configInfo = Config.magnet
|
||||
val tier = getTier(item)
|
||||
val maxRadius = configInfo.radiusBase + (tier.level * configInfo.radiusPerTier)
|
||||
|
||||
val diff = event.newSlot - event.previousSlot
|
||||
val scrollUp = (diff == -1 || diff == 8)
|
||||
val change = if (scrollUp) 1.0 else -1.0
|
||||
|
||||
// Get current radius
|
||||
var currentRadius = item.itemMeta?.persistentDataContainer?.get(KEY_RADIUS, PersistentDataType.DOUBLE) ?: maxRadius
|
||||
|
||||
currentRadius += change
|
||||
currentRadius += delta.toDouble()
|
||||
currentRadius = currentRadius.coerceIn(1.0, maxRadius)
|
||||
|
||||
// Save to PDC
|
||||
|
|
@ -143,8 +139,8 @@ class MagnetItem : AbstractItem("magnet_item") {
|
|||
// 視覚的なフィードバック (BlockDisplayによるリング表示)
|
||||
updateRadiusRing(player, currentRadius, tier)
|
||||
|
||||
// Cancel event to prevent slot switch
|
||||
event.isCancelled = true
|
||||
player.playSound(player.location, Sound.UI_BUTTON_CLICK, 0.3f, 1.2f)
|
||||
}
|
||||
}
|
||||
|
||||
private val activeRings = java.util.concurrent.ConcurrentHashMap<java.util.UUID, RingSession>()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ import org.bukkit.event.entity.ProjectileHitEvent
|
|||
import org.bukkit.event.entity.EntityExplodeEvent
|
||||
import org.bukkit.event.entity.EntityInteractEvent
|
||||
import org.bukkit.event.block.*
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import net.hareworks.hcu.items.util.ItemActionUtil
|
||||
import org.bukkit.plugin.EventExecutor
|
||||
import org.bukkit.plugin.Plugin
|
||||
import org.bukkit.event.EventPriority
|
||||
|
|
@ -120,6 +122,11 @@ class EventListener(private val plugin: Plugin) : Listener {
|
|||
dispatchGlobalToComponents(event)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onPlayerQuit(event: PlayerQuitEvent) {
|
||||
ItemActionUtil.clearScrollState(event.player)
|
||||
}
|
||||
|
||||
private fun <T : Event> dispatchGlobalToComponents(event: T) {
|
||||
val eventClass = event.javaClass.kotlin
|
||||
ComponentRegistry.getAll().forEach { component ->
|
||||
|
|
|
|||
107
src/main/kotlin/net/hareworks/hcu/items/util/ItemActionUtil.kt
Normal file
107
src/main/kotlin/net/hareworks/hcu/items/util/ItemActionUtil.kt
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package net.hareworks.hcu.items.util
|
||||
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.player.PlayerItemHeldEvent
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* アイテム操作に関する共通ユーティリティ
|
||||
*/
|
||||
object ItemActionUtil {
|
||||
// プレイヤーごとのスクロール状態を管理
|
||||
private data class ScrollState(
|
||||
var lastScrollTime: Long = 0L,
|
||||
var accumulatedDelta: Double = 0.0,
|
||||
var lastProcessedTime: Long = 0L
|
||||
)
|
||||
|
||||
private val scrollStates = ConcurrentHashMap<UUID, ScrollState>()
|
||||
|
||||
// 設定値
|
||||
private const val SCROLL_COOLDOWN_MS = 50L // スクロール間隔(ミリ秒)
|
||||
private const val ACCELERATION_THRESHOLD = 150L // 加速判定の時間閾値
|
||||
private const val DELTA_THRESHOLD = 0.8 // 累積値の閾値
|
||||
private const val MAX_ACCUMULATED_DELTA = 5.0 // 最大累積値
|
||||
|
||||
/**
|
||||
* マウスホイール(スロット変更)による設定値の調整ロジックを処理します。
|
||||
* スクロールの速度に応じて滑らかに、かつ連続スクロール時には加速して調整します。
|
||||
*
|
||||
* @param event スロット変更イベント
|
||||
* @param onAdjust 調整が有効な場合に呼び出されるコールバック (delta: Int)
|
||||
*/
|
||||
fun handleScrollAdjustment(event: PlayerItemHeldEvent, onAdjust: (Int) -> Unit) {
|
||||
val player = event.player
|
||||
|
||||
// 2. プレイヤーがほぼ静止状態のみ有効
|
||||
if (player.velocity.length() > 0.08) return
|
||||
|
||||
// 3. スクロール方向を判定
|
||||
val diff = event.newSlot - event.previousSlot
|
||||
val scrollUp = (diff == -1 || diff == 8)
|
||||
val rawDelta = if (scrollUp) 1.0 else -1.0
|
||||
|
||||
// 4. 滑らかなスクロール処理
|
||||
val state = scrollStates.computeIfAbsent(player.uniqueId) { ScrollState() }
|
||||
val currentTime = System.currentTimeMillis()
|
||||
val timeSinceLastScroll = currentTime - state.lastScrollTime
|
||||
|
||||
// クールダウンチェック(連続スクロールの検出)
|
||||
if (timeSinceLastScroll < SCROLL_COOLDOWN_MS) {
|
||||
event.isCancelled = true
|
||||
return
|
||||
}
|
||||
|
||||
// 加速度の計算(素早くスクロールすると累積値が増える)
|
||||
val accelerationFactor = if (timeSinceLastScroll < ACCELERATION_THRESHOLD) {
|
||||
1.5 // 素早いスクロールで加速
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
|
||||
// 累積デルタ値の更新
|
||||
state.accumulatedDelta += rawDelta * accelerationFactor
|
||||
state.lastScrollTime = currentTime
|
||||
|
||||
// 累積値の制限
|
||||
state.accumulatedDelta = state.accumulatedDelta.coerceIn(
|
||||
-MAX_ACCUMULATED_DELTA,
|
||||
MAX_ACCUMULATED_DELTA
|
||||
)
|
||||
|
||||
// 閾値を超えたら実際に値を変更
|
||||
val timeSinceLastProcess = currentTime - state.lastProcessedTime
|
||||
if (kotlin.math.abs(state.accumulatedDelta) >= DELTA_THRESHOLD ||
|
||||
timeSinceLastProcess > 200L) { // または一定時間経過
|
||||
|
||||
val deltaToApply = state.accumulatedDelta.toInt()
|
||||
if (deltaToApply != 0) {
|
||||
onAdjust(deltaToApply)
|
||||
state.lastProcessedTime = currentTime
|
||||
state.accumulatedDelta = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
// 5. イベントをキャンセルしてスロット切り替えを防ぐ
|
||||
event.isCancelled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* プレイヤーのスクロール状態をクリアします。
|
||||
* プレイヤーがログアウトした際などに呼び出してください。
|
||||
*
|
||||
* @param player 対象プレイヤー
|
||||
*/
|
||||
fun clearScrollState(player: Player) {
|
||||
scrollStates.remove(player.uniqueId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 全てのスクロール状態をクリアします。
|
||||
* プラグインの無効化時などに呼び出してください。
|
||||
*/
|
||||
fun clearAllScrollStates() {
|
||||
scrollStates.clear()
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user