1.0.1:Fix bug:[21:01:10 INFO]: [PBL] §a========================================
[21:01:10 INFO]: [PBL] §ePlayerBlockLife v1.0.1-1.20.4 已启用
[21:01:10 INFO]: [PBL] §e作者: [YourName]
[21:01:10 INFO]: [PBL] §a========================================
This commit is contained in:
@@ -17,21 +17,41 @@ public class AdminCommands implements CommandExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
if (!sender.hasPermission("playerblocklife.admin")) {
|
MessageManager msgManager = plugin.getMessageManager();
|
||||||
sender.sendMessage("§c你没有权限使用此命令!");
|
ConfigManager config = plugin.getConfigManager();
|
||||||
|
|
||||||
|
String commandName = command.getName().toLowerCase();
|
||||||
|
|
||||||
|
// 检查命令是否启用
|
||||||
|
if (!config.isCommandEnabled(commandName)) {
|
||||||
|
String message = msgManager.getMessage("game.errors.command_disabled",
|
||||||
|
"&c此命令已被禁用!");
|
||||||
|
sender.sendMessage(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查管理员权限和配置
|
||||||
|
if (!sender.hasPermission("playerblocklife.admin") || config.isAdminOnly(commandName)) {
|
||||||
|
String message = msgManager.getMessage("game.errors.no_permission",
|
||||||
|
"&c你没有权限使用此命令!");
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.getName().equalsIgnoreCase("pblreload")) {
|
if (commandName.equals("pblreload")) {
|
||||||
// 调用插件的完整重载方法
|
// 调用插件的完整重载方法
|
||||||
plugin.reloadPluginConfig();
|
plugin.reloadPluginConfig();
|
||||||
sender.sendMessage("§a插件配置已完全重载!");
|
String message = msgManager.getCommandMessage("pblreload", "success",
|
||||||
|
"&a配置已重载!");
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.getName().equalsIgnoreCase("pbldelete")) {
|
if (commandName.equals("pbldelete")) {
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
sender.sendMessage("§c用法: /pbldelete <玩家名>");
|
String usage = msgManager.getCommandMessage("pbldelete", "usage",
|
||||||
|
"&c用法: /pbldelete <玩家>");
|
||||||
|
sender.sendMessage(usage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,43 +66,57 @@ public class AdminCommands implements CommandExecutor {
|
|||||||
try {
|
try {
|
||||||
targetId = Bukkit.getOfflinePlayer(targetName).getUniqueId();
|
targetId = Bukkit.getOfflinePlayer(targetName).getUniqueId();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
sender.sendMessage("§c找不到玩家: " + targetName);
|
String message = msgManager.getMessage("game.errors.player_not_found",
|
||||||
|
"&c找不到玩家: {player}");
|
||||||
|
message = message.replace("{player}", targetName);
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin.getBlockManager().clearPlayerBlocks(targetId);
|
plugin.getBlockManager().clearPlayerBlocks(targetId);
|
||||||
sender.sendMessage("§a已删除玩家 " + targetName + " 的生命方块");
|
String message = msgManager.getCommandMessage("pbldelete", "success",
|
||||||
|
"&a已删除玩家 {player} 的生命方块!");
|
||||||
|
message = message.replace("{player}", targetName);
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.getName().equalsIgnoreCase("pblrevive")) {
|
if (commandName.equals("pblrevive")) {
|
||||||
Player target;
|
Player target;
|
||||||
|
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
sender.sendMessage("§c控制台使用时必须指定玩家名: /pblrevive <玩家名>");
|
String usage = msgManager.getCommandMessage("pblrevive", "usage",
|
||||||
|
"&c用法: /pblrevive [玩家]");
|
||||||
|
sender.sendMessage(usage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
target = (Player) sender;
|
target = (Player) sender;
|
||||||
} else {
|
} else {
|
||||||
target = Bukkit.getPlayer(args[0]);
|
target = Bukkit.getPlayer(args[0]);
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
sender.sendMessage("§c玩家不存在或不在线!");
|
String message = msgManager.getMessage("game.errors.player_offline",
|
||||||
|
"&c玩家 {player} 不在线!");
|
||||||
|
message = message.replace("{player}", args[0]);
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plugin.getLifeSystem() != null) {
|
if (plugin.getLifeSystem() != null) {
|
||||||
plugin.getLifeSystem().revivePlayer(target);
|
plugin.getLifeSystem().revivePlayer(target);
|
||||||
sender.sendMessage("§a玩家 " + target.getName() + " 已复活!");
|
String message = msgManager.getCommandMessage("pblrevive", "success",
|
||||||
|
"&a玩家 {player} 已复活!");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
sender.sendMessage(message);
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage("§c复活失败:生命系统未初始化");
|
sender.sendMessage("§c复活失败:生命系统未初始化");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.getName().equalsIgnoreCase("pblstats")) {
|
if (commandName.equals("pblstats")) {
|
||||||
if (plugin.getBlockManager() == null) {
|
if (plugin.getBlockManager() == null) {
|
||||||
sender.sendMessage("§c方块管理器未初始化");
|
sender.sendMessage("§c方块管理器未初始化");
|
||||||
return true;
|
return true;
|
||||||
@@ -90,12 +124,37 @@ public class AdminCommands implements CommandExecutor {
|
|||||||
|
|
||||||
int totalPlayers = plugin.getBlockManager().getPlayerBlocksCount();
|
int totalPlayers = plugin.getBlockManager().getPlayerBlocksCount();
|
||||||
int totalBlocks = plugin.getBlockManager().getTotalBlocksCount();
|
int totalBlocks = plugin.getBlockManager().getTotalBlocksCount();
|
||||||
|
|
||||||
sender.sendMessage("§a===== PlayerBlockLife 统计 =====");
|
// 获取统计标题
|
||||||
sender.sendMessage("§7注册玩家数: §e" + totalPlayers);
|
String title = msgManager.getCommandMessage("pblstats", "title",
|
||||||
sender.sendMessage("§7总生命方块数: §e" + totalBlocks);
|
"&6=== PlayerBlockLife 统计 ===");
|
||||||
sender.sendMessage("§7在线玩家生命方块:");
|
sender.sendMessage(title);
|
||||||
|
|
||||||
|
// 在线玩家统计
|
||||||
|
String onlineMsg = msgManager.getCommandMessage("pblstats", "online_players",
|
||||||
|
"&e在线玩家: {count}");
|
||||||
|
onlineMsg = onlineMsg.replace("{count}", String.valueOf(Bukkit.getOnlinePlayers().size()));
|
||||||
|
sender.sendMessage(onlineMsg);
|
||||||
|
|
||||||
|
// 总方块统计
|
||||||
|
String blocksMsg = msgManager.getCommandMessage("pblstats", "total_blocks",
|
||||||
|
"&e总生命方块: {count}");
|
||||||
|
blocksMsg = blocksMsg.replace("{count}", String.valueOf(totalBlocks));
|
||||||
|
sender.sendMessage(blocksMsg);
|
||||||
|
|
||||||
|
// 淘汰玩家统计
|
||||||
|
int eliminatedCount = 0;
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (plugin.getBlockManager().getRemainingBlocks(player.getUniqueId()) == 0) {
|
||||||
|
eliminatedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String eliminatedMsg = msgManager.getCommandMessage("pblstats", "eliminated_players",
|
||||||
|
"&e已淘汰玩家: {count}");
|
||||||
|
eliminatedMsg = eliminatedMsg.replace("{count}", String.valueOf(eliminatedCount));
|
||||||
|
sender.sendMessage(eliminatedMsg);
|
||||||
|
|
||||||
|
sender.sendMessage("§7在线玩家详情:");
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
int blocks = plugin.getBlockManager().getRemainingBlocks(player.getUniqueId());
|
int blocks = plugin.getBlockManager().getRemainingBlocks(player.getUniqueId());
|
||||||
String status = blocks > 0 ? "§a存活" : "§c已淘汰";
|
String status = blocks > 0 ? "§a存活" : "§c已淘汰";
|
||||||
@@ -106,12 +165,9 @@ public class AdminCommands implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage("§c未知的管理员命令!");
|
String unknownMsg = msgManager.getMessage("game.errors.invalid_arguments",
|
||||||
sender.sendMessage("§e可用命令:");
|
"&c未知的管理员命令!");
|
||||||
sender.sendMessage("§7/pblreload §8- §f重载插件配置");
|
sender.sendMessage(unknownMsg);
|
||||||
sender.sendMessage("§7/pbldelete <玩家> §8- §f删除玩家的生命方块");
|
|
||||||
sender.sendMessage("§7/pblrevive [玩家] §8- §f复活被淘汰的玩家");
|
|
||||||
sender.sendMessage("§7/pblstats §8- §f查看插件统计");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,8 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BlockBreakListener implements Listener {
|
public class BlockBreakListener implements Listener {
|
||||||
@@ -39,7 +41,9 @@ public class BlockBreakListener implements Listener {
|
|||||||
|
|
||||||
if (ownerId.equals(breaker.getUniqueId())) {
|
if (ownerId.equals(breaker.getUniqueId())) {
|
||||||
if (breaker.getGameMode() != GameMode.CREATIVE) {
|
if (breaker.getGameMode() != GameMode.CREATIVE) {
|
||||||
breaker.sendMessage("§c你不能挖掘自己的生命方块!");
|
String message = plugin.getMessageManager().getMessage("game.errors.cannot_break_own_block",
|
||||||
|
"&c你不能挖掘自己的生命方块!");
|
||||||
|
breaker.sendMessage(message);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -47,19 +51,61 @@ public class BlockBreakListener implements Listener {
|
|||||||
|
|
||||||
if (plugin.getBlockManager().removeBlock(location, breaker)) {
|
if (plugin.getBlockManager().removeBlock(location, breaker)) {
|
||||||
int remaining = plugin.getBlockManager().getRemainingBlocks(ownerId);
|
int remaining = plugin.getBlockManager().getRemainingBlocks(ownerId);
|
||||||
|
Player owner = Bukkit.getPlayer(ownerId);
|
||||||
|
String ownerName = owner != null ? owner.getName() : Bukkit.getOfflinePlayer(ownerId).getName();
|
||||||
|
|
||||||
if (remaining <= 0) {
|
if (remaining <= 0) {
|
||||||
plugin.getLifeSystem().handlePlayerDeath(ownerId);
|
plugin.getLifeSystem().handlePlayerDeath(ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
breaker.sendMessage("§a✓ 成功破坏一个生命方块!");
|
// 通知破坏者
|
||||||
breaker.sendMessage("§7剩余方块: §e" + remaining);
|
Map<String, String> variables = new HashMap<>();
|
||||||
|
variables.put("owner", ownerName != null ? ownerName : "未知玩家");
|
||||||
|
variables.put("remaining", String.valueOf(remaining));
|
||||||
|
variables.put("total", String.valueOf(plugin.getConfigManager().getBlocksPerPlayer()));
|
||||||
|
|
||||||
|
String breakerMsg = plugin.getMessageManager().getFormattedMessage("game.block.destroyed.breaker",
|
||||||
|
"&a你破坏了 {owner} 的生命方块!", variables);
|
||||||
|
breaker.sendMessage(breakerMsg);
|
||||||
|
|
||||||
|
String remainingMsg = plugin.getMessageManager().getFormattedMessage("game.block.destroyed.remaining",
|
||||||
|
"&7剩余方块: {remaining}/{total}", variables);
|
||||||
|
breaker.sendMessage(remainingMsg);
|
||||||
|
|
||||||
if (remaining == 1) {
|
if (remaining == 1) {
|
||||||
breaker.sendMessage("§6⚡ 对方只剩最后1个生命方块了!");
|
String lastBlockMsg = plugin.getMessageManager().getMessage("game.block.last_block_warning",
|
||||||
|
"&6⚡ 对方只剩最后1个生命方块了!");
|
||||||
|
breaker.sendMessage(lastBlockMsg);
|
||||||
breaker.playSound(breaker.getLocation(),
|
breaker.playSound(breaker.getLocation(),
|
||||||
org.bukkit.Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.5f);
|
org.bukkit.Sound.ENTITY_PLAYER_LEVELUP, 1.0f, 1.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知方块所有者
|
||||||
|
if (owner != null && owner.isOnline()) {
|
||||||
|
variables.put("breaker", breaker.getName());
|
||||||
|
String ownerMsg = plugin.getMessageManager().getFormattedMessage("game.block.destroyed.owner",
|
||||||
|
"&c⚠ 警告!你的生命方块被 {breaker} 破坏了!剩余: {remaining}/{total}", variables);
|
||||||
|
owner.sendMessage(ownerMsg);
|
||||||
|
|
||||||
|
if (remaining == 0) {
|
||||||
|
String allDestroyedMsg = plugin.getMessageManager().getMessage("game.block.all_destroyed",
|
||||||
|
"&c☠ 你的所有生命方块已被破坏!你已被淘汰!");
|
||||||
|
owner.sendMessage(allDestroyedMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 广播(如果启用)
|
||||||
|
if (plugin.getConfigManager().isBroadcastOnBlockBreak()) {
|
||||||
|
String broadcastMsg = plugin.getMessageManager().getFormattedMessage("broadcast.block_destroyed",
|
||||||
|
"&6{breaker} &7破坏了 &c{owner} &7的生命方块!", variables);
|
||||||
|
int range = plugin.getConfigManager().getBroadcastRange();
|
||||||
|
for (Player nearby : breaker.getWorld().getPlayers()) {
|
||||||
|
if (nearby.getLocation().distance(breaker.getLocation()) <= range &&
|
||||||
|
nearby != breaker && (owner == null || nearby != owner)) {
|
||||||
|
nearby.sendMessage(broadcastMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +119,9 @@ public class BlockBreakListener implements Listener {
|
|||||||
|
|
||||||
UUID ownerId = plugin.getBlockManager().getBlockOwner(block.getLocation());
|
UUID ownerId = plugin.getBlockManager().getBlockOwner(block.getLocation());
|
||||||
if (ownerId != null && !ownerId.equals(player.getUniqueId())) {
|
if (ownerId != null && !ownerId.equals(player.getUniqueId())) {
|
||||||
player.sendMessage("§c你不能在这里放置方块,这是别人的生命方块区域!");
|
String message = plugin.getMessageManager().getMessage("game.errors.cannot_place_in_block_area",
|
||||||
|
"&c你不能在这里放置方块,这是别人的生命方块区域!");
|
||||||
|
player.sendMessage(message);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,49 +19,81 @@ public class CheckLifeBlocksCommand implements CommandExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
// 检查命令是否启用
|
||||||
|
if (!plugin.getConfigManager().isCommandEnabled("checklifeblocks")) {
|
||||||
|
String message = plugin.getMessageManager().getMessage("game.errors.command_disabled",
|
||||||
|
"&c此命令已被禁用!");
|
||||||
|
sender.sendMessage(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
sender.sendMessage("§c只有玩家可以使用此命令!");
|
String message = plugin.getMessageManager().getMessage("game.errors.no_permission",
|
||||||
|
"&c只有玩家可以使用此命令!");
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player player = (Player) sender;
|
Player player = (Player) sender;
|
||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
|
|
||||||
List<Location> blocks = plugin.getBlockManager().getPlayerBlocks(playerId);
|
// 检查是否允许玩家自己使用
|
||||||
int remaining = blocks.size();
|
if (!plugin.getConfigManager().isSelfUseAllowed("checklifeblocks")) {
|
||||||
|
String message = plugin.getMessageManager().getMessage("game.errors.no_permission",
|
||||||
if (remaining == 0) {
|
"&c你没有权限使用此命令!");
|
||||||
player.sendMessage("§c你还没有设置生命方块!");
|
player.sendMessage(message);
|
||||||
player.sendMessage("§7使用 §e/setlifeblocks §7来设置你的生命方块");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage("§a========== 你的生命方块信息 ==========");
|
List<Location> blocks = plugin.getBlockManager().getPlayerBlocks(playerId);
|
||||||
|
int remaining = blocks.size();
|
||||||
|
MessageManager msgManager = plugin.getMessageManager();
|
||||||
|
|
||||||
|
if (remaining == 0) {
|
||||||
|
String noBlocksMsg = msgManager.getCommandMessage("checklifeblocks", "no_blocks",
|
||||||
|
"&c你还没有生命方块!");
|
||||||
|
player.sendMessage(noBlocksMsg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取消息
|
||||||
|
String successMsg = msgManager.getCommandMessage("checklifeblocks", "success",
|
||||||
|
"&e你的生命方块位置:");
|
||||||
|
player.sendMessage(successMsg);
|
||||||
|
|
||||||
player.sendMessage("§7剩余方块数量: §e" + remaining + " §7/ §a5");
|
player.sendMessage("§7剩余方块数量: §e" + remaining + " §7/ §a5");
|
||||||
player.sendMessage("§7当前生命值: §c" +
|
|
||||||
(plugin.getLifeSystem().getPlayerHealth(playerId) != null ?
|
// 显示生命值(如果启用)
|
||||||
plugin.getLifeSystem().getPlayerHealth(playerId) : "20") + " ❤");
|
if (plugin.getConfigManager().isHealthSystemEnabled()) {
|
||||||
|
Integer health = plugin.getLifeSystem().getPlayerHealth(playerId);
|
||||||
|
player.sendMessage("§7当前生命值: §c" + (health != null ? health : "20") + " ❤");
|
||||||
|
}
|
||||||
|
|
||||||
if (remaining <= 2) {
|
if (remaining <= 2) {
|
||||||
player.sendMessage("§c⚠ 警告!生命方块即将耗尽!");
|
String warningMsg = msgManager.getMessage("game.block.warning_low_blocks",
|
||||||
|
"&c⚠ 警告!生命方块即将耗尽!");
|
||||||
|
player.sendMessage(warningMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage("§7方块位置:");
|
player.sendMessage("§7方块位置:");
|
||||||
for (int i = 0; i < blocks.size(); i++) {
|
for (int i = 0; i < blocks.size(); i++) {
|
||||||
Location loc = blocks.get(i);
|
Location loc = blocks.get(i);
|
||||||
String worldName = loc.getWorld() != null ? loc.getWorld().getName() : "未知世界";
|
String worldName = loc.getWorld() != null ? loc.getWorld().getName() : "未知世界");
|
||||||
player.sendMessage("§7" + (i + 1) + ". §e世界: " + worldName +
|
String locationMsg = msgManager.getMessage("game.block.location_item",
|
||||||
" §7坐标: §a" + loc.getBlockX() + " §7, §a" +
|
"&7- {world} ({x}, {y}, {z})");
|
||||||
loc.getBlockY() + " §7, §a" + loc.getBlockZ());
|
locationMsg = locationMsg.replace("{world}", worldName)
|
||||||
|
.replace("{x}", String.valueOf(loc.getBlockX()))
|
||||||
|
.replace("{y}", String.valueOf(loc.getBlockY()))
|
||||||
|
.replace("{z}", String.valueOf(loc.getBlockZ()));
|
||||||
|
player.sendMessage(locationMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage("§a======================================");
|
|
||||||
|
|
||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
player.sendMessage("§e提示:");
|
Location nearestBlock = plugin.getBlockManager().getNearestBlock(player);
|
||||||
player.sendMessage("§7- 方块距离你: §a" +
|
if (nearestBlock != null) {
|
||||||
(int) player.getLocation().distance(blocks.get(0)) + " §7格");
|
double distance = player.getLocation().distance(nearestBlock);
|
||||||
player.sendMessage("§7- 使用指南针可以追踪方块位置");
|
player.sendMessage("§7最近方块距离: §a" + (int)distance + " §7格");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -77,10 +77,41 @@ public class ConfigManager {
|
|||||||
*/
|
*/
|
||||||
private void updateConfig(int fromVersion, int toVersion) {
|
private void updateConfig(int fromVersion, int toVersion) {
|
||||||
if (fromVersion == 1 && toVersion == 2) {
|
if (fromVersion == 1 && toVersion == 2) {
|
||||||
// 示例:添加新配置项
|
// 添加自动生成配置
|
||||||
if (!config.contains("new-feature.enabled")) {
|
if (!config.contains("auto-generation.enabled")) {
|
||||||
config.set("new-feature.enabled", true);
|
config.set("auto-generation.enabled", true);
|
||||||
config.set("new-feature.duration", 60);
|
config.set("auto-generation.require_open_sky", true);
|
||||||
|
config.set("auto-generation.max_attempts", 50);
|
||||||
|
config.set("auto-generation.on_failure", "notify");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加命令启用配置
|
||||||
|
if (!config.contains("commands.setlifeblocks.enabled")) {
|
||||||
|
config.set("commands.setlifeblocks.enabled", true);
|
||||||
|
config.set("commands.setlifeblocks.allow_self_use", true);
|
||||||
|
config.set("commands.setlifeblocks.allow_admin_use", true);
|
||||||
|
|
||||||
|
config.set("commands.checklifeblocks.enabled", true);
|
||||||
|
config.set("commands.checklifeblocks.allow_self_use", true);
|
||||||
|
config.set("commands.checklifeblocks.allow_admin_use", true);
|
||||||
|
|
||||||
|
config.set("commands.pblreload.enabled", true);
|
||||||
|
config.set("commands.pblreload.admin_only", true);
|
||||||
|
|
||||||
|
config.set("commands.pbldelete.enabled", true);
|
||||||
|
config.set("commands.pbldelete.admin_only", true);
|
||||||
|
|
||||||
|
config.set("commands.pblrevive.enabled", true);
|
||||||
|
config.set("commands.pblrevive.admin_only", true);
|
||||||
|
|
||||||
|
config.set("commands.pblstats.enabled", true);
|
||||||
|
config.set("commands.pblstats.admin_only", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新消息配置
|
||||||
|
if (!config.contains("messages.use_external_file")) {
|
||||||
|
config.set("messages.use_external_file", true);
|
||||||
|
config.set("messages.external_file", "messages.yml");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新版本号
|
// 更新版本号
|
||||||
@@ -202,7 +233,58 @@ public class ConfigManager {
|
|||||||
return getConfig().getBoolean("protection.protect_from_pistons", true);
|
return getConfig().getBoolean("protection.protect_from_pistons", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自动生成配置获取方法
|
||||||
|
public boolean isAutoGenerationEnabled() {
|
||||||
|
return getConfig().getBoolean("auto-generation.enabled", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequireOpenSky() {
|
||||||
|
return getConfig().getBoolean("auto-generation.require_open_sky", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxAttempts() {
|
||||||
|
return getConfig().getInt("auto-generation.max_attempts", 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOnFailureAction() {
|
||||||
|
return getConfig().getString("auto-generation.on_failure", "notify");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 命令启用配置获取方法
|
||||||
|
public boolean isCommandEnabled(String commandName) {
|
||||||
|
return getConfig().getBoolean("commands." + commandName + ".enabled", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSelfUseAllowed(String commandName) {
|
||||||
|
return getConfig().getBoolean("commands." + commandName + ".allow_self_use", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAdminUseAllowed(String commandName) {
|
||||||
|
return getConfig().getBoolean("commands." + commandName + ".allow_admin_use", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAdminOnly(String commandName) {
|
||||||
|
return getConfig().getBoolean("commands." + commandName + ".admin_only", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 消息文件配置获取方法
|
||||||
|
public boolean useExternalMessageFile() {
|
||||||
|
return getConfig().getBoolean("messages.use_external_file", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExternalMessageFileName() {
|
||||||
|
return getConfig().getString("messages.external_file", "messages.yml");
|
||||||
|
}
|
||||||
|
|
||||||
public String getMessage(String path, String defaultValue) {
|
public String getMessage(String path, String defaultValue) {
|
||||||
|
// 优先从外部消息文件获取
|
||||||
|
if (useExternalMessageFile()) {
|
||||||
|
// 这里应该调用MessageManager来获取消息
|
||||||
|
// 暂时返回默认值,MessageManager会处理具体逻辑
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从config.yml获取
|
||||||
String message = getConfig().getString("messages." + path, defaultValue);
|
String message = getConfig().getString("messages." + path, defaultValue);
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
message = message.replace("&", "§");
|
message = message.replace("&", "§");
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class PlayerBlockLife extends JavaPlugin {
|
|||||||
private SkinManager skinManager;
|
private SkinManager skinManager;
|
||||||
private LifeSystem lifeSystem;
|
private LifeSystem lifeSystem;
|
||||||
private ConfigManager configManager;
|
private ConfigManager configManager;
|
||||||
|
private MessageManager messageManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
@@ -21,12 +22,14 @@ public class PlayerBlockLife extends JavaPlugin {
|
|||||||
|
|
||||||
// 第二步:初始化管理器(注意顺序!)
|
// 第二步:初始化管理器(注意顺序!)
|
||||||
this.configManager = new ConfigManager(this);
|
this.configManager = new ConfigManager(this);
|
||||||
|
this.messageManager = new MessageManager(this);
|
||||||
this.skinManager = new SkinManager(this);
|
this.skinManager = new SkinManager(this);
|
||||||
this.blockManager = new PlayerBlockManager(this, skinManager);
|
this.blockManager = new PlayerBlockManager(this, skinManager);
|
||||||
this.lifeSystem = new LifeSystem(this);
|
this.lifeSystem = new LifeSystem(this);
|
||||||
|
|
||||||
// 第三步:加载数据(必须在管理器初始化之后)
|
// 第三步:加载数据(必须在管理器初始化之后)
|
||||||
this.configManager.loadConfig();
|
this.configManager.loadConfig();
|
||||||
|
this.messageManager.loadMessages();
|
||||||
|
|
||||||
// 第四步:注册事件监听器
|
// 第四步:注册事件监听器
|
||||||
getServer().getPluginManager().registerEvents(new BlockBreakListener(this), this);
|
getServer().getPluginManager().registerEvents(new BlockBreakListener(this), this);
|
||||||
@@ -83,6 +86,9 @@ public class PlayerBlockLife extends JavaPlugin {
|
|||||||
if (configManager != null) {
|
if (configManager != null) {
|
||||||
configManager.reloadConfig();
|
configManager.reloadConfig();
|
||||||
}
|
}
|
||||||
|
if (messageManager != null) {
|
||||||
|
messageManager.reloadMessages();
|
||||||
|
}
|
||||||
if (blockManager != null) {
|
if (blockManager != null) {
|
||||||
blockManager.loadData();
|
blockManager.loadData();
|
||||||
}
|
}
|
||||||
@@ -139,6 +145,10 @@ public class PlayerBlockLife extends JavaPlugin {
|
|||||||
return configManager;
|
return configManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MessageManager getMessageManager() {
|
||||||
|
return messageManager;
|
||||||
|
}
|
||||||
|
|
||||||
public void logInfo(String message) {
|
public void logInfo(String message) {
|
||||||
getLogger().info(message);
|
getLogger().info(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,32 +34,43 @@ public class PlayerBlockManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 为玩家设置生命方块
|
* 为玩家设置生命方块(兼容旧方法)
|
||||||
*/
|
*/
|
||||||
public boolean setLifeBlocks(Player player, Location center) {
|
public boolean setLifeBlocks(Player player, Location center) {
|
||||||
|
ConfigManager config = plugin.getConfigManager();
|
||||||
|
int blockAmount = config.getBlocksPerPlayer();
|
||||||
|
int spreadRange = config.getSpreadRange();
|
||||||
|
boolean requireOpenSky = config.isRequireOpenSky();
|
||||||
|
int maxAttempts = config.getMaxAttempts();
|
||||||
|
|
||||||
|
return generateLifeBlocksForPlayer(player, blockAmount, spreadRange, requireOpenSky, maxAttempts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为玩家生成生命方块(新方法,支持自动生成)
|
||||||
|
*/
|
||||||
|
public boolean generateLifeBlocksForPlayer(Player player, int blockAmount, int spreadRange, boolean requireOpenSky, int maxAttempts) {
|
||||||
UUID playerId = player.getUniqueId();
|
UUID playerId = player.getUniqueId();
|
||||||
String playerName = player.getName();
|
String playerName = player.getName();
|
||||||
|
|
||||||
// 检查是否已有生命方块
|
// 检查是否已有生命方块
|
||||||
if (hasLifeBlocks(playerId)) {
|
if (hasLifeBlocks(playerId)) {
|
||||||
player.sendMessage("§c你已经有生命方块了!");
|
|
||||||
player.sendMessage("§e使用 /checklifeblocks 查看位置");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查玩家皮肤是否已加载
|
// 检查玩家皮肤是否已加载
|
||||||
if (!skinManager.isSkinLoaded(playerId)) {
|
if (!skinManager.isSkinLoaded(playerId)) {
|
||||||
player.sendMessage("§e你的皮肤正在加载中,请稍候...");
|
|
||||||
player.sendMessage("§7(如果长时间未加载完成,请重新加入服务器)");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Location> blocks = new ArrayList<>();
|
List<Location> blocks = new ArrayList<>();
|
||||||
int blocksPlaced = 0;
|
int blocksPlaced = 0;
|
||||||
|
int attempts = 0;
|
||||||
|
|
||||||
// 尝试在中心周围生成5个方块
|
// 尝试生成指定数量的方块
|
||||||
for (int attempt = 0; attempt < 20 && blocksPlaced < 5; attempt++) {
|
while (blocksPlaced < blockAmount && attempts < maxAttempts) {
|
||||||
Location blockLoc = findSuitableLocation(center);
|
Location blockLoc = findSurfaceLocation(player.getLocation(), spreadRange, requireOpenSky);
|
||||||
|
attempts++;
|
||||||
|
|
||||||
if (blockLoc != null && placePlayerHead(blockLoc, playerId, playerName)) {
|
if (blockLoc != null && placePlayerHead(blockLoc, playerId, playerName)) {
|
||||||
blocks.add(blockLoc);
|
blocks.add(blockLoc);
|
||||||
@@ -74,22 +85,70 @@ public class PlayerBlockManager {
|
|||||||
if (blocksPlaced > 0) {
|
if (blocksPlaced > 0) {
|
||||||
playerBlocks.put(playerId, blocks);
|
playerBlocks.put(playerId, blocks);
|
||||||
saveData();
|
saveData();
|
||||||
|
|
||||||
player.sendMessage("§a========================================");
|
|
||||||
player.sendMessage("§a成功生成 §e" + blocksPlaced + " §a个生命方块!");
|
|
||||||
player.sendMessage("§6方块使用了你的皮肤头像");
|
|
||||||
player.sendMessage("§c⚠ 警告: 方块被挖光时,你将死亡!");
|
|
||||||
player.sendMessage("§7使用 /checklifeblocks 查看方块位置");
|
|
||||||
player.sendMessage("§a========================================");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage("§c无法生成生命方块!");
|
|
||||||
player.sendMessage("§7请确保周围有足够的空间(至少5个可放置位置)");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寻找地表位置(上方无方块覆盖)
|
||||||
|
*/
|
||||||
|
private Location findSurfaceLocation(Location center, int spreadRange, boolean requireOpenSky) {
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
int x = random.nextInt(spreadRange * 2 + 1) - spreadRange;
|
||||||
|
int z = random.nextInt(spreadRange * 2 + 1) - spreadRange;
|
||||||
|
|
||||||
|
// 从中心点上方开始向下寻找地表
|
||||||
|
Location testLoc = center.clone().add(x, 10, z);
|
||||||
|
World world = testLoc.getWorld();
|
||||||
|
if (world == null) continue;
|
||||||
|
|
||||||
|
// 向下寻找第一个非空气方块
|
||||||
|
Block groundBlock = null;
|
||||||
|
for (int y = 10; y > world.getMinHeight(); y--) {
|
||||||
|
testLoc.setY(y);
|
||||||
|
Block block = testLoc.getBlock();
|
||||||
|
if (!block.getType().isAir()) {
|
||||||
|
groundBlock = block;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groundBlock == null) continue;
|
||||||
|
|
||||||
|
// 检查地表方块上方位置
|
||||||
|
Location surfaceLoc = groundBlock.getLocation().add(0, 1, 0);
|
||||||
|
Block surfaceBlock = surfaceLoc.getBlock();
|
||||||
|
|
||||||
|
// 检查是否已有方块
|
||||||
|
if (blockOwners.containsKey(surfaceLoc)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查地表方块是否合适
|
||||||
|
if (!isSuitableLocation(surfaceLoc)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要上方无方块覆盖,检查上方
|
||||||
|
if (requireOpenSky) {
|
||||||
|
boolean hasCover = false;
|
||||||
|
for (int y = 1; y <= 5; y++) {
|
||||||
|
Block aboveBlock = surfaceLoc.clone().add(0, y, 0).getBlock();
|
||||||
|
if (!aboveBlock.getType().isAir()) {
|
||||||
|
hasCover = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasCover) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return surfaceLoc;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 寻找合适的位置
|
* 寻找合适的位置
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class PlayerJoinListener implements Listener {
|
public class PlayerJoinListener implements Listener {
|
||||||
@@ -26,34 +28,135 @@ public class PlayerJoinListener implements Listener {
|
|||||||
// 异步加载玩家皮肤
|
// 异步加载玩家皮肤
|
||||||
plugin.getSkinManager().loadPlayerSkinAsync(player);
|
plugin.getSkinManager().loadPlayerSkinAsync(player);
|
||||||
|
|
||||||
// 延迟发送消息,确保皮肤加载完成
|
// 延迟执行,确保皮肤加载完成
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||||
int remainingBlocks = plugin.getBlockManager().getRemainingBlocks(playerId);
|
int remainingBlocks = plugin.getBlockManager().getRemainingBlocks(playerId);
|
||||||
|
|
||||||
if (remainingBlocks > 0) {
|
// 检查是否启用自动生成
|
||||||
|
if (plugin.getConfigManager().isAutoGenerationEnabled() && remainingBlocks == 0) {
|
||||||
|
// 自动生成生命方块
|
||||||
|
generateLifeBlocksForPlayer(player);
|
||||||
|
} else if (remainingBlocks > 0) {
|
||||||
|
// 已有方块,显示欢迎信息
|
||||||
|
Map<String, String> variables = new HashMap<>();
|
||||||
|
variables.put("player", player.getName());
|
||||||
|
variables.put("remaining", String.valueOf(remainingBlocks));
|
||||||
|
variables.put("total", String.valueOf(plugin.getConfigManager().getBlocksPerPlayer()));
|
||||||
|
|
||||||
|
String welcomeMsg = plugin.getMessageManager().getFormattedMessage("game.player.welcome_back",
|
||||||
|
"&e欢迎回来,&6{player}&e!", variables);
|
||||||
|
String blocksMsg = plugin.getMessageManager().getFormattedMessage("game.player.remaining_blocks",
|
||||||
|
"&7你还有 &e{remaining} &7个生命方块", variables);
|
||||||
|
String checkMsg = plugin.getMessageManager().getMessage("game.player.check_blocks_hint",
|
||||||
|
"&7使用 &e/checklifeblocks &7查看方块位置");
|
||||||
|
|
||||||
player.sendMessage("§a========================================");
|
player.sendMessage("§a========================================");
|
||||||
player.sendMessage("§e欢迎回来,§6" + player.getName() + "§e!");
|
player.sendMessage(welcomeMsg);
|
||||||
player.sendMessage("§7你还有 §e" + remainingBlocks + " §7个生命方块");
|
player.sendMessage(blocksMsg);
|
||||||
player.sendMessage("§7使用 §e/checklifeblocks §7查看方块位置");
|
player.sendMessage(checkMsg);
|
||||||
player.sendMessage("§a========================================");
|
player.sendMessage("§a========================================");
|
||||||
|
|
||||||
if (remainingBlocks <= 2) {
|
if (remainingBlocks <= 2) {
|
||||||
player.sendMessage("§c⚠ 警告!你的生命方块即将耗尽!");
|
String warningMsg = plugin.getMessageManager().getMessage("game.block.warning_low_blocks",
|
||||||
|
"&c⚠ 警告!你的生命方块即将耗尽!");
|
||||||
|
player.sendMessage(warningMsg);
|
||||||
player.playSound(player.getLocation(),
|
player.playSound(player.getLocation(),
|
||||||
org.bukkit.Sound.ENTITY_WITHER_SPAWN, 0.5f, 1.0f);
|
org.bukkit.Sound.ENTITY_WITHER_SPAWN, 0.5f, 1.0f);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
player.sendMessage("§e欢迎加入游戏!");
|
// 没有方块且自动生成未启用
|
||||||
player.sendMessage("§7使用 §e/setlifeblocks §7来设置你的生命方块");
|
String welcomeMsg = plugin.getMessageManager().getMessage("game.player.welcome_new",
|
||||||
player.sendMessage("§6游戏规则:");
|
"&e欢迎加入游戏!");
|
||||||
player.sendMessage("§7- 每个玩家有5个生命方块");
|
String setBlocksMsg = plugin.getMessageManager().getMessage("game.player.set_blocks_hint",
|
||||||
player.sendMessage("§7- 方块被其他玩家挖光时,你将死亡");
|
"&7使用 &e/setlifeblocks &7来设置你的生命方块");
|
||||||
player.sendMessage("§7- 方块使用你的皮肤作为材质");
|
String rulesTitle = plugin.getMessageManager().getMessage("game.player.rules_title",
|
||||||
player.sendMessage("§7- 你可以自由移动,但方块固定位置");
|
"&6游戏规则:");
|
||||||
|
String rule1 = plugin.getMessageManager().getMessage("game.player.rule1",
|
||||||
|
"&7- 每个玩家有5个生命方块");
|
||||||
|
String rule2 = plugin.getMessageManager().getMessage("game.player.rule2",
|
||||||
|
"&7- 方块被其他玩家挖光时,你将死亡");
|
||||||
|
String rule3 = plugin.getMessageManager().getMessage("game.player.rule3",
|
||||||
|
"&7- 方块使用你的皮肤作为材质");
|
||||||
|
String rule4 = plugin.getMessageManager().getMessage("game.player.rule4",
|
||||||
|
"&7- 你可以自由移动,但方块固定位置");
|
||||||
|
|
||||||
|
player.sendMessage(welcomeMsg);
|
||||||
|
player.sendMessage(setBlocksMsg);
|
||||||
|
player.sendMessage(rulesTitle);
|
||||||
|
player.sendMessage(rule1);
|
||||||
|
player.sendMessage(rule2);
|
||||||
|
player.sendMessage(rule3);
|
||||||
|
player.sendMessage(rule4);
|
||||||
}
|
}
|
||||||
}, 40L);
|
}, 40L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为玩家自动生成生命方块
|
||||||
|
*/
|
||||||
|
private void generateLifeBlocksForPlayer(Player player) {
|
||||||
|
try {
|
||||||
|
// 获取配置
|
||||||
|
ConfigManager config = plugin.getConfigManager();
|
||||||
|
int blockAmount = config.getBlocksPerPlayer();
|
||||||
|
int spreadRange = config.getSpreadRange();
|
||||||
|
boolean requireOpenSky = config.isRequireOpenSky();
|
||||||
|
int maxAttempts = config.getMaxAttempts();
|
||||||
|
|
||||||
|
// 调用方块管理器生成方块
|
||||||
|
boolean success = plugin.getBlockManager().generateLifeBlocksForPlayer(
|
||||||
|
player, blockAmount, spreadRange, requireOpenSky, maxAttempts
|
||||||
|
);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
// 发送成功消息
|
||||||
|
String message = plugin.getMessageManager().getMessage("console.blocks_generated",
|
||||||
|
"&a[PlayerBlockLife] 已为玩家 {player} 生成 {amount} 个生命方块");
|
||||||
|
message = message.replace("{player}", player.getName())
|
||||||
|
.replace("{amount}", String.valueOf(blockAmount))
|
||||||
|
.replace("&", "§");
|
||||||
|
plugin.getLogger().info(message);
|
||||||
|
|
||||||
|
// 发送给玩家
|
||||||
|
String playerMsg = plugin.getMessageManager().getMessage("game.block.placed",
|
||||||
|
"&a已为你生成 {amount} 个生命方块!");
|
||||||
|
playerMsg = playerMsg.replace("{amount}", String.valueOf(blockAmount))
|
||||||
|
.replace("&", "§");
|
||||||
|
player.sendMessage(playerMsg);
|
||||||
|
} else {
|
||||||
|
// 生成失败
|
||||||
|
String failureMsg = plugin.getMessageManager().getMessage("console.error_generating_blocks",
|
||||||
|
"&c[PlayerBlockLife] 为玩家 {player} 生成生命方块时失败");
|
||||||
|
failureMsg = failureMsg.replace("{player}", player.getName())
|
||||||
|
.replace("&", "§");
|
||||||
|
plugin.getLogger().warning(failureMsg);
|
||||||
|
|
||||||
|
// 根据配置处理失败
|
||||||
|
String onFailure = config.getOnFailureAction();
|
||||||
|
if (onFailure.equals("notify")) {
|
||||||
|
String notifyMsg = plugin.getMessageManager().getMessage("game.errors.cannot_generate_blocks",
|
||||||
|
"&c无法生成生命方块:找不到合适的位置");
|
||||||
|
notifyMsg = notifyMsg.replace("&", "§");
|
||||||
|
player.sendMessage(notifyMsg);
|
||||||
|
player.sendMessage("§7请手动使用 §e/setlifeblocks §7命令生成方块");
|
||||||
|
} else if (onFailure.equals("teleport_to_spawn")) {
|
||||||
|
player.teleport(player.getWorld().getSpawnLocation());
|
||||||
|
player.sendMessage("§e已将你传送至出生点,请手动生成方块");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
plugin.getLogger().severe("为玩家 " + player.getName() + " 生成生命方块时发生错误: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
String errorMsg = plugin.getMessageManager().getMessage("console.error_generating_blocks",
|
||||||
|
"&c[PlayerBlockLife] 为玩家 {player} 生成生命方块时出错: {error}");
|
||||||
|
errorMsg = errorMsg.replace("{player}", player.getName())
|
||||||
|
.replace("{error}", e.getMessage())
|
||||||
|
.replace("&", "§");
|
||||||
|
plugin.getLogger().severe(errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
|
|||||||
@@ -18,8 +18,18 @@ public class SetLifeBlocksCommand implements CommandExecutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||||
|
// 检查命令是否启用
|
||||||
|
if (!plugin.getConfigManager().isCommandEnabled("setlifeblocks")) {
|
||||||
|
String message = plugin.getMessageManager().getMessage("game.errors.command_disabled",
|
||||||
|
"&c此命令已被禁用!");
|
||||||
|
sender.sendMessage(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(sender instanceof Player)) {
|
if (!(sender instanceof Player)) {
|
||||||
sender.sendMessage("§c只有玩家可以使用此命令!");
|
String message = plugin.getMessageManager().getMessage("game.errors.no_permission",
|
||||||
|
"&c只有玩家可以使用此命令!");
|
||||||
|
sender.sendMessage(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,22 +41,42 @@ public class SetLifeBlocksCommand implements CommandExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length > 0 && player.hasPermission("playerblocklife.admin")) {
|
// 检查管理员权限和配置
|
||||||
if (args[0].equalsIgnoreCase("other")) {
|
if (args.length > 0 && args[0].equalsIgnoreCase("other")) {
|
||||||
if (args.length < 2) {
|
// 检查是否允许管理员使用
|
||||||
player.sendMessage("§c用法: /setlifeblocks other <玩家名>");
|
if (!plugin.getConfigManager().isAdminUseAllowed("setlifeblocks") || !player.hasPermission("playerblocklife.admin")) {
|
||||||
return true;
|
String message = plugin.getMessageManager().getMessage("game.errors.no_permission",
|
||||||
}
|
"&c你没有权限使用此命令!");
|
||||||
|
player.sendMessage(message);
|
||||||
Player target = Bukkit.getPlayer(args[1]);
|
|
||||||
if (target == null) {
|
|
||||||
player.sendMessage("§c找不到玩家: " + args[1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
setBlocksForPlayer(target, player);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
String usage = plugin.getMessageManager().getCommandMessage("setlifeblocks", "usage",
|
||||||
|
"&c用法: /setlifeblocks [reset|other|help]");
|
||||||
|
player.sendMessage(usage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player target = Bukkit.getPlayer(args[1]);
|
||||||
|
if (target == null) {
|
||||||
|
String message = plugin.getMessageManager().getMessage("game.errors.player_not_found",
|
||||||
|
"&c找不到玩家: {player}");
|
||||||
|
message = message.replace("{player}", args[1]);
|
||||||
|
player.sendMessage(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBlocksForPlayer(target, player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否允许玩家自己使用
|
||||||
|
if (!plugin.getConfigManager().isSelfUseAllowed("setlifeblocks")) {
|
||||||
|
String message = plugin.getMessageManager().getMessage("game.errors.no_permission",
|
||||||
|
"&c你没有权限使用此命令!");
|
||||||
|
player.sendMessage(message);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setBlocksForPlayer(player, null);
|
setBlocksForPlayer(player, null);
|
||||||
@@ -55,21 +85,28 @@ public class SetLifeBlocksCommand implements CommandExecutor {
|
|||||||
|
|
||||||
private void setBlocksForPlayer(Player target, Player executor) {
|
private void setBlocksForPlayer(Player target, Player executor) {
|
||||||
UUID targetId = target.getUniqueId();
|
UUID targetId = target.getUniqueId();
|
||||||
|
MessageManager msgManager = plugin.getMessageManager();
|
||||||
|
|
||||||
if (plugin.getBlockManager().hasLifeBlocks(targetId)) {
|
if (plugin.getBlockManager().hasLifeBlocks(targetId)) {
|
||||||
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
||||||
executor.sendMessage("§c玩家 " + target.getName() + " 已经有生命方块了!");
|
String message = msgManager.getMessage("game.errors.player_already_has_blocks",
|
||||||
|
"&c玩家 {player} 已经有生命方块了!");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
executor.sendMessage(message);
|
||||||
} else {
|
} else {
|
||||||
target.sendMessage("§c你已经有生命方块了!");
|
String alreadyHas = msgManager.getCommandMessage("setlifeblocks", "already_has",
|
||||||
target.sendMessage("§e使用 /checklifeblocks 查看位置");
|
"&c你已经有生命方块了!使用 /checklifeblocks 查看位置");
|
||||||
target.sendMessage("§e使用 /setlifeblocks reset 重置方块位置");
|
target.sendMessage(alreadyHas);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!plugin.getSkinManager().isSkinLoaded(targetId)) {
|
if (!plugin.getSkinManager().isSkinLoaded(targetId)) {
|
||||||
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
||||||
executor.sendMessage("§e玩家 " + target.getName() + " 的皮肤正在加载中,请稍候...");
|
String message = msgManager.getMessage("game.skin_loading",
|
||||||
|
"&e玩家 {player} 的皮肤正在加载中,请稍候...");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
executor.sendMessage(message);
|
||||||
} else {
|
} else {
|
||||||
target.sendMessage("§e你的皮肤正在加载中,请稍候...");
|
target.sendMessage("§e你的皮肤正在加载中,请稍候...");
|
||||||
target.sendMessage("§7(如果长时间未加载完成,请重新加入服务器)");
|
target.sendMessage("§7(如果长时间未加载完成,请重新加入服务器)");
|
||||||
@@ -81,11 +118,23 @@ public class SetLifeBlocksCommand implements CommandExecutor {
|
|||||||
boolean success = plugin.getBlockManager().setLifeBlocks(target, target.getLocation());
|
boolean success = plugin.getBlockManager().setLifeBlocks(target, target.getLocation());
|
||||||
if (success) {
|
if (success) {
|
||||||
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
||||||
executor.sendMessage("§a已为玩家 " + target.getName() + " 生成生命方块!");
|
String message = msgManager.getMessage("game.blocks_generated_for_other",
|
||||||
|
"&a已为玩家 {player} 生成生命方块!");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
executor.sendMessage(message);
|
||||||
|
} else {
|
||||||
|
String successMsg = msgManager.getCommandMessage("setlifeblocks", "success",
|
||||||
|
"&a已为你生成 {blocks} 个生命方块!");
|
||||||
|
ConfigManager config = plugin.getConfigManager();
|
||||||
|
successMsg = successMsg.replace("{blocks}", String.valueOf(config.getBlocksPerPlayer()));
|
||||||
|
target.sendMessage(successMsg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
||||||
executor.sendMessage("§c为玩家 " + target.getName() + " 生成生命方块失败!");
|
String message = msgManager.getMessage("game.errors.failed_to_generate_blocks",
|
||||||
|
"&c为玩家 {player} 生成生命方块失败!");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
executor.sendMessage(message);
|
||||||
} else {
|
} else {
|
||||||
target.sendMessage("§c生成失败,请稍后再试或联系管理员");
|
target.sendMessage("§c生成失败,请稍后再试或联系管理员");
|
||||||
}
|
}
|
||||||
@@ -99,11 +148,23 @@ public class SetLifeBlocksCommand implements CommandExecutor {
|
|||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
||||||
executor.sendMessage("§a已为玩家 " + target.getName() + " 生成生命方块!");
|
String message = msgManager.getMessage("game.blocks_generated_for_other",
|
||||||
|
"&a已为玩家 {player} 生成生命方块!");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
executor.sendMessage(message);
|
||||||
|
} else {
|
||||||
|
String successMsg = msgManager.getCommandMessage("setlifeblocks", "success",
|
||||||
|
"&a已为你生成 {blocks} 个生命方块!");
|
||||||
|
ConfigManager config = plugin.getConfigManager();
|
||||||
|
successMsg = successMsg.replace("{blocks}", String.valueOf(config.getBlocksPerPlayer()));
|
||||||
|
target.sendMessage(successMsg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
if (executor != null && !targetId.equals(executor.getUniqueId())) {
|
||||||
executor.sendMessage("§c为玩家 " + target.getName() + " 生成生命方块失败!");
|
String message = msgManager.getMessage("game.errors.failed_to_generate_blocks",
|
||||||
|
"&c为玩家 {player} 生成生命方块失败!");
|
||||||
|
message = message.replace("{player}", target.getName());
|
||||||
|
executor.sendMessage(message);
|
||||||
} else {
|
} else {
|
||||||
target.sendMessage("§c生成失败,请确保周围有足够空间");
|
target.sendMessage("§c生成失败,请确保周围有足够空间");
|
||||||
}
|
}
|
||||||
@@ -111,22 +172,13 @@ public class SetLifeBlocksCommand implements CommandExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showHelp(Player player) {
|
private void showHelp(Player player) {
|
||||||
player.sendMessage("§a========== PlayerBlockLife 帮助 ==========");
|
String helpMessage = plugin.getMessageManager().getCommandMessage("setlifeblocks", "help",
|
||||||
player.sendMessage("§e/setlifeblocks §7- 设置你的生命方块");
|
"&6=== PlayerBlockLife 帮助 ===\n" +
|
||||||
player.sendMessage("§e/checklifeblocks §7- 查看你的生命方块位置");
|
"&e/setlifeblocks &7- 设置你的生命方块\n" +
|
||||||
player.sendMessage("§e/setlifeblocks reset §7- 重置生命方块位置");
|
"&e/setlifeblocks reset &7- 重置生命方块位置\n" +
|
||||||
|
"&e/setlifeblocks other <玩家> &7- 为其他玩家设置(管理员)\n" +
|
||||||
if (player.hasPermission("playerblocklife.admin")) {
|
"&e/setlifeblocks help &7- 显示此帮助");
|
||||||
player.sendMessage("§6管理员命令:");
|
|
||||||
player.sendMessage("§e/setlifeblocks other <玩家> §7- 为其他玩家设置生命方块");
|
player.sendMessage(helpMessage);
|
||||||
player.sendMessage("§e/pblreload §7- 重载插件配置");
|
|
||||||
player.sendMessage("§e/pbldelete <玩家> §7- 删除玩家的生命方块");
|
|
||||||
}
|
|
||||||
|
|
||||||
player.sendMessage("§7游戏规则:");
|
|
||||||
player.sendMessage("§7- 每个玩家有5个生命方块");
|
|
||||||
player.sendMessage("§7- 方块被挖光时,玩家死亡");
|
|
||||||
player.sendMessage("§7- 方块使用玩家的皮肤作为材质");
|
|
||||||
player.sendMessage("§a======================================");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,13 +70,62 @@ protection:
|
|||||||
# 是否保护生命方块不被活塞推动
|
# 是否保护生命方块不被活塞推动
|
||||||
protect_from_pistons: true
|
protect_from_pistons: true
|
||||||
|
|
||||||
# 消息配置(可选,插件会使用默认消息)
|
# 自动生成设置
|
||||||
|
auto-generation:
|
||||||
|
# 玩家加入时是否自动生成生命方块
|
||||||
|
enabled: true
|
||||||
|
# 生成位置要求:上方无方块覆盖的地表
|
||||||
|
require_open_sky: true
|
||||||
|
# 最大尝试次数(如果找不到合适位置)
|
||||||
|
max_attempts: 50
|
||||||
|
# 生成失败时的处理方式 (none, notify, teleport_to_spawn)
|
||||||
|
on_failure: notify
|
||||||
|
|
||||||
|
# 命令启用配置
|
||||||
|
commands:
|
||||||
|
# setlifeblocks 命令
|
||||||
|
setlifeblocks:
|
||||||
|
enabled: true
|
||||||
|
# 是否允许玩家自己使用
|
||||||
|
allow_self_use: true
|
||||||
|
# 是否允许管理员为其他玩家设置
|
||||||
|
allow_admin_use: true
|
||||||
|
|
||||||
|
# checklifeblocks 命令
|
||||||
|
checklifeblocks:
|
||||||
|
enabled: true
|
||||||
|
# 是否允许玩家自己查看
|
||||||
|
allow_self_use: true
|
||||||
|
# 是否允许管理员查看其他玩家
|
||||||
|
allow_admin_use: true
|
||||||
|
|
||||||
|
# pblreload 命令
|
||||||
|
pblreload:
|
||||||
|
enabled: true
|
||||||
|
# 仅限管理员使用
|
||||||
|
admin_only: true
|
||||||
|
|
||||||
|
# pbldelete 命令
|
||||||
|
pbldelete:
|
||||||
|
enabled: true
|
||||||
|
# 仅限管理员使用
|
||||||
|
admin_only: true
|
||||||
|
|
||||||
|
# pblrevive 命令
|
||||||
|
pblrevive:
|
||||||
|
enabled: true
|
||||||
|
# 仅限管理员使用
|
||||||
|
admin_only: true
|
||||||
|
|
||||||
|
# pblstats 命令
|
||||||
|
pblstats:
|
||||||
|
enabled: true
|
||||||
|
# 仅限管理员使用
|
||||||
|
admin_only: true
|
||||||
|
|
||||||
|
# 消息配置(现在使用独立的 messages.yml 文件)
|
||||||
messages:
|
messages:
|
||||||
commands:
|
# 是否启用独立的消息文件
|
||||||
setlifeblocks:
|
use_external_file: true
|
||||||
success: "&a已为你生成 {blocks} 个生命方块!"
|
# 外部消息文件名称
|
||||||
already_has: "&c你已经有生命方块了!使用 /checklifeblocks 查看位置"
|
external_file: "messages.yml"
|
||||||
game:
|
|
||||||
block_destroyed:
|
|
||||||
owner: "&c⚠ 警告!你的生命方块被 {breaker} 破坏了!"
|
|
||||||
breaker: "&a你破坏了 {owner} 的生命方块!"
|
|
||||||
108
src/main/resources/messages.yml
Normal file
108
src/main/resources/messages.yml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# PlayerBlockLife 消息配置文件
|
||||||
|
# 所有插件输出消息都可以在这里自定义
|
||||||
|
|
||||||
|
# 控制台消息
|
||||||
|
console:
|
||||||
|
plugin_enabled: "&a[PlayerBlockLife] 插件已启用!版本: {version}"
|
||||||
|
plugin_disabled: "&c[PlayerBlockLife] 插件已禁用!"
|
||||||
|
config_reloaded: "&a[PlayerBlockLife] 配置已重载!"
|
||||||
|
player_joined: "&a[PlayerBlockLife] 玩家 {player} 已加入,正在生成生命方块..."
|
||||||
|
blocks_generated: "&a[PlayerBlockLife] 已为玩家 {player} 生成 {amount} 个生命方块"
|
||||||
|
player_eliminated: "&c[PlayerBlockLife] 玩家 {player} 的生命方块已被挖光,已被淘汰!"
|
||||||
|
error_generating_blocks: "&c[PlayerBlockLife] 为玩家 {player} 生成生命方块时出错: {error}"
|
||||||
|
|
||||||
|
# 游戏内消息
|
||||||
|
game:
|
||||||
|
# 方块相关
|
||||||
|
block:
|
||||||
|
destroyed:
|
||||||
|
owner: "&c⚠ 警告!你的生命方块被 {breaker} 破坏了!剩余: {remaining}/{total}"
|
||||||
|
breaker: "&a你破坏了 {owner} 的生命方块!"
|
||||||
|
all_destroyed: "&c☠ 你的所有生命方块已被破坏!你已被淘汰!"
|
||||||
|
placed: "&a已为你生成 {amount} 个生命方块!"
|
||||||
|
check_location: "&e你的生命方块位置:"
|
||||||
|
location_item: "&7- {world} ({x}, {y}, {z})"
|
||||||
|
no_blocks: "&c你还没有生命方块!"
|
||||||
|
|
||||||
|
# 玩家状态
|
||||||
|
player:
|
||||||
|
eliminated: "&c玩家 {player} 已被淘汰!"
|
||||||
|
revived: "&a玩家 {player} 已被复活!"
|
||||||
|
already_eliminated: "&c玩家 {player} 已被淘汰,无法执行此操作!"
|
||||||
|
not_eliminated: "&c玩家 {player} 未被淘汰!"
|
||||||
|
|
||||||
|
# 错误消息
|
||||||
|
errors:
|
||||||
|
no_permission: "&c你没有权限使用此命令!"
|
||||||
|
player_not_found: "&c玩家 {player} 未找到!"
|
||||||
|
player_offline: "&c玩家 {player} 不在线!"
|
||||||
|
invalid_arguments: "&c参数无效!用法: {usage}"
|
||||||
|
command_disabled: "&c此命令已被禁用!"
|
||||||
|
world_not_found: "&c世界 {world} 未找到!"
|
||||||
|
cannot_generate_blocks: "&c无法生成生命方块:{reason}"
|
||||||
|
internal_error: "&c发生内部错误,请联系管理员!"
|
||||||
|
|
||||||
|
# 成功消息
|
||||||
|
success:
|
||||||
|
blocks_reset: "&a已重置你的生命方块!"
|
||||||
|
blocks_deleted: "&a已删除玩家 {player} 的生命方块!"
|
||||||
|
config_reloaded: "&a配置已重载!"
|
||||||
|
player_revived: "&a玩家 {player} 已复活!"
|
||||||
|
|
||||||
|
# 命令消息
|
||||||
|
commands:
|
||||||
|
setlifeblocks:
|
||||||
|
success: "&a已为你生成 {blocks} 个生命方块!"
|
||||||
|
already_has: "&c你已经有生命方块了!使用 /checklifeblocks 查看位置"
|
||||||
|
help: |
|
||||||
|
&6=== PlayerBlockLife 帮助 ===
|
||||||
|
&e/setlifeblocks &7- 设置你的生命方块
|
||||||
|
&e/setlifeblocks reset &7- 重置生命方块位置
|
||||||
|
&e/setlifeblocks other <玩家> &7- 为其他玩家设置(管理员)
|
||||||
|
&e/setlifeblocks help &7- 显示此帮助
|
||||||
|
usage: "&c用法: /setlifeblocks [reset|other|help]"
|
||||||
|
|
||||||
|
checklifeblocks:
|
||||||
|
success: "&e你的生命方块位置:"
|
||||||
|
no_blocks: "&c你还没有生命方块!"
|
||||||
|
usage: "&c用法: /checklifeblocks"
|
||||||
|
|
||||||
|
pblreload:
|
||||||
|
success: "&a配置已重载!"
|
||||||
|
usage: "&c用法: /pblreload"
|
||||||
|
|
||||||
|
pbldelete:
|
||||||
|
success: "&a已删除玩家 {player} 的生命方块!"
|
||||||
|
usage: "&c用法: /pbldelete <玩家>"
|
||||||
|
|
||||||
|
pblrevive:
|
||||||
|
success: "&a玩家 {player} 已复活!"
|
||||||
|
usage: "&c用法: /pblrevive [玩家]"
|
||||||
|
|
||||||
|
pblstats:
|
||||||
|
title: "&6=== PlayerBlockLife 统计 ==="
|
||||||
|
online_players: "&e在线玩家: {count}"
|
||||||
|
total_blocks: "&e总生命方块: {count}"
|
||||||
|
eliminated_players: "&e已淘汰玩家: {count}"
|
||||||
|
usage: "&c用法: /pblstats"
|
||||||
|
|
||||||
|
# 广播消息
|
||||||
|
broadcast:
|
||||||
|
block_destroyed: "&6{breaker} &7破坏了 &c{owner} &7的生命方块!"
|
||||||
|
player_eliminated: "&c☠ {player} &7的生命方块已被挖光,已被淘汰!"
|
||||||
|
player_revived: "&a✨ {player} &7已被复活!"
|
||||||
|
|
||||||
|
# 变量说明
|
||||||
|
# {player} - 玩家名称
|
||||||
|
# {breaker} - 破坏者名称
|
||||||
|
# {owner} - 方块所有者名称
|
||||||
|
# {amount} - 方块数量
|
||||||
|
# {remaining} - 剩余方块数量
|
||||||
|
# {total} - 总方块数量
|
||||||
|
# {x}, {y}, {z} - 坐标
|
||||||
|
# {world} - 世界名称
|
||||||
|
# {version} - 插件版本
|
||||||
|
# {error} - 错误信息
|
||||||
|
# {reason} - 原因
|
||||||
|
# {count} - 计数
|
||||||
|
# {usage} - 命令用法
|
||||||
Reference in New Issue
Block a user