feat: Implement Vein Miner component with configurable multi-block breaking, compatible material groups, tool categories, and visual highlighting.
This commit is contained in:
parent
f1787b9b62
commit
f45947b9e9
|
|
@ -11,6 +11,7 @@ import net.hareworks.hcu.items.content.items.GrapplingItem
|
||||||
import net.hareworks.hcu.items.content.components.GliderComponent
|
import net.hareworks.hcu.items.content.components.GliderComponent
|
||||||
import net.hareworks.hcu.items.content.components.DoubleJumpComponent
|
import net.hareworks.hcu.items.content.components.DoubleJumpComponent
|
||||||
import net.hareworks.hcu.items.content.components.BlinkComponent
|
import net.hareworks.hcu.items.content.components.BlinkComponent
|
||||||
|
import net.hareworks.hcu.items.content.components.VeinMinerComponent
|
||||||
|
|
||||||
import org.bukkit.permissions.PermissionDefault
|
import org.bukkit.permissions.PermissionDefault
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
@ -43,6 +44,7 @@ public class App : JavaPlugin() {
|
||||||
ComponentRegistry.register(GliderComponent(this))
|
ComponentRegistry.register(GliderComponent(this))
|
||||||
ComponentRegistry.register(DoubleJumpComponent(this))
|
ComponentRegistry.register(DoubleJumpComponent(this))
|
||||||
ComponentRegistry.register(BlinkComponent(this))
|
ComponentRegistry.register(BlinkComponent(this))
|
||||||
|
ComponentRegistry.register(VeinMinerComponent(this))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,5 @@ interface CustomComponent {
|
||||||
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) {}
|
fun onToggleSneak(player: org.bukkit.entity.Player, item: org.bukkit.inventory.ItemStack, event: org.bukkit.event.player.PlayerToggleSneakEvent) {}
|
||||||
fun onToggleGlide(player: org.bukkit.entity.Player, item: org.bukkit.inventory.ItemStack, event: org.bukkit.event.entity.EntityToggleGlideEvent) {}
|
fun onToggleGlide(player: org.bukkit.entity.Player, item: org.bukkit.inventory.ItemStack, event: org.bukkit.event.entity.EntityToggleGlideEvent) {}
|
||||||
|
fun onBlockBreak(event: org.bukkit.event.block.BlockBreakEvent) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,13 @@ object Config {
|
||||||
var doubleJumpCooldown: Long = 1500
|
var doubleJumpCooldown: Long = 1500
|
||||||
var doubleJumpPowerVertical: Double = 0.5
|
var doubleJumpPowerVertical: Double = 0.5
|
||||||
var doubleJumpPowerForward: Double = 0.3
|
var doubleJumpPowerForward: Double = 0.3
|
||||||
|
|
||||||
|
// Vein Miner
|
||||||
|
data class ToolCategory(val toolPattern: String, val allowedBlockPatterns: 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 veinMinerToolCategories: MutableList<ToolCategory> = mutableListOf()
|
||||||
|
|
||||||
fun load(plugin: JavaPlugin) {
|
fun load(plugin: JavaPlugin) {
|
||||||
plugin.reloadConfig()
|
plugin.reloadConfig()
|
||||||
|
|
@ -23,6 +30,12 @@ object Config {
|
||||||
doubleJumpPowerVertical = config.getDouble("components.double_jump.power.vertical", 0.5)
|
doubleJumpPowerVertical = config.getDouble("components.double_jump.power.vertical", 0.5)
|
||||||
doubleJumpPowerForward = config.getDouble("components.double_jump.power.forward", 0.3)
|
doubleJumpPowerForward = config.getDouble("components.double_jump.power.forward", 0.3)
|
||||||
|
|
||||||
|
// Vein Miner
|
||||||
|
veinMinerMaxBlocks = config.getInt("components.vein_miner.max_blocks", 64)
|
||||||
|
veinMinerActivationMode = config.getString("components.vein_miner.activation_mode", "SNEAK") ?: "SNEAK"
|
||||||
|
loadCompatibleGroups(config)
|
||||||
|
loadToolCategories(config)
|
||||||
|
|
||||||
// Save back to ensure defaults are written if missing
|
// Save back to ensure defaults are written if missing
|
||||||
saveDefaults(plugin, config)
|
saveDefaults(plugin, config)
|
||||||
}
|
}
|
||||||
|
|
@ -33,7 +46,45 @@ object Config {
|
||||||
config.addDefault("components.double_jump.power.vertical", 0.5)
|
config.addDefault("components.double_jump.power.vertical", 0.5)
|
||||||
config.addDefault("components.double_jump.power.forward", 0.3)
|
config.addDefault("components.double_jump.power.forward", 0.3)
|
||||||
|
|
||||||
|
config.addDefault("components.vein_miner.max_blocks", 64)
|
||||||
|
// Groups default is complex to add here, relying on config.yml resource or existing file
|
||||||
|
|
||||||
|
// Tool categories default is handled by config.yml resource
|
||||||
|
|
||||||
config.options().copyDefaults(true)
|
config.options().copyDefaults(true)
|
||||||
plugin.saveConfig()
|
plugin.saveConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun loadCompatibleGroups(config: FileConfiguration) {
|
||||||
|
veinMinerCompatibleMaterials.clear()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}.toSet()
|
||||||
|
|
||||||
|
for (mat in materials) {
|
||||||
|
val existing = veinMinerCompatibleMaterials.getOrDefault(mat, emptySet())
|
||||||
|
veinMinerCompatibleMaterials[mat] = existing + materials
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadToolCategories(config: FileConfiguration) {
|
||||||
|
veinMinerToolCategories.clear()
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,311 @@
|
||||||
|
package net.hareworks.hcu.items.content.components
|
||||||
|
|
||||||
|
import net.hareworks.hcu.items.api.component.EquippableComponent
|
||||||
|
import net.hareworks.hcu.items.api.Tier
|
||||||
|
import net.hareworks.hcu.items.config.Config
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
import org.bukkit.inventory.meta.Damageable
|
||||||
|
import org.bukkit.enchantments.Enchantment
|
||||||
|
import org.bukkit.entity.ExperienceOrb
|
||||||
|
import org.bukkit.entity.BlockDisplay
|
||||||
|
import org.bukkit.entity.Display
|
||||||
|
import org.bukkit.util.Transformation
|
||||||
|
import org.joml.Vector3f
|
||||||
|
import org.bukkit.Color
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import java.util.LinkedList
|
||||||
|
import java.util.Queue
|
||||||
|
import java.util.Random
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
class VeinMinerComponent(private val plugin: JavaPlugin) : EquippableComponent {
|
||||||
|
|
||||||
|
override val key: NamespacedKey = NamespacedKey(plugin, "vein_miner")
|
||||||
|
override val displayName: String = "Vein Miner"
|
||||||
|
override val maxTier: Int = 1
|
||||||
|
override val minTier: Int = 1
|
||||||
|
|
||||||
|
private val activeHighlights = mutableMapOf<UUID, HighlightSession>()
|
||||||
|
|
||||||
|
data class HighlightSession(
|
||||||
|
val centerBlock: Block,
|
||||||
|
val entities: List<BlockDisplay>,
|
||||||
|
val lastUpdate: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun apply(item: ItemStack, tier: Tier?) {
|
||||||
|
val meta = item.itemMeta ?: return
|
||||||
|
meta.persistentDataContainer.set(key, PersistentDataType.BYTE, 1.toByte())
|
||||||
|
item.itemMeta = meta
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun has(item: ItemStack): Boolean {
|
||||||
|
if (item.type.isAir) return false
|
||||||
|
return item.itemMeta?.persistentDataContainer?.has(key, PersistentDataType.BYTE) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(item: ItemStack) {
|
||||||
|
val meta = item.itemMeta ?: return
|
||||||
|
meta.persistentDataContainer.remove(key)
|
||||||
|
item.itemMeta = meta
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTick(player: Player, item: ItemStack) {
|
||||||
|
// ハイライト条件チェック (Sneakしながら)
|
||||||
|
if (!player.isSneaking) {
|
||||||
|
clearHighlight(player)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ターゲットブロック取得
|
||||||
|
val targetBlock = player.getTargetBlockExact(5)
|
||||||
|
if (targetBlock == null || targetBlock.type == Material.AIR) {
|
||||||
|
clearHighlight(player)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 既存ハイライトの更新不要チェック
|
||||||
|
val session = activeHighlights[player.uniqueId]
|
||||||
|
if (session != null && session.centerBlock == targetBlock) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ハイライト再生成
|
||||||
|
clearHighlight(player)
|
||||||
|
|
||||||
|
// 破壊対象計算
|
||||||
|
val blocksToBreak = calculateBreakList(player, targetBlock, item)
|
||||||
|
if (blocksToBreak.isEmpty()) return
|
||||||
|
|
||||||
|
// ハイライトエンティティ生成
|
||||||
|
val entities = mutableListOf<BlockDisplay>()
|
||||||
|
|
||||||
|
// クライアントのパフォーマンスを考慮し、最大ハイライト数を制限しても良いが、
|
||||||
|
// ユーザー要望通り全てハイライトする
|
||||||
|
for (block in blocksToBreak) {
|
||||||
|
val loc = block.location.add(0.5, 0.5, 0.5)
|
||||||
|
try {
|
||||||
|
// BlockDisplay生成
|
||||||
|
val display = block.world.spawn(loc, BlockDisplay::class.java) { e ->
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
e.isGlowing = true
|
||||||
|
e.glowColorOverride = Color.AQUA // 鮮やかな色
|
||||||
|
e.brightness = Display.Brightness(15, 15) // 最大輝度
|
||||||
|
e.isVisibleByDefault = false
|
||||||
|
}
|
||||||
|
player.showEntity(plugin, display)
|
||||||
|
entities.add(display)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// 1.19.4未満などのケース
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activeHighlights[player.uniqueId] = HighlightSession(targetBlock, entities, System.currentTimeMillis())
|
||||||
|
}
|
||||||
|
|
||||||
|
// アイテム持ち替えやスニーク解除時にも消えるように
|
||||||
|
override fun onUnequip(player: Player, item: ItemStack) {
|
||||||
|
clearHighlight(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearHighlight(player: Player) {
|
||||||
|
val session = activeHighlights.remove(player.uniqueId) ?: return
|
||||||
|
for (e in session.entities) {
|
||||||
|
e.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBlockBreak(event: BlockBreakEvent) {
|
||||||
|
if (event.isCancelled) return
|
||||||
|
val player = event.player
|
||||||
|
val block = event.block
|
||||||
|
val item = player.inventory.itemInMainHand
|
||||||
|
|
||||||
|
// 発動条件チェック
|
||||||
|
if (!shouldActivate(player)) return
|
||||||
|
|
||||||
|
// 破壊対象リスト
|
||||||
|
val blocksToBreak = calculateBreakList(player, block, item)
|
||||||
|
|
||||||
|
// 単一破壊(連鎖なし)なら何もしない(通常のイベントに任せる)
|
||||||
|
if (blocksToBreak.size <= 1) return
|
||||||
|
|
||||||
|
// ハイライト消去
|
||||||
|
clearHighlight(player)
|
||||||
|
|
||||||
|
val dropLocation = block.location.add(0.5, 0.5, 0.5)
|
||||||
|
val hasSilkTouch = item.containsEnchantment(Enchantment.SILK_TOUCH)
|
||||||
|
|
||||||
|
var soundPlayed = false
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// ドロップ処理
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldActivate(player: Player): Boolean {
|
||||||
|
return when (Config.veinMinerActivationMode) {
|
||||||
|
"SNEAK" -> player.isSneaking
|
||||||
|
"STAND" -> !player.isSneaking
|
||||||
|
"ALWAYS" -> true
|
||||||
|
else -> player.isSneaking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateBreakList(player: Player, startBlock: Block, item: ItemStack): Set<Block> {
|
||||||
|
val visited = mutableSetOf<Block>()
|
||||||
|
|
||||||
|
// ターゲット適正チェック
|
||||||
|
if (!isValidTarget(startBlock, item)) return emptySet()
|
||||||
|
|
||||||
|
// 互換ブロックタイプ抽出
|
||||||
|
val startType = startBlock.type
|
||||||
|
val targetMaterials = Config.veinMinerCompatibleMaterials[startType] ?: setOf()
|
||||||
|
val efficientTargets = if (targetMaterials.isNotEmpty()) targetMaterials else setOf(startType)
|
||||||
|
|
||||||
|
val queue: Queue<Block> = LinkedList()
|
||||||
|
visited.add(startBlock)
|
||||||
|
queue.add(startBlock)
|
||||||
|
|
||||||
|
val max = Config.veinMinerMaxBlocks
|
||||||
|
// 見つかったブロックの実リスト
|
||||||
|
val foundBlocks = mutableSetOf<Block>()
|
||||||
|
foundBlocks.add(startBlock)
|
||||||
|
|
||||||
|
while (queue.isNotEmpty() && foundBlocks.size < max) {
|
||||||
|
val current = queue.poll()
|
||||||
|
|
||||||
|
// 隣接チェック
|
||||||
|
for (x in -1..1) {
|
||||||
|
for (y in -1..1) {
|
||||||
|
for (z in -1..1) {
|
||||||
|
if (x == 0 && y == 0 && z == 0) continue
|
||||||
|
val neighbor = current.getRelative(x, y, z)
|
||||||
|
|
||||||
|
if (visited.contains(neighbor)) continue
|
||||||
|
|
||||||
|
if (efficientTargets.contains(neighbor.type)) {
|
||||||
|
visited.add(neighbor)
|
||||||
|
|
||||||
|
// まだ破壊できるならQueueに追加
|
||||||
|
if (foundBlocks.size < max) {
|
||||||
|
foundBlocks.add(neighbor)
|
||||||
|
queue.add(neighbor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (isAllowed) break
|
||||||
|
}
|
||||||
|
return isAllowed
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExpFromBlock(type: Material): Int {
|
||||||
|
val random = Random()
|
||||||
|
return when (type) {
|
||||||
|
Material.COAL_ORE, Material.DEEPSLATE_COAL_ORE -> random.nextInt(3)
|
||||||
|
Material.DIAMOND_ORE, Material.DEEPSLATE_DIAMOND_ORE -> random.nextInt(5) + 3
|
||||||
|
Material.EMERALD_ORE, Material.DEEPSLATE_EMERALD_ORE -> random.nextInt(5) + 3
|
||||||
|
Material.LAPIS_ORE, Material.DEEPSLATE_LAPIS_ORE -> random.nextInt(4) + 2
|
||||||
|
Material.NETHER_QUARTZ_ORE -> random.nextInt(4) + 2
|
||||||
|
Material.REDSTONE_ORE, Material.DEEPSLATE_REDSTONE_ORE -> random.nextInt(5) + 1
|
||||||
|
Material.NETHER_GOLD_ORE -> random.nextInt(2)
|
||||||
|
Material.SCULK -> 1
|
||||||
|
Material.SPAWNER -> random.nextInt(29) + 15
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -121,6 +121,15 @@ class EventListener(private val plugin: Plugin) : Listener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onBlockBreak(event: org.bukkit.event.block.BlockBreakEvent) {
|
||||||
|
val player = event.player
|
||||||
|
val item = player.inventory.itemInMainHand
|
||||||
|
|
||||||
|
// Dispatch to components on the main hand item
|
||||||
|
dispatchToComponents(item) { it.onBlockBreak(event) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun tickComponents() {
|
private fun tickComponents() {
|
||||||
for (player in plugin.server.onlinePlayers) {
|
for (player in plugin.server.onlinePlayers) {
|
||||||
val items = getEquipmentItems(player)
|
val items = getEquipmentItems(player)
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,45 @@ components:
|
||||||
power:
|
power:
|
||||||
vertical: 0.5
|
vertical: 0.5
|
||||||
forward: 0.3
|
forward: 0.3
|
||||||
|
vein_miner:
|
||||||
|
max_blocks: 64
|
||||||
|
activation_mode: "SNEAK" # SNEAK, ALWAYS, STAND
|
||||||
|
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" ]
|
||||||
|
tool_categories:
|
||||||
|
- tool_pattern: "_pickaxe"
|
||||||
|
allowed_blocks:
|
||||||
|
- "_ore"
|
||||||
|
- "minecraft:ancient_debris"
|
||||||
|
- "minecraft:amethyst_block"
|
||||||
|
- "minecraft:budding_amethyst"
|
||||||
|
- "minecraft:obsidian"
|
||||||
|
- tool_pattern: "_axe"
|
||||||
|
allowed_blocks:
|
||||||
|
- "_log"
|
||||||
|
- "_stem"
|
||||||
|
- "_hyphae"
|
||||||
|
- "minecraft:mangrove_roots"
|
||||||
|
- "minecraft:bamboo_block"
|
||||||
|
- tool_pattern: "_shovel"
|
||||||
|
allowed_blocks:
|
||||||
|
- "minecraft:clay"
|
||||||
|
- "minecraft:gravel"
|
||||||
|
- "minecraft:soul_sand"
|
||||||
|
- "minecraft:soul_soil"
|
||||||
|
- "minecraft:mud"
|
||||||
|
- "minecraft:snow"
|
||||||
|
- tool_pattern: "_hoe"
|
||||||
|
allowed_blocks:
|
||||||
|
- "_leaves"
|
||||||
|
- "minecraft:nether_wart_block"
|
||||||
|
- "minecraft:shroomlight"
|
||||||
|
- "minecraft:hay_block"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user