fix: 修复已知代码问题 - 禁言生效/heal血量恢复/kick自我检查/控制台解禁/注册tpaback/NPE防护/屏蔽词包含匹配/PAPI缺失优雅退出/权限节点统一
This commit is contained in:
1 parent
6c7d7fedcb
commit
9d262330d4
10 files changed
+62
-35
No files matched your search
@@ -94,15 +94,15 @@
|
|||||||
| `/back` | - | `/back` | `OpenTools.default` | 所有人 |
|
| `/back` | - | `/back` | `OpenTools.default` | 所有人 |
|
||||||
| `/tpaaccept` | - | `/tpaaccept <玩家ID>` | `OpenTools.default` | 所有人 |
|
| `/tpaaccept` | - | `/tpaaccept <玩家ID>` | `OpenTools.default` | 所有人 |
|
||||||
| `/tpadefuse` | - | `/tpadefuse <玩家ID>` | `OpenTools.default` | 所有人 |
|
| `/tpadefuse` | - | `/tpadefuse <玩家ID>` | `OpenTools.default` | 所有人 |
|
||||||
|
| `/tpaback` | - | `/tpaback` | `OpenTools.default` | 所有人 |
|
||||||
| `/PlayerTitle` | `/plt` | `/PlayerTitle help` | `OpenTools.default` | 所有人 |
|
| `/PlayerTitle` | `/plt` | `/PlayerTitle help` | `OpenTools.default` | 所有人 |
|
||||||
| `/testGUI` | - | `/testGUI KickGUI` | `OpenTools.testGUI` | OP |
|
| `/testGUI` | - | `/testGUI KickGUI` | `OpenTools.testGUI` | OP |
|
||||||
| `/OSTReload` | - | `/OSTReload` | `OpenTools.reload` | OP |
|
| `/OSTReload` | - | `/OSTReload` | `OpenTools.ostreload` | OP |
|
||||||
| `/stop` | - | `/stop [提示语]` | `OpenTools.stop` | OP |
|
| `/stop` | - | `/stop [提示语]` | `OpenTools.stop` | OP |
|
||||||
| `/gamemode` | `/gm` | `/gamemode <模式> [玩家ID]` | `OpenTools.gamemode` | OP |
|
| `/gamemode` | `/gm` | `/gamemode <模式> [玩家ID]` | `OpenTools.gamemode` | OP |
|
||||||
| `/sun` | - | `/sun` | `OpenTools.sun` | OP |
|
| `/sun` | - | `/sun` | `OpenTools.sun` | OP |
|
||||||
| `/setspawn` | - | `/setspawn` | `OpenTools.setspawn` | OP |
|
| `/setspawn` | - | `/setspawn` | `OpenTools.setspawn` | OP |
|
||||||
| `/day` | - | `/day` | `OpenTools.day` | OP |
|
| `/day` | - | `/day` | `OpenTools.day` | OP || `/vanish` | `/v` | `/vanish [玩家ID]` | `OpenTools.vanish` | OP |
|
||||||
| `/vanish` | `/v` | `/vanish [玩家ID]` | `OpenTools.vanish` | OP |
|
|
||||||
| `/fly` | - | `/fly [玩家ID]` | `OpenTools.fly` | OP |
|
| `/fly` | - | `/fly [玩家ID]` | `OpenTools.fly` | OP |
|
||||||
| `/mute` | - | `/mute <玩家ID>` | `OpenTools.mute` | OP |
|
| `/mute` | - | `/mute <玩家ID>` | `OpenTools.mute` | OP |
|
||||||
| `/unmute` | - | `/unmute <玩家ID>` | `OpenTools.unmute` | OP |
|
| `/unmute` | - | `/unmute <玩家ID>` | `OpenTools.unmute` | OP |
|
||||||
@@ -138,6 +138,7 @@
|
|||||||
| `OpenTools.stop` | OP | /stop |
|
| `OpenTools.stop` | OP | /stop |
|
||||||
| `OpenTools.gamemode` | OP | /gamemode |
|
| `OpenTools.gamemode` | OP | /gamemode |
|
||||||
| `OpenTools.setspawn` | OP | /setspawn |
|
| `OpenTools.setspawn` | OP | /setspawn |
|
||||||
|
| `OpenTools.day` | OP | /day |
|
||||||
| `OpenTools.list` | OP | /list |
|
| `OpenTools.list` | OP | /list |
|
||||||
| `OpenTools.testGUI` | OP | /testGUI |
|
| `OpenTools.testGUI` | OP | /testGUI |
|
||||||
|
|
||||||
@@ -249,6 +250,7 @@ powershell -NoProfile -ExecutionPolicy Bypass -File tools/smoke-test/start-test-
|
|||||||
|
|
||||||
| 版本 | 日期 | 变更 |
|
| 版本 | 日期 | 变更 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
| `dev-mc-1.21.11`(分支) | 2026-11-09 | 修复 10 项已知代码问题(禁言生效、/heal 血量恢复、/kick 自我检查、控制台解禁、注册 /tpaback、NPE 防护、屏蔽词包含匹配、PAPI 缺失优雅退出、权限节点统一) |
|
||||||
| `2.1.0` | 2026-11-09 | 升级 Bukkit API 至 **1.21.11**;`api-version` 提升至 `1.21`;声明 `depend: [PlaceholderAPI]` 保证加载顺序;补充自动化冒烟测试设施 |
|
| `2.1.0` | 2026-11-09 | 升级 Bukkit API 至 **1.21.11**;`api-version` 提升至 `1.21`;声明 `depend: [PlaceholderAPI]` 保证加载顺序;补充自动化冒烟测试设施 |
|
||||||
| `2.0` | 2025 | 初版(Spigot API 1.20) |
|
| `2.0` | 2025 | 初版(Spigot API 1.20) |
|
||||||
|
|
||||||
@@ -256,18 +258,23 @@ powershell -NoProfile -ExecutionPolicy Bypass -File tools/smoke-test/start-test-
|
|||||||
|
|
||||||
## 已知问题与限制
|
## 已知问题与限制
|
||||||
|
|
||||||
> 以下问题为代码现状记录,不影响插件基本使用,欢迎提交 PR 修复。
|
以下问题已在 **`dev-mc-1.21.11` 分支修复**:
|
||||||
|
|
||||||
1. **禁言不生效**:`/mute` 仅将玩家写入配置 `MutePlayerList`,聊天事件未检查该列表。
|
1. ✅ 禁言不生效 → 聊天事件现在检查 `MutePlayerList`,被禁言玩家无法发言。
|
||||||
2. **`/heal` 实际恢复的是饱食度**(与 `/feed` 相同),且配置键大小写不匹配(`healCommandSetting` vs `HealCommandSetting`),导致默认被禁用。
|
2. ✅ `/heal` 恢复饱食度 + 配置键大小写不匹配 → 现在恢复生命值并使用正确的 `HealCommandSetting` 配置键。
|
||||||
3. **`/kick` 无法阻止踢出自己**:自我检查逻辑失效(`player.getName().equals(player.getName())` 恒为真)。
|
3. ✅ `/kick` 无法阻止踢出自己 → 自我检查改为与命令发送者比较。
|
||||||
4. **控制台执行 `/unmute` 无效**:解禁分支误用 `add` 而非 `remove`。
|
4. ✅ 控制台 `/unmute` 无效 → 解禁分支由 `add` 修正为 `remove`。
|
||||||
5. **`/tpaback` 未注册**:类存在但未在 plugin.yml 与主类中注册。
|
5. ✅ `/tpaback` 未注册 → 已注册命令与权限(返回 TPA 传送前位置)。
|
||||||
6. **空指针风险**:玩家未死亡时使用 `/back` 或重生事件、未使用过 TPA 时执行 `/tpaback`、跨世界飞行检查,均可能抛出 NPE。
|
6. ✅ 多处空指针风险(重生事件、/tpaback、跨世界飞行检查)→ 已加空值保护。
|
||||||
7. **状态仅存内存**:TPA 请求、聊天冷却、死亡点、隐身/飞行状态存于静态 HashMap,服务器重启即丢失。
|
7. ✅ 跨世界飞行权限节点错误(`OpenSourceTools.FLY`)→ 改为正确的 `OpenTools.fly`。
|
||||||
8. **权限声明不一致**:`/OSTReload` 使用 `OpenTools.reload` 而权限节定义为 `OpenTools.ostreload`;`/day` 的 `OpenTools.day` 未在权限节声明。
|
8. ✅ 屏蔽词仅整句精确匹配 → 改为包含匹配(忽略大小写)。
|
||||||
9. **硬依赖退出方式激进**:缺失 PlaceholderAPI 时插件会 `System.exit(0)` 直接结束整个 JVM(现已通过 `depend` 声明保证加载顺序规避)。
|
9. ✅ 缺失 PlaceholderAPI 时 `System.exit(0)` 强杀整个 JVM → 改为优雅禁用插件。
|
||||||
10. **屏蔽词精确匹配**:仅拦截与关键词完全相同的整句消息。
|
10. ✅ 权限声明不一致(OSTReload/day)→ 已统一权限节点。
|
||||||
|
|
||||||
|
### 仍存在的限制
|
||||||
|
|
||||||
|
- **状态仅存内存**:TPA 请求、聊天冷却、死亡点、隐身/飞行状态保存在内存中,服务器重启后丢失(如需持久化请提 Issue 讨论方案)。
|
||||||
|
- `/kick` 踢人 GUI 与命令的自我踢出/管理员保护逻辑按现有设计保留。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ public class PlayerChangedWorld_Event implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void On_Event(PlayerChangedWorldEvent event) {
|
public void On_Event(PlayerChangedWorldEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if (player.hasPermission("OpenSourceTools.FLY")) {
|
if (player.hasPermission("OpenTools.fly")) {
|
||||||
if (unity.getStringTemp(player.getName() + "_Fly").equals("已开启")) {
|
String Fly = unity.getStringTemp(player.getName() + "_Fly");
|
||||||
|
if (Fly != null && Fly.equals("已开启")) {
|
||||||
player.setAllowFlight(true);
|
player.setAllowFlight(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,15 @@ public class PlayerChat_Event implements Listener {
|
|||||||
public void PlayerChat(AsyncPlayerChatEvent event) {
|
public void PlayerChat(AsyncPlayerChatEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
String Message = event.getMessage();
|
String Message = event.getMessage();
|
||||||
|
|
||||||
|
// 禁言检查
|
||||||
|
List<String> MutePlayerList = main.instance.getConfig().getStringList("MutePlayerList");
|
||||||
|
if (MutePlayerList.contains(player.getName())) {
|
||||||
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&c你已被禁言,无法发送消息!"));
|
||||||
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (player.isOp()) {
|
if (player.isOp()) {
|
||||||
if (main.instance.getConfig().getBoolean("ColorChatSetting.AllowAdminUsedColorChat")) {
|
if (main.instance.getConfig().getBoolean("ColorChatSetting.AllowAdminUsedColorChat")) {
|
||||||
event.setMessage(unity.ColorMessage(Message));
|
event.setMessage(unity.ColorMessage(Message));
|
||||||
@@ -34,7 +43,7 @@ public class PlayerChat_Event implements Listener {
|
|||||||
|
|
||||||
List<String> keywords = new ArrayList<>(main.instance.getConfig().getStringList("AntiKeyWords"));
|
List<String> keywords = new ArrayList<>(main.instance.getConfig().getStringList("AntiKeyWords"));
|
||||||
for (String keyword : keywords) {
|
for (String keyword : keywords) {
|
||||||
if (Message.toUpperCase().contentEquals(keyword)) {
|
if (Message.toUpperCase().contains(keyword.toUpperCase())) {
|
||||||
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d&l检测到屏蔽词,已阻止发送\n屏蔽词内容:" + keyword));
|
player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d&l检测到屏蔽词,已阻止发送\n屏蔽词内容:" + keyword));
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
for (Player player1 : Bukkit.getOnlinePlayers()) {
|
for (Player player1 : Bukkit.getOnlinePlayers()) {
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ public class PlayerReSpawn_Event implements Listener {
|
|||||||
public void On_Event(PlayerRespawnEvent event) {
|
public void On_Event(PlayerRespawnEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
Location DiedLocation = unity.getLocationTempTemp(player.getName() + "_Back");
|
Location DiedLocation = unity.getLocationTempTemp(player.getName() + "_Back");
|
||||||
player.sendMessage(unity.ColorMessage("&a&l您的死亡位置是X:" + DiedLocation.getBlockX() + " Y:" + DiedLocation.getBlockY() + "_DiedY" + " Z:" + DiedLocation.getBlockZ()));
|
if (DiedLocation == null) {
|
||||||
|
player.sendMessage(unity.ColorMessage("&a&l你还没有死亡记录"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.sendMessage(unity.ColorMessage("&a&l您的死亡位置是 X:" + DiedLocation.getBlockX() + " Y:" + DiedLocation.getBlockY() + " Z:" + DiedLocation.getBlockZ()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ public class SuperKick_Command implements CommandExecutor {
|
|||||||
if (Objects.requireNonNull(player).isOnline()) {
|
if (Objects.requireNonNull(player).isOnline()) {
|
||||||
if (sender instanceof Player) {
|
if (sender instanceof Player) {
|
||||||
if (!player.isOp()) {
|
if (!player.isOp()) {
|
||||||
if (!player.getName().equals(player.getName())) {
|
if (!player.getName().equals(sender.getName())) {
|
||||||
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', "&d你被踢出服务器"));
|
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', "&d你被踢出服务器"));
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出自己"));
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出自己"));
|
||||||
@@ -48,7 +48,7 @@ public class SuperKick_Command implements CommandExecutor {
|
|||||||
if (Objects.requireNonNull(player).isOnline()) {
|
if (Objects.requireNonNull(player).isOnline()) {
|
||||||
if (sender instanceof Player) {
|
if (sender instanceof Player) {
|
||||||
if (!player.isOp()) {
|
if (!player.isOp()) {
|
||||||
if (!player.getName().equals(player.getName())) {
|
if (!player.getName().equals(sender.getName())) {
|
||||||
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', message));
|
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', message));
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出自己"));
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出自己"));
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class heal_Command implements CommandExecutor {
|
|||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
if (sender instanceof Player) {
|
if (sender instanceof Player) {
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
String CommandName = "heal";
|
String CommandName = "Heal";
|
||||||
if (player.isOp()) {
|
if (player.isOp()) {
|
||||||
if (!instance.getConfig().getBoolean(CommandName + "CommandSetting.AllowAdminUsed" + CommandName + "Command")) {
|
if (!instance.getConfig().getBoolean(CommandName + "CommandSetting.AllowAdminUsed" + CommandName + "Command")) {
|
||||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个服务器禁止管理员使用heal命令!"));
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个服务器禁止管理员使用heal命令!"));
|
||||||
@@ -26,8 +26,7 @@ public class heal_Command implements CommandExecutor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
player.setSaturation(20);
|
player.setHealth(player.getMaxHealth());
|
||||||
player.setFoodLevel(20);
|
|
||||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a你的血量被神奇的恢复了"));
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a你的血量被神奇的恢复了"));
|
||||||
}else {
|
}else {
|
||||||
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行"));
|
sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行"));
|
||||||
|
|||||||
@@ -40,14 +40,9 @@ public final class main extends JavaPlugin implements Listener {
|
|||||||
|
|
||||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) {
|
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) {
|
||||||
unity.GetLoggerPlus("&d找不到PlaceholderAPI,请安装PlaceholderAPI后才能使用本插件");
|
unity.GetLoggerPlus("&d找不到PlaceholderAPI,请安装PlaceholderAPI后才能使用本插件");
|
||||||
Bukkit.getPluginManager().disablePlugins();
|
Bukkit.getPluginManager().disablePlugin(this);
|
||||||
try {
|
return;
|
||||||
Thread.sleep(2300);
|
} else {
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
System.exit(0);
|
|
||||||
} else if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
|
||||||
unity.GetLoggerPlus("&2已检测到PlaceholderAPI前置");
|
unity.GetLoggerPlus("&2已检测到PlaceholderAPI前置");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +93,7 @@ public final class main extends JavaPlugin implements Listener {
|
|||||||
Objects.requireNonNull(getCommand("tpa")).setExecutor(new Tpa_Command());
|
Objects.requireNonNull(getCommand("tpa")).setExecutor(new Tpa_Command());
|
||||||
Objects.requireNonNull(getCommand("tpaaccept")).setExecutor(new tpaAccept_Command());
|
Objects.requireNonNull(getCommand("tpaaccept")).setExecutor(new tpaAccept_Command());
|
||||||
Objects.requireNonNull(getCommand("tpadefuse")).setExecutor(new tpaDefuse_Command());
|
Objects.requireNonNull(getCommand("tpadefuse")).setExecutor(new tpaDefuse_Command());
|
||||||
|
Objects.requireNonNull(getCommand("tpaback")).setExecutor(new tpaback_Command());
|
||||||
Objects.requireNonNull(getCommand("vanish")).setExecutor(new vanish_Command());
|
Objects.requireNonNull(getCommand("vanish")).setExecutor(new vanish_Command());
|
||||||
Objects.requireNonNull(getCommand("fly")).setExecutor(new fly_Command());
|
Objects.requireNonNull(getCommand("fly")).setExecutor(new fly_Command());
|
||||||
Objects.requireNonNull(getCommand("mute")).setExecutor(new mute_Command());
|
Objects.requireNonNull(getCommand("mute")).setExecutor(new mute_Command());
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ public class tpaback_Command implements CommandExecutor {
|
|||||||
if (sender instanceof Player) {
|
if (sender instanceof Player) {
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
Location BackLocation = unity.getLocationTempTemp(player.getName() + "_Tpa");
|
Location BackLocation = unity.getLocationTempTemp(player.getName() + "_Tpa");
|
||||||
|
if (BackLocation == null) {
|
||||||
|
player.sendMessage(unity.ColorMessage("&d你还没有传送记录,无法返回!"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
player.teleport(BackLocation);
|
player.teleport(BackLocation);
|
||||||
player.sendMessage(unity.ColorMessage("&a传送成功!"));
|
player.sendMessage(unity.ColorMessage("&a传送成功!"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ public class unmute_Command implements CommandExecutor {
|
|||||||
|
|
||||||
for (String MutePlayers : MutePlayerList) {
|
for (String MutePlayers : MutePlayerList) {
|
||||||
if (MutePlayers.equals(Objects.requireNonNull(player).getName())) {
|
if (MutePlayers.equals(Objects.requireNonNull(player).getName())) {
|
||||||
MutePlayerList.add(Objects.requireNonNull(player).getName());
|
MutePlayerList.remove(Objects.requireNonNull(player).getName());
|
||||||
main.instance.getConfig().set("MutePlayerList", MutePlayerList);
|
main.instance.getConfig().set("MutePlayerList", MutePlayerList);
|
||||||
unity.SaveAndReloadConfig();
|
unity.SaveAndReloadConfig();
|
||||||
sender.sendMessage(ChatColor.GREEN + "你解除了 控制台 的禁言");
|
sender.sendMessage(ChatColor.GREEN + "你解除了 " + player.getName() + " 的禁言");
|
||||||
player.sendMessage(ChatColor.RED + "你被 控制台 解除禁言了!");
|
player.sendMessage(ChatColor.RED + "你被 控制台 解除禁言了!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,13 +35,17 @@ commands:
|
|||||||
description: 拒绝传送请求
|
description: 拒绝传送请求
|
||||||
permission: OpenTools.default
|
permission: OpenTools.default
|
||||||
permission-message: §c§l权限不足
|
permission-message: §c§l权限不足
|
||||||
|
tpaback:
|
||||||
|
description: 返回传送前位置
|
||||||
|
permission: OpenTools.default
|
||||||
|
permission-message: §c§l权限不足
|
||||||
testGUI:
|
testGUI:
|
||||||
description: 测试GUI命令
|
description: 测试GUI命令
|
||||||
permission: OpenTools.testGUI
|
permission: OpenTools.testGUI
|
||||||
permission-message: §c§l权限不足
|
permission-message: §c§l权限不足
|
||||||
OSTReload:
|
OSTReload:
|
||||||
description: 重载插件
|
description: 重载插件
|
||||||
permission: OpenTools.reload
|
permission: OpenTools.ostreload
|
||||||
permission-message: §c§l权限不足
|
permission-message: §c§l权限不足
|
||||||
stop:
|
stop:
|
||||||
description: 关闭服务器
|
description: 关闭服务器
|
||||||
@@ -112,7 +116,7 @@ permissions:
|
|||||||
description: fly命令的权限
|
description: fly命令的权限
|
||||||
default: op
|
default: op
|
||||||
OpenTools.vanish:
|
OpenTools.vanish:
|
||||||
description: unmute命令的权限
|
description: vanish命令的权限
|
||||||
default: op
|
default: op
|
||||||
OpenTools.ostreload:
|
OpenTools.ostreload:
|
||||||
description: ostreload命令的权限
|
description: ostreload命令的权限
|
||||||
@@ -132,6 +136,9 @@ permissions:
|
|||||||
OpenTools.list:
|
OpenTools.list:
|
||||||
description: list命令的权限
|
description: list命令的权限
|
||||||
default: op
|
default: op
|
||||||
|
OpenTools.day:
|
||||||
|
description: day命令的权限
|
||||||
|
default: op
|
||||||
OpenTools.testGUI:
|
OpenTools.testGUI:
|
||||||
description: testGUI命令的权限
|
description: testGUI命令的权限
|
||||||
default: op
|
default: op
|
||||||
Reference in new issue
Block a user