feat: Vein Miner configuration now supports block tags and block highlight colors.

This commit is contained in:
Kariya 2025-12-16 20:03:17 +00:00
parent 32dbebb228
commit a464a8f77f
3 changed files with 152 additions and 103 deletions

View File

@ -15,12 +15,14 @@ object Config {
var componentTickInterval: Long = 1L
// Vein Miner
data class ToolCategory(val toolPattern: String, val allowedBlockPatterns: List<String>)
data class ToolCategory(val tool: String, val blocks: List<String>)
var veinMinerMaxBlocks: Int = 64
var veinMinerActivationMode: String = "SNEAK" // "SNEAK", "ALWAYS", "STAND"
val veinMinerCompatibleMaterials: MutableMap<org.bukkit.Material, Set<org.bukkit.Material>> = mutableMapOf()
val veinMinerBlockColors: MutableMap<org.bukkit.Material, org.bukkit.Color> = mutableMapOf()
val veinMinerToolCategories: MutableList<ToolCategory> = 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<org.bukkit.Material>()
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<String>() ?: continue
veinMinerToolCategories.add(ToolCategory(toolPattern, allowedBlocks))
val tool = map["tool"] as? String ?: continue
val blocks = (map["active_blocks"] as? List<*>)?.filterIsInstance<String>() ?: 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
}
}
}
}
}

View File

@ -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
}
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 == 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
}
// Exact Material Match
val targetMat = Material.matchMaterial(criteria)
return targetMat != null && block.type == targetMat
}
private fun getExpFromBlock(type: Material): Int {

View File

@ -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"