Skip to content

Commit 779088f

Browse files
committed
feat: add script execution limits, permission/group checks, and script location visualization
1 parent 967fc33 commit 779088f

6 files changed

Lines changed: 90 additions & 3 deletions

File tree

‎src/main/kotlin/com/github/albardoo02/scriptBlockNext/command/ScriptCommand.kt‎

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,27 @@ class ScriptCommand: CommandExecutor, TabCompleter {
246246
ScriptManager.addMode.remove(sender.uniqueId)
247247
sender.sendMsg("mode_removal", "type" to type)
248248
}
249+
"show" -> {
250+
val world = sender.world
251+
val scriptsInWorld = ScriptManager.scripts[type]?.filter { it.key.world == world.name }
252+
if (scriptsInWorld.isNullOrEmpty()) {
253+
sender.sendMsg("error_no_script_info", "type" to type)
254+
return true
255+
}
256+
sender.sendMsg("info_show_start", "type" to type, "count" to scriptsInWorld.size.toString())
257+
var ticks = 0
258+
val taskId = Bukkit.getScheduler().runTaskTimer(ScriptBlockNext.instance, Runnable {
259+
if (ticks > 200) return@Runnable // 10 seconds
260+
for ((locData, _) in scriptsInWorld) {
261+
val loc = org.bukkit.Location(world, locData.x + 0.5, locData.y + 0.5, locData.z + 0.5)
262+
world.spawnParticle(org.bukkit.Particle.VILLAGER_HAPPY, loc, 3, 0.3, 0.3, 0.3, 0.0)
263+
}
264+
ticks += 10
265+
}, 0L, 10L).taskId
266+
Bukkit.getScheduler().runTaskLater(ScriptBlockNext.instance, Runnable {
267+
Bukkit.getScheduler().cancelTask(taskId)
268+
}, 205L)
269+
}
249270
else -> sender.sendMsg("error_unknown_action", "action" to action)
250271
}
251272
return true
@@ -283,7 +304,7 @@ class ScriptCommand: CommandExecutor, TabCompleter {
283304

284305
if (args.size == 2 && first in listOf("interact", "break", "walk", "hit")) {
285306
if (!sender.hasPermission("scriptblocknext.command.$first")) return emptyList()
286-
return listOf("create", "add", "remove", "view", "info", "copy").filter { it.startsWith(args[1], ignoreCase = true) }
307+
return listOf("create", "add", "remove", "view", "info", "copy", "show").filter { it.startsWith(args[1], ignoreCase = true) }
287308
}
288309

289310
if (args.size >= 3 && first in listOf("interact", "break", "walk", "hit")) {
@@ -323,7 +344,8 @@ class ScriptCommand: CommandExecutor, TabCompleter {
323344
"[@oldCooldown:", $$"[$item:", "[@command ", "[@msg ", "@message ", "[@player ",
324345
"[@server ", "[@console ", "[@bypass ", "[@sound:", "[@title:", "[@actionBar:",
325346
"[@velocity:", "[@checkpoint]", "[@return]", "[@noFall:", "[@potion:",
326-
"[@if ", "[@hand:", "[@bypassPerm:"
347+
"[@if ", "[@hand:", "[@bypassPerm:", "[@perm:", "[@amount:", "[@globalAmount:",
348+
"[@cancelEvent:true]", "[@cancelEvent:false]"
327349
)
328350

329351
if (VaultManager.isHooked) {

‎src/main/kotlin/com/github/albardoo02/scriptBlockNext/hook/LuckPermsManager.kt‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,15 @@ object LuckPermsManager {
3737
} catch (e: Exception) {
3838
}
3939
}
40+
41+
fun hasGroup(player: Player, group: String): Boolean {
42+
if (!isHooked) return false
43+
try {
44+
val api = LuckPermsProvider.get()
45+
val user = api.userManager.getUser(player.uniqueId) ?: return false
46+
return user.getNodes().stream().anyMatch { it is InheritanceNode && it.groupName.equals(group, ignoreCase = true) }
47+
} catch (e: Exception) {
48+
return false
49+
}
50+
}
4051
}

‎src/main/kotlin/com/github/albardoo02/scriptBlockNext/listener/InteractListener.kt‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,14 @@ class InteractListener: Listener {
6767

6868
if (player.isSneaking && (player.isOp || player.hasPermission("scriptblocknext.admin"))) return
6969

70-
event.isCancelled = true
70+
val hasCancelFalse = scriptData.commands.any {
71+
val cleanCmd = it.removePrefix("!")
72+
cleanCmd.startsWith("@cancelEvent:false", ignoreCase = true)
73+
}
74+
if (!hasCancelFalse) {
75+
event.isCancelled = true
76+
}
77+
7178
ScriptExecutor.run(player, scriptData, location)
7279
}
7380
}

