From a464a8f77fc767f6273ceb010f1a1e0ecc3bd72a Mon Sep 17 00:00:00 2001 From: Kariya Date: Tue, 16 Dec 2025 20:03:17 +0000 Subject: [PATCH] feat: Vein Miner configuration now supports block tags and block highlight colors. --- .../net/hareworks/hcu/items/config/Config.kt | 84 +++++++++++-- .../content/components/VeinMinerComponent.kt | 110 +++++++----------- src/main/resources/config.yml | 61 ++++++---- 3 files changed, 152 insertions(+), 103 deletions(-) diff --git a/src/main/kotlin/net/hareworks/hcu/items/config/Config.kt b/src/main/kotlin/net/hareworks/hcu/items/config/Config.kt index 9c58ae6..373f495 100644 --- a/src/main/kotlin/net/hareworks/hcu/items/config/Config.kt +++ b/src/main/kotlin/net/hareworks/hcu/items/config/Config.kt @@ -15,12 +15,14 @@ object Config { var componentTickInterval: Long = 1L // Vein Miner - data class ToolCategory(val toolPattern: String, val allowedBlockPatterns: List) + data class ToolCategory(val tool: String, val blocks: List) var veinMinerMaxBlocks: Int = 64 var veinMinerActivationMode: String = "SNEAK" // "SNEAK", "ALWAYS", "STAND" val veinMinerCompatibleMaterials: MutableMap> = mutableMapOf() + val veinMinerBlockColors: MutableMap = mutableMapOf() val veinMinerToolCategories: MutableList = mutableListOf() + fun load(plugin: JavaPlugin) { plugin.reloadConfig() val config = plugin.config @@ -47,6 +49,7 @@ object Config { veinMinerActivationMode = config.getString("components.vein_miner.activation_mode", "SNEAK") ?: "SNEAK" loadCompatibleGroups(config) + loadBlockColors(config) loadToolCategories(config) // Save back to ensure defaults are written if missing @@ -75,15 +78,32 @@ object Config { val groups = config.getList("components.vein_miner.compatible_groups") as? List<*> ?: return for (groupObj in groups) { - val group = groupObj as? List<*> ?: continue - val materials = group.mapNotNull { - val name = (it as? String) ?: return@mapNotNull null - try { - org.bukkit.Material.valueOf(name.uppercase().removePrefix("MINECRAFT:")) - } catch (e: IllegalArgumentException) { - null + val group = when (groupObj) { + is List<*> -> groupObj + is String -> listOf(groupObj) + else -> continue + } + + val materials = mutableSetOf() + + for (it in group) { + val name = (it as? String) ?: continue + if (name.startsWith("#")) { + val key = org.bukkit.NamespacedKey.fromString(name.substring(1)) + if (key != null) { + val tag = org.bukkit.Bukkit.getTag(org.bukkit.Tag.REGISTRY_BLOCKS, key, org.bukkit.Material::class.java) + if (tag != null) { + materials.addAll(tag.values) + } + } + } else { + try { + materials.add(org.bukkit.Material.valueOf(name.uppercase().removePrefix("MINECRAFT:"))) + } catch (e: IllegalArgumentException) { + // Ignore + } } - }.toSet() + } for (mat in materials) { val existing = veinMinerCompatibleMaterials.getOrDefault(mat, emptySet()) @@ -97,9 +117,49 @@ object Config { val list = config.getMapList("components.vein_miner.tool_categories") for (map in list) { - val toolPattern = map["tool_pattern"] as? String ?: continue - val allowedBlocks = (map["allowed_blocks"] as? List<*>)?.filterIsInstance() ?: continue - veinMinerToolCategories.add(ToolCategory(toolPattern, allowedBlocks)) + val tool = map["tool"] as? String ?: continue + val blocks = (map["active_blocks"] as? List<*>)?.filterIsInstance() ?: continue + veinMinerToolCategories.add(ToolCategory(tool, blocks)) + } + } + private fun loadBlockColors(config: FileConfiguration) { + veinMinerBlockColors.clear() + val section = config.getConfigurationSection("components.vein_miner.block_colors") ?: return + + for (keyStr in section.getKeys(false)) { + val hexOrRgb = section.getString(keyStr) ?: continue + val color = try { + if (hexOrRgb.contains(",")) { + val parts = hexOrRgb.split(",").map { it.trim().toInt() } + if (parts.size == 3) org.bukkit.Color.fromRGB(parts[0], parts[1], parts[2]) else null + } else { + val hex = hexOrRgb.removePrefix("#") + org.bukkit.Color.fromRGB(hex.toInt(16)) + } + } catch (e: Exception) { + null + } + + if (color == null) continue + + if (keyStr.startsWith("#")) { + val key = org.bukkit.NamespacedKey.fromString(keyStr.substring(1)) + if (key != null) { + val tag = org.bukkit.Bukkit.getTag(org.bukkit.Tag.REGISTRY_BLOCKS, key, org.bukkit.Material::class.java) + if (tag != null) { + for (mat in tag.values) { + veinMinerBlockColors[mat] = color + } + } + } + } else { + try { + val mat = org.bukkit.Material.valueOf(keyStr.uppercase().removePrefix("MINECRAFT:")) + veinMinerBlockColors[mat] = color + } catch (e: IllegalArgumentException) { + continue + } + } } } } diff --git a/src/main/kotlin/net/hareworks/hcu/items/content/components/VeinMinerComponent.kt b/src/main/kotlin/net/hareworks/hcu/items/content/components/VeinMinerComponent.kt index dba920b..3d16502 100644 --- a/src/main/kotlin/net/hareworks/hcu/items/content/components/VeinMinerComponent.kt +++ b/src/main/kotlin/net/hareworks/hcu/items/content/components/VeinMinerComponent.kt @@ -8,6 +8,7 @@ import org.bukkit.NamespacedKey import org.bukkit.block.Block import org.bukkit.entity.Player import org.bukkit.event.block.BlockBreakEvent +import org.bukkit.event.player.PlayerItemDamageEvent import org.bukkit.inventory.ItemStack import org.bukkit.persistence.PersistentDataType import org.bukkit.plugin.java.JavaPlugin @@ -17,6 +18,9 @@ import org.bukkit.entity.ExperienceOrb import org.bukkit.entity.BlockDisplay import org.bukkit.entity.Display import org.bukkit.util.Transformation +import org.bukkit.map.MapPalette +import org.bukkit.GameMode +import org.bukkit.Tag import org.joml.Vector3f import org.bukkit.Color import org.bukkit.Bukkit @@ -102,7 +106,6 @@ class VeinMinerComponent(private val plugin: JavaPlugin) : ToolComponent { // クライアントのパフォーマンスを考慮し、最大ハイライト数を制限しても良いが、 // ユーザー要望通り全てハイライトする if (!supportsBlockDisplay) return - for (block in blocksToBreak) { val loc = block.location.add(0.5, 0.5, 0.5) try { @@ -111,13 +114,13 @@ class VeinMinerComponent(private val plugin: JavaPlugin) : ToolComponent { e.block = block.blockData // 少し大きくして元のブロックを覆う e.transformation = Transformation( - Vector3f(0f, 0f, 0f), - org.joml.AxisAngle4f(0f, 0f, 0f, 0f), - Vector3f(1.01f, 1.01f, 1.01f), - org.joml.AxisAngle4f(0f, 0f, 0f, 0f) + Vector3f(-0.5005f, -0.5005f, -0.5005f), + org.joml.AxisAngle4f(0f, 0f, 0f, 1f), + Vector3f(1.001f, 1.001f, 1.001f), + org.joml.AxisAngle4f(0f, 0f, 0f, 1f) ) e.isGlowing = true - e.glowColorOverride = Color.AQUA // 鮮やかな色 + e.glowColorOverride = Config.veinMinerBlockColors[block.type] ?: block.blockData.getMapColor() e.brightness = Display.Brightness(15, 15) // 最大輝度 e.isVisibleByDefault = false } @@ -128,6 +131,7 @@ class VeinMinerComponent(private val plugin: JavaPlugin) : ToolComponent { } } + activeHighlights[player.uniqueId] = HighlightSession(targetBlock, entities, System.currentTimeMillis()) } @@ -162,44 +166,16 @@ class VeinMinerComponent(private val plugin: JavaPlugin) : ToolComponent { val dropLocation = block.location.add(0.5, 0.5, 0.5) val hasSilkTouch = item.containsEnchantment(Enchantment.SILK_TOUCH) - - var soundPlayed = false + val isDropItems = player.gameMode != GameMode.CREATIVE && player.gameMode != GameMode.SPECTATOR for (target in blocksToBreak) { if (target == block) continue // 起点ブロックはイベントフローで破壊される - // 保護プラグインチェック (擬似イベント) - val checkEvent = BlockBreakEvent(target, player) - Bukkit.getPluginManager().callEvent(checkEvent) - if (checkEvent.isCancelled) continue - - // 演出 (最初の1回だけ、または確率で) - if (!soundPlayed) { - target.world.playSound(target.location, target.blockSoundGroup.breakSound, 1f, 1f) - target.world.spawnParticle(org.bukkit.Particle.BLOCK, target.location.add(0.5,0.5,0.5), 10, 0.3, 0.3, 0.3, target.blockData) - soundPlayed = true + if (isDropItems){ + target.breakNaturally(item, true, true, true) + player.damageItemStack(item, 1) } - - // ドロップ処理 - val drops = target.getDrops(item) - for (drop in drops) { - target.world.dropItem(dropLocation, drop) - } - - // 経験値 - if (!hasSilkTouch) { - val xp = getExpFromBlock(target.type) - if (xp > 0) { - val orb = target.world.spawn(dropLocation, ExperienceOrb::class.java) - orb.experience = xp - } - } - - // ブロック消去 - target.type = Material.AIR - - // 耐久消費 - damageItem(player, item) + else target.type = Material.AIR } } @@ -264,46 +240,40 @@ class VeinMinerComponent(private val plugin: JavaPlugin) : ToolComponent { private fun isValidTarget(block: Block, item: ItemStack): Boolean { if (block.getDrops(item).isEmpty()) return false - val itemName = item.type.key.toString() - val blockName = block.type.key.toString() - - var isAllowed = false for (category in Config.veinMinerToolCategories) { - if (itemName.contains(category.toolPattern)) { - for (pattern in category.allowedBlockPatterns) { - if (blockName.contains(pattern)) { - isAllowed = true - break + if (matchesTool(item, category.tool)) { + for (blockPattern in category.blocks) { + if (matchesBlock(block, blockPattern)) { + return true } } } - if (isAllowed) break } - return isAllowed + return false } - - private fun damageItem(player: Player, item: ItemStack) { - val meta = item.itemMeta as? Damageable ?: return - val unbreakingLevel = item.getEnchantmentLevel(Enchantment.UNBREAKING) - if (unbreakingLevel > 0) { - val random = Random() - if (random.nextInt(unbreakingLevel + 1) > 0) { - return - } + private fun matchesTool(item: ItemStack, criteria: String): Boolean { + // Tag check (#namespace:key) + if (criteria.startsWith("#")) { + val key = NamespacedKey.fromString(criteria.substring(1)) + return key != null && Bukkit.getTag(Tag.REGISTRY_ITEMS, key, Material::class.java)?.isTagged(item.type) == true + } + + // Exact Material Match + val targetMat = Material.matchMaterial(criteria) + return targetMat == item.type + } + + private fun matchesBlock(block: Block, criteria: String): Boolean { + // Tag check (#namespace:key) + if (criteria.startsWith("#")) { + val key = NamespacedKey.fromString(criteria.substring(1)) ?: return false + return Bukkit.getTag(Tag.REGISTRY_BLOCKS, key, Material::class.java)?.isTagged(block.type) == true } - val maxDamage = item.type.maxDurability - if (maxDamage > 0) { - val newDamage = meta.damage + 1 - if (newDamage >= maxDamage) { - item.amount = 0 - player.world.playSound(player.location, org.bukkit.Sound.ENTITY_ITEM_BREAK, 1f, 1f) - } else { - meta.damage = newDamage - item.itemMeta = meta - } - } + // Exact Material Match + val targetMat = Material.matchMaterial(criteria) + return targetMat != null && block.type == targetMat } private fun getExpFromBlock(type: Material): Int { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 74337b8..345125b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -9,42 +9,61 @@ components: vein_miner: max_blocks: 64 activation_mode: "SNEAK" # SNEAK, ALWAYS, STAND + block_colors: + "#minecraft:diamond_ores": "#5DECE5" + "#minecraft:iron_ores": "#D8AF93" + "#minecraft:gold_ores": "#FCEE4B" + "#minecraft:copper_ores": "#966756" + "#minecraft:coal_ores": "#363636" + "#minecraft:redstone_ores": "#FF0000" + "#minecraft:lapis_ores": "#1F61AE" + "#minecraft:emerald_ores": "#00D93A" + "minecraft:ancient_debr ": "#623A32" + "minecraft:nether_quartz_ore": "#EADFD4" compatible_groups: - - [ "minecraft:diamond_ore", "minecraft:deepslate_diamond_ore" ] - - [ "minecraft:iron_ore", "minecraft:deepslate_iron_ore" ] - - [ "minecraft:gold_ore", "minecraft:deepslate_gold_ore" ] - - [ "minecraft:copper_ore", "minecraft:deepslate_copper_ore" ] - - [ "minecraft:coal_ore", "minecraft:deepslate_coal_ore" ] - - [ "minecraft:redstone_ore", "minecraft:deepslate_redstone_ore" ] - - [ "minecraft:lapis_ore", "minecraft:deepslate_lapis_ore" ] - - [ "minecraft:emerald_ore", "minecraft:deepslate_emerald_ore" ] + - [ "#minecraft:diamond_ores" ] + - [ "#minecraft:iron_ores" ] + - [ "#minecraft:gold_ores" ] + - [ "#minecraft:copper_ores" ] + - [ "#minecraft:coal_ores" ] + - [ "#minecraft:redstone_ores" ] + - [ "#minecraft:lapis_ores" ] + - [ "#minecraft:emerald_ores" ] tool_categories: - - tool_pattern: "_pickaxe" - allowed_blocks: - - "_ore" + - tool: "#minecraft:pickaxes" + active_blocks: + - "#minecraft:coal_ores" + - "#minecraft:iron_ores" + - "#minecraft:copper_ores" + - "#minecraft:gold_ores" + - "#minecraft:redstone_ores" + - "#minecraft:lapis_ores" + - "#minecraft:diamond_ores" + - "#minecraft:emerald_ores" + - "minecraft:nether_quartz_ore" - "minecraft:ancient_debris" - "minecraft:amethyst_block" - "minecraft:budding_amethyst" - "minecraft:obsidian" - - tool_pattern: "_axe" - allowed_blocks: - - "_log" - - "_stem" - - "_hyphae" + - tool: "#minecraft:axes" + active_blocks: + - "#minecraft:logs" - "minecraft:mangrove_roots" - "minecraft:bamboo_block" - - tool_pattern: "_shovel" - allowed_blocks: + - tool: "#minecraft:shovels" + active_blocks: - "minecraft:clay" - "minecraft:gravel" - "minecraft:soul_sand" - "minecraft:soul_soil" - "minecraft:mud" - "minecraft:snow" - - tool_pattern: "_hoe" - allowed_blocks: - - "_leaves" + - "minecraft:snow_block" + - tool: "#minecraft:hoes" + active_blocks: + - "#minecraft:leaves" - "minecraft:nether_wart_block" - "minecraft:shroomlight" - "minecraft:hay_block" + - "#minecraft:wart_blocks"