diff --git a/build.gradle.kts b/build.gradle.kts index 9a67d2c..e26bc32 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,21 +1,21 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.7.0" - kotlin("plugin.serialization") version "1.7.0" + kotlin("jvm") version "1.9.20" + kotlin("plugin.serialization") version "1.9.20" id("com.github.johnrengelman.shadow") version "7.1.2" } group = "top.e404" -version = "2.0.10" -val ePluginVersion = "1.0.4" +version = "2.11.0" +val ePluginVersion = "1.2.0" fun eplugin(module: String, version: String = ePluginVersion) = "top.e404:eplugin-${module}:${version}" repositories { maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://oss.sonatype.org/content/groups/public/") - mavenLocal() mavenCentral() + mavenLocal() } dependencies { @@ -29,11 +29,12 @@ dependencies { } tasks { - withType() { + withType { kotlinOptions.jvmTarget = "1.8" } processResources { + filteringCharset = Charsets.UTF_8.name() filesMatching("plugin.yml") { expand(project.properties) } @@ -41,9 +42,10 @@ tasks { shadowJar { archiveFileName.set("${project.name}-${project.version}.jar") - exclude("META-INF/*") - relocate("org.bstats", "top.e404.boom.bstats") - relocate("kotlin", "kotlin1_7_0") + exclude("META-INF/**") + relocate("org.bstats", "top.e404.boom.relocate.bstats") + relocate("kotlin", "top.e404.boom.relocate.kotlin") + relocate("top.eplugin", "top.e404.boom.relocate.eplugin") doFirst { for (file in File("jar").listFiles() ?: arrayOf()) { diff --git a/src/main/kotlin/config/Config.kt b/src/main/kotlin/config/Config.kt index c11b297..4bf9921 100644 --- a/src/main/kotlin/config/Config.kt +++ b/src/main/kotlin/config/Config.kt @@ -297,7 +297,7 @@ data class ClickBlockConfig( @Serializable(RegexSerialization::class) val item: Regex, @Serializable(RegexSerialization::class) - val block: Regex, + val block: Regex? = null, @Serializable(ClickTypeSerializer::class) val type: ClickType ) diff --git a/src/main/kotlin/listener/ClickListener.kt b/src/main/kotlin/listener/ClickListener.kt index b89eba8..54e5962 100644 --- a/src/main/kotlin/listener/ClickListener.kt +++ b/src/main/kotlin/listener/ClickListener.kt @@ -2,12 +2,12 @@ package top.e404.boom.listener import org.bukkit.entity.Player import org.bukkit.event.EventHandler -import org.bukkit.event.block.Action import org.bukkit.event.block.BlockBreakEvent import org.bukkit.event.entity.EntityDamageByEntityEvent import org.bukkit.event.hanging.HangingBreakByEntityEvent import org.bukkit.event.player.PlayerInteractEntityEvent import org.bukkit.event.player.PlayerInteractEvent +import org.bukkit.inventory.EquipmentSlot import top.e404.boom.PL import top.e404.boom.config.ClickType import top.e404.boom.config.Config @@ -23,15 +23,61 @@ object ClickListener : EListener(PL) { */ @EventHandler fun PlayerInteractEvent.onEvent() { - val block = clickedBlock ?: return + val block = clickedBlock val hand = hand ?: return val cfg = Config.getConfig(player.location) { preventClickBlock } ?: return val item = player.inventory.getItem(hand).type.name + + if (block == null) { + for ((itemRegex, blockRegex, type) in cfg) { + // 匹配blockRegex为空的 + if (blockRegex != null) continue + // 检测破坏 && 动作不是破坏 + if (type == ClickType.LEFT && !action.name.startsWith("LEFT")) continue + // 检测点击 && 动作不是点击 + if (type == ClickType.RIGHT && !action.name.startsWith("RIGHT")) continue + // 物品或方块不匹配 + if (!itemRegex.matches(item)) continue + if (player.hasPermission("boom.bypass.block")) { + plugin.debug { + Lang[ + "click_air.pass", + "player" to player.name, + "hand" to hand.alias, + "item" to item + ] + } + return + } + isCancelled = true + plugin.debug { + Lang[ + "click_air.prevent", + "player" to player.name, + "hand" to hand.alias, + "item" to item + ] + } + return + } + plugin.debug { + Lang[ + "click_air.no_handler", + "player" to player.name, + "hand" to hand.alias, + "item" to item + ] + } + return + } + for ((itemRegex, blockRegex, type) in cfg) { + // 匹配blockRegex不为空的 + if (blockRegex == null) continue // 检测破坏 && 动作不是破坏 - if (type == ClickType.LEFT && action != Action.LEFT_CLICK_BLOCK) continue + if (type == ClickType.LEFT && !action.name.startsWith("LEFT")) continue // 检测点击 && 动作不是点击 - if (type == ClickType.RIGHT && action != Action.RIGHT_CLICK_BLOCK) continue + if (type == ClickType.RIGHT && !action.name.startsWith("RIGHT")) continue // 物品或方块不匹配 if (!blockRegex.matches(block.type.name) || !itemRegex.matches(item) @@ -39,43 +85,46 @@ object ClickListener : EListener(PL) { if (player.hasPermission("boom.bypass.block")) { plugin.debug { Lang[ - "click.pass", - "player" to player.name, - "item" to item, - "target" to block.type.name, - "world" to player.world.name, - "x" to block.x, - "y" to block.y, - "z" to block.z, - ] - } - return - } - isCancelled = true - plugin.debug { - Lang[ - "click.prevent", + "click.pass", "player" to player.name, + "hand" to hand.alias, "item" to item, "target" to block.type.name, "world" to player.world.name, "x" to block.x, "y" to block.y, "z" to block.z, - ] + ] + } + return } - return - } - plugin.debug { - Lang[ - "click.pass", + isCancelled = true + plugin.debug { + Lang[ + "click.prevent", "player" to player.name, + "hand" to hand.alias, "item" to item, "target" to block.type.name, "world" to player.world.name, "x" to block.x, "y" to block.y, "z" to block.z, + ] + } + return + } + plugin.debug { + Lang[ + "click.no_handler", + "player" to player.name, + "hand" to hand.alias, + "item" to item, + "target" to block.type.name, + "world" to player.world.name, + "x" to block.x, + "y" to block.y, + "z" to block.z, ] } } @@ -89,6 +138,8 @@ object ClickListener : EListener(PL) { val cfg = Config.getConfig(player.location) { preventClickBlock } ?: return val item = player.inventory.itemInMainHand.type.name for ((itemRegex, blockRegex, type) in cfg) { + // 匹配blockRegex不为空的 + if (blockRegex == null) continue // 忽略交互检测 if (type == ClickType.RIGHT) continue // 物品或方块不匹配 @@ -98,43 +149,46 @@ object ClickListener : EListener(PL) { if (player.hasPermission("boom.bypass.block")) { plugin.debug { Lang[ - "click.pass", - "player" to player.name, - "item" to item, - "target" to block.type.name, - "world" to player.world.name, - "x" to block.x, - "y" to block.y, - "z" to block.z, - ] - } - return - } - isCancelled = true - plugin.debug { - Lang[ - "click.prevent", + "click.pass", "player" to player.name, + "hand" to "主", "item" to item, "target" to block.type.name, "world" to player.world.name, "x" to block.x, "y" to block.y, "z" to block.z, - ] + ] + } + return } - return - } - plugin.debug { - Lang[ - "click.pass", + isCancelled = true + plugin.debug { + Lang[ + "click.prevent", "player" to player.name, + "hand" to "主", "item" to item, "target" to block.type.name, "world" to player.world.name, "x" to block.x, "y" to block.y, "z" to block.z, + ] + } + return + } + plugin.debug { + Lang[ + "click.no_handler", + "player" to player.name, + "hand" to "主", + "item" to item, + "target" to block.type.name, + "world" to player.world.name, + "x" to block.x, + "y" to block.y, + "z" to block.z, ] } } @@ -158,45 +212,48 @@ object ClickListener : EListener(PL) { plugin.debug { val l = rightClicked.location Lang[ - "click.pass", - "player" to player.name, - "item" to item, - "target" to entity, - "world" to player.world.name, - "x" to l.blockX, - "y" to l.blockY, - "z" to l.blockZ, - ] - } - return - } - isCancelled = true - plugin.debug { - val l = rightClicked.location - Lang[ - "click.prevent", + "click.pass", "player" to player.name, + "hand" to hand.alias, "item" to item, "target" to entity, "world" to player.world.name, "x" to l.blockX, "y" to l.blockY, "z" to l.blockZ, - ] + ] + } + return } - return - } - plugin.debug { - val l = rightClicked.location - Lang[ - "click.pass", + isCancelled = true + plugin.debug { + val l = rightClicked.location + Lang[ + "click.prevent", "player" to player.name, + "hand" to hand.alias, "item" to item, "target" to entity, "world" to player.world.name, "x" to l.blockX, "y" to l.blockY, "z" to l.blockZ, + ] + } + return + } + plugin.debug { + val l = rightClicked.location + Lang[ + "click.no_handler", + "player" to player.name, + "hand" to hand.alias, + "item" to item, + "target" to entity, + "world" to player.world.name, + "x" to l.blockX, + "y" to l.blockY, + "z" to l.blockZ, ] } } @@ -222,45 +279,48 @@ object ClickListener : EListener(PL) { plugin.debug { val l = entity.location Lang[ - "click.pass", - "player" to remover.name, - "item" to item, - "target" to entity.type.name, - "world" to remover.world.name, - "x" to l.blockX, - "y" to l.blockY, - "z" to l.blockZ, - ] - } - return - } - isCancelled = true - plugin.debug { - val l = entity.location - Lang[ - "click.prevent", + "click.pass", "player" to remover.name, + "hand" to "主", "item" to item, "target" to entity.type.name, "world" to remover.world.name, "x" to l.blockX, "y" to l.blockY, "z" to l.blockZ, - ] + ] + } + return } - return - } - plugin.debug { - val l = entity.location - Lang[ - "click.pass", + isCancelled = true + plugin.debug { + val l = entity.location + Lang[ + "click.prevent", "player" to remover.name, + "hand" to "主", "item" to item, "target" to entity.type.name, "world" to remover.world.name, "x" to l.blockX, "y" to l.blockY, "z" to l.blockZ, + ] + } + return + } + plugin.debug { + val l = entity.location + Lang[ + "click.no_handler", + "player" to remover.name, + "hand" to "主", + "item" to item, + "target" to entity.type.name, + "world" to remover.world.name, + "x" to l.blockX, + "y" to l.blockY, + "z" to l.blockZ, ] } } @@ -285,14 +345,15 @@ object ClickListener : EListener(PL) { plugin.debug { val l = entity.location Lang[ - "click.pass", - "player" to damager.name, - "item" to item, - "target" to entity.type.name, - "world" to damager.world.name, - "x" to l.blockX, - "y" to l.blockY, - "z" to l.blockZ, + "click.pass", + "player" to damager.name, + "hand" to "主", + "item" to item, + "target" to entity.type.name, + "world" to damager.world.name, + "x" to l.blockX, + "y" to l.blockY, + "z" to l.blockZ, ] } return @@ -301,30 +362,34 @@ object ClickListener : EListener(PL) { plugin.debug { val l = entity.location Lang[ - "click.prevent", - "player" to damager.name, - "item" to item, - "target" to entityType.name, - "world" to damager.world.name, - "x" to l.blockX, - "y" to l.blockY, - "z" to l.blockZ, - ] - } - return - } - plugin.debug { - val l = entity.location - Lang[ - "click.pass", + "click.prevent", "player" to damager.name, + "hand" to "主", "item" to item, "target" to entityType.name, "world" to damager.world.name, "x" to l.blockX, "y" to l.blockY, "z" to l.blockZ, + ] + } + return + } + plugin.debug { + val l = entity.location + Lang[ + "click.no_handler", + "player" to damager.name, + "hand" to "主", + "item" to item, + "target" to entityType.name, + "world" to damager.world.name, + "x" to l.blockX, + "y" to l.blockY, + "z" to l.blockZ, ] } } + + private inline val EquipmentSlot.alias get() = if (this == EquipmentSlot.HAND) "主" else "副" } \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5d980ef..4cfda8b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -242,14 +242,23 @@ global: # 反向匹配正则示例(方块)(除了其中写到的其他都匹配): "(?!(IRON_ORE|DIAMOND_ORE)$).+" # 匹配全部示例(匹配所有): ".*" prevent_click_block: + # - item: ".*" # 玩家点击方块时的物品类型匹配正则 .* 会匹配任意物品 + # block: ".*" # 玩家点击的方块类型匹配正则 .* 匹配任意方块 若不写该条, 则匹配点击空气的情况(若为空则永不触发挖掘) + # type: right # 点击的类型 (left/right/all) left对应挖掘, right对应点击 + + # 以下内容为示例, 若有需要请自行修改 + # 以下这条配置的效果是阻止玩家使用刷怪蛋点击刷怪笼 -# - # 玩家点击方块时的物品类型匹配正则 -# item: "(?i)[a-z]+_spawn_egg" -# # 玩家点击的方块类型匹配正则 -# block: "(?i)spawner" -# # 点击的类型 (left/right/all) -# # left对应挖掘, right对应点击 -# type: right + # - item: "(?i)[a-z]+_spawn_egg" + # block: "(?i)spawner" + # type: right + + # 以下这条配置的效果是阻止玩家用空瓶装水 装水的时候会有点击方块 也会有点击空气 + # - item: "GLASS_BOTTLE" # 匹配空手右键 + # type: right + # - item: "GLASS_BOTTLE" # 匹配点击方块 + # block: ".*" + # type: right # 阻止玩家使用物品点击实体 # 空手时item为AIR @@ -261,14 +270,20 @@ global: # 反向匹配正则示例(实体)(除了其中写到的其他都匹配): "(?!(SPIDER|ZOMBIE)$).+" # 匹配全部示例(匹配所有): ".*" prevent_click_entity: + - item: "(?i)carrot" # 玩家点击实体时的物品类型匹配正则 + entity: "(?i)pig" # 玩家点击的方块类型匹配正则 + type: right # 点击的类型 (left/right/all) left对应伤害, right对应点击 + + # 以下内容为示例, 若有需要请自行修改 + # 以下这条配置的效果是阻止玩家使用胡萝卜点击猪 -# - # 玩家点击方块时的物品类型匹配正则 -# item: "(?i)carrot" -# # 玩家点击的方块类型匹配正则 -# entity: "(?i)pig" -# # 点击的类型 (left/right/all) -# # left对应伤害, right对应点击 -# type: right + # - # 玩家点击方块时的物品类型匹配正则 + # item: "(?i)carrot" + # # 玩家点击的方块类型匹配正则 + # entity: "(?i)pig" + # # 点击的类型 (left/right/all) + # # left对应伤害, right对应点击 + # type: right # 世界设置 # 可以自行扩展, 配置格式与global的一致 diff --git a/src/main/resources/lang.yml b/src/main/resources/lang.yml index b0f9db6..909371f 100644 --- a/src/main/resources/lang.yml +++ b/src/main/resources/lang.yml @@ -113,8 +113,14 @@ weather: thunder: "雷暴" click: - prevent: "阻止玩家{player}手持{item}点击{target}(world: {world}, x: {x}, y: {y}, z: {z})" - pass: "未处理玩家{player}手持{item}点击{target}(world: {world}, x: {x}, y: {y}, z: {z})" + prevent: "阻止玩家{player}{hand}手持{item}点击{target}(world: {world}, x: {x}, y: {y}, z: {z})" + pass: "未处理有boom.bypass.block权限的玩家{player}{hand}手持{item}点击{target}(world: {world}, x: {x}, y: {y}, z: {z})" + no_handler: "未处理玩家{player}{hand}手持{item}点击{target}(world: {world}, x: {x}, y: {y}, z: {z})" + +click_air: + prevent: "阻止玩家{player}{hand}手持{item}点击空气" + pass: "未处理有boom.bypass.block权限的玩家{player}{hand}手持{item}点击空气" + no_handler: "未处理玩家{player}{hand}手持{item}点击空气" player_damage: prevent: "阻止玩家{player}受到伤害(world: {world}, x: {x}, y: {y}, z: {z})"