‎src/main/kotlin/com/github/albardoo02/scriptBlockNext/listener/ScriptExecutor.kt‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ object ScriptExecutor {
2626

2727
private val playerCooldowns = mutableMapOf<UUID, MutableMap<Location, Long>>()
2828
private val globalCooldowns = mutableMapOf<Location, Long>()
29+
private val playerAmounts = mutableMapOf<UUID, MutableMap<Location, Int>>()
30+
private val globalAmounts = mutableMapOf<Location, Int>()
2931

3032
fun run(player: Player, scriptData: ScriptData, location: Location, actionType: String = "") {
3133
if (ScriptBlockNext.instance.config.getBoolean("output_script_log", false)) {
@@ -132,6 +134,28 @@ object ScriptExecutor {
132134
val channelId = cleanCmd.substringAfter(":")
133135
val isInChannel = DiscordSRVManager.getVoiceChannelId(player.uniqueId) == channelId
134136
if (if (isInverted) isInChannel else !isInChannel) return
137+
} else if (cleanCmd.startsWith("@perm:", ignoreCase = true)) {
138+
val perm = cleanCmd.substringAfter(":")
139+
val hasPerm = player.hasPermission(perm)
140+
if (if (isInverted) hasPerm else !hasPerm) return
141+
} else if (cleanCmd.startsWith("@group:", ignoreCase = true)) {
142+
val group = cleanCmd.substringAfter(":")
143+
val hasGroup = LuckPermsManager.hasGroup(player, group)
144+
if (if (isInverted) hasGroup else !hasGroup) return
145+
} else if (cleanCmd.startsWith("@amount:", ignoreCase = true)) {
146+
val amountLimit = cleanCmd.substringAfter(":").toIntOrNull() ?: 0
147+
val used = playerAmounts[player.uniqueId]?.get(location) ?: 0
148+
if (used >= amountLimit) {
149+
player.sendMsg("error_amount_limit", "limit" to amountLimit.toString())
150+
return
151+
}
152+
} else if (cleanCmd.startsWith("@globalAmount:", ignoreCase = true)) {
153+
val amountLimit = cleanCmd.substringAfter(":").toIntOrNull() ?: 0
154+
val used = globalAmounts[location] ?: 0
155+
if (used >= amountLimit) {
156+
player.sendMsg("error_global_amount_limit", "limit" to amountLimit.toString())
157+
return
158+
}
135159
} else if (cleanCmd.startsWith("@if ")) {
136160
val ifArgs = cleanCmd.substringAfter("@if ").split(" ", limit = 4)
137161
if (ifArgs.size >= 3) {
@@ -185,6 +209,18 @@ object ScriptExecutor {
185209
MythicMobsManager.takeMythicItem(player, mythicId, amount)
186210
}
187211

212+
// Increment amounts
213+
for (line in scriptData.commands) {
214+
val cmd = PlaceholderManager.replace(player, line)
215+
val cleanCmd = cmd.removePrefix("!")
216+
if (cleanCmd.startsWith("@amount:", ignoreCase = true)) {
217+
val map = playerAmounts.getOrPut(player.uniqueId) { mutableMapOf() }
218+
map[location] = (map[location] ?: 0) + 1
219+
} else if (cleanCmd.startsWith("@globalAmount:", ignoreCase = true)) {
220+
globalAmounts[location] = (globalAmounts[location] ?: 0) + 1
221+
}
222+
}
223+
188224
executeCommands(player, scriptData.commands, 0)
189225
}
190226

@@ -202,6 +238,11 @@ object ScriptExecutor {
202238
activeCmd.startsWith("@oldCooldown:") || activeCmd.startsWith("@action:") ||
203239
activeCmd.startsWith("@blockType:") ||
204240
activeCmd.startsWith("@hand:") ||
241+
activeCmd.startsWith("@perm:", ignoreCase = true) ||
242+
activeCmd.startsWith("@group:", ignoreCase = true) ||
243+
activeCmd.startsWith("@amount:", ignoreCase = true) ||
244+
activeCmd.startsWith("@globalAmount:", ignoreCase = true) ||
245+
activeCmd.startsWith("@cancelEvent:", ignoreCase = true) ||
205246
activeCmd.startsWith("@mmid:", ignoreCase = true) ||
206247
activeCmd.startsWith("@dRole:", ignoreCase = true) || activeCmd.startsWith("@dChannel:", ignoreCase = true)) continue
207248
if (activeCmd.startsWith("@delay:")) {

‎src/main/resources/messages/lang_en.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ error_cooldown: "&cYou are on cooldown (Remaining: {time}s)"
99
error_look_at_block: "&cPlease look at a block."
1010
error_no_script_info: "&cNo {type} script is set on this block."
1111
error_selection_incomplete: "&cError: Selection is incomplete. Set Pos1 and Pos2 with the tool."
12+
error_amount_limit: "&cYou have reached the execution limit ({limit} times) for this script."
13+
error_global_amount_limit: "&cThis script has reached the global execution limit ({limit} times)."
1214

1315
# Command Usage
1416
cmd_usage_main: "&cUsage: /sbn <type> <action> [args] or /sbn reload"
@@ -38,6 +40,7 @@ info_creator: "&7Creator: &b{creator}"
3840
info_commands_header: "&7Commands:"
3941
info_command_line: "&8[&7{index}&8] &f{command}"
4042
info_footer: "&e=========================="
43+
info_show_start: "&aShowing locations of {type} scripts with particles for 10 seconds (Total: {count})."
4144

4245
# Clipboard & Paste
4346
error_empty_clipboard: "&cError: Clipboard is empty. Copy a script first using /sbn <type> copy."

‎src/main/resources/messages/lang_ja.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ error_cooldown: "&cクールダウン中です(残り:{time}秒)"
99
error_look_at_block: "&c視点をブロックに合わせて下さい。"
1010
error_no_script_info: "&cこのブロックに{type}のスクリプトは設定されていません。"
1111
error_selection_incomplete: "&cエラー: 範囲が正しく選択されていません。ツールでPos1とPos2を設定してください。"
12+
error_amount_limit: "&cこのスクリプトは実行上限({limit}回)に達しています。"
13+
error_global_amount_limit: "&cこのスクリプトはサーバー全体での実行上限({limit}回)に達しています。"
1214

1315
# コマンドの使い方
1416
cmd_usage_main: "&c使用方法: /sbn <type> <action> [args] または /sbn reload"
@@ -38,6 +40,7 @@ info_creator: "&7登録者: &b{creator}"
3840
info_commands_header: "&7コマンド一覧:"
3941
info_command_line: "&8[&7{index}&8] &f{command}"
4042
info_footer: "&e=========================="
43+
info_show_start: "&a{type} のスクリプト位置を10秒間パーティクルで表示します (計{count}個)。"
4144

4245
# クリップボード・ペースト
4346
error_empty_clipboard: "&cエラー: クリップボードが空です。先に /sbn <type> copy でスクリプトをコピーしてください。"

0 commit comments

Comments
 (0)