From 8b502459b011f87afdf675759d0eb9337df69247 Mon Sep 17 00:00:00 2001 From: xiaobai Date: Fri, 13 Feb 2026 22:03:17 +0800 Subject: [PATCH] =?UTF-8?q?1.0.1=EF=BC=9AFix=20bug:[21:01:10=20INFO]:=20[P?= =?UTF-8?q?BL]=20=C2=A7a=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D?= =?UTF-8?q?=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D?= =?UTF-8?q?=3D=3D=3D=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20[21:01:10?= =?UTF-8?q?=20INFO]:=20[PBL]=20=C2=A7ePlayerBlockLife=20v1.0.1-1.20.4=20?= =?UTF-8?q?=E5=B7=B2=E5=90=AF=E7=94=A8=20=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20[21:01:10=20INFO]:=20[PBL]=20=C2=A7e=E4=BD=9C=E8=80=85?= =?UTF-8?q?:=20[YourName]=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20[21:?= =?UTF-8?q?01:10=20INFO]:=20[PBL]=20=C2=A7a=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D?= =?UTF-8?q?=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D?= =?UTF-8?q?=3D=3D=3D=3D=3D=3D=3D=3D=3D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/playerblocklife/AdminCommands.java | 106 ++++++++++---- .../playerblocklife/BlockBreakListener.java | 58 +++++++- .../CheckLifeBlocksCommand.java | 78 +++++++--- .../com/playerblocklife/ConfigManager.java | 90 +++++++++++- .../com/playerblocklife/PlayerBlockLife.java | 10 ++ .../playerblocklife/PlayerBlockManager.java | 95 ++++++++++--- .../playerblocklife/PlayerJoinListener.java | 129 +++++++++++++++-- .../playerblocklife/SetLifeBlocksCommand.java | 134 ++++++++++++------ src/main/resources/config.yml | 67 +++++++-- src/main/resources/messages.yml | 108 ++++++++++++++ 10 files changed, 737 insertions(+), 138 deletions(-) create mode 100644 src/main/resources/messages.yml diff --git a/src/main/java/com/playerblocklife/AdminCommands.java b/src/main/java/com/playerblocklife/AdminCommands.java index 127c854..9a7df76 100644 --- a/src/main/java/com/playerblocklife/AdminCommands.java +++ b/src/main/java/com/playerblocklife/AdminCommands.java @@ -17,21 +17,41 @@ public class AdminCommands implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!sender.hasPermission("playerblocklife.admin")) { - sender.sendMessage("§c你没有权限使用此命令!"); + MessageManager msgManager = plugin.getMessageManager(); + 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; } - if (command.getName().equalsIgnoreCase("pblreload")) { + if (commandName.equals("pblreload")) { // 调用插件的完整重载方法 plugin.reloadPluginConfig(); - sender.sendMessage("§a插件配置已完全重载!"); + String message = msgManager.getCommandMessage("pblreload", "success", + "&a配置已重载!"); + sender.sendMessage(message); return true; } - if (command.getName().equalsIgnoreCase("pbldelete")) { + if (commandName.equals("pbldelete")) { if (args.length < 1) { - sender.sendMessage("§c用法: /pbldelete <玩家名>"); + String usage = msgManager.getCommandMessage("pbldelete", "usage", + "&c用法: /pbldelete <玩家>"); + sender.sendMessage(usage); return true; } @@ -46,43 +66,57 @@ public class AdminCommands implements CommandExecutor { try { targetId = Bukkit.getOfflinePlayer(targetName).getUniqueId(); } 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; } } 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; } - if (command.getName().equalsIgnoreCase("pblrevive")) { + if (commandName.equals("pblrevive")) { Player target; if (args.length < 1) { if (!(sender instanceof Player)) { - sender.sendMessage("§c控制台使用时必须指定玩家名: /pblrevive <玩家名>"); + String usage = msgManager.getCommandMessage("pblrevive", "usage", + "&c用法: /pblrevive [玩家]"); + sender.sendMessage(usage); return true; } target = (Player) sender; } else { target = Bukkit.getPlayer(args[0]); 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; } } if (plugin.getLifeSystem() != null) { 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 { sender.sendMessage("§c复活失败:生命系统未初始化"); } return true; } - if (command.getName().equalsIgnoreCase("pblstats")) { + if (commandName.equals("pblstats")) { if (plugin.getBlockManager() == null) { sender.sendMessage("§c方块管理器未初始化"); return true; @@ -90,12 +124,37 @@ public class AdminCommands implements CommandExecutor { int totalPlayers = plugin.getBlockManager().getPlayerBlocksCount(); int totalBlocks = plugin.getBlockManager().getTotalBlocksCount(); - - sender.sendMessage("§a===== PlayerBlockLife 统计 ====="); - sender.sendMessage("§7注册玩家数: §e" + totalPlayers); - sender.sendMessage("§7总生命方块数: §e" + totalBlocks); - sender.sendMessage("§7在线玩家生命方块:"); - + + // 获取统计标题 + String title = msgManager.getCommandMessage("pblstats", "title", + "&6=== PlayerBlockLife 统计 ==="); + 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()) { int blocks = plugin.getBlockManager().getRemainingBlocks(player.getUniqueId()); String status = blocks > 0 ? "§a存活" : "§c已淘汰"; @@ -106,12 +165,9 @@ public class AdminCommands implements CommandExecutor { return true; } - sender.sendMessage("§c未知的管理员命令!"); - sender.sendMessage("§e可用命令:"); - sender.sendMessage("§7/pblreload §8- §f重载插件配置"); - sender.sendMessage("§7/pbldelete <玩家> §8- §f删除玩家的生命方块"); - sender.sendMessage("§7/pblrevive [玩家] §8- §f复活被淘汰的玩家"); - sender.sendMessage("§7/pblstats §8- §f查看插件统计"); + String unknownMsg = msgManager.getMessage("game.errors.invalid_arguments", + "&c未知的管理员命令!"); + sender.sendMessage(unknownMsg); return true; } } \ No newline at end of file diff --git a/src/main/java/com/playerblocklife/BlockBreakListener.java b/src/main/java/com/playerblocklife/BlockBreakListener.java index dbee13f..62e8a02 100644 --- a/src/main/java/com/playerblocklife/BlockBreakListener.java +++ b/src/main/java/com/playerblocklife/BlockBreakListener.java @@ -12,6 +12,8 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; public class BlockBreakListener implements Listener { @@ -39,7 +41,9 @@ public class BlockBreakListener implements Listener { if (ownerId.equals(breaker.getUniqueId())) { 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); } return; @@ -47,19 +51,61 @@ public class BlockBreakListener implements Listener { if (plugin.getBlockManager().removeBlock(location, breaker)) { int remaining = plugin.getBlockManager().getRemainingBlocks(ownerId); + Player owner = Bukkit.getPlayer(ownerId); + String ownerName = owner != null ? owner.getName() : Bukkit.getOfflinePlayer(ownerId).getName(); if (remaining <= 0) { plugin.getLifeSystem().handlePlayerDeath(ownerId); } - breaker.sendMessage("§a✓ 成功破坏一个生命方块!"); - breaker.sendMessage("§7剩余方块: §e" + remaining); + // 通知破坏者 + Map 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) { - breaker.sendMessage("§6⚡ 对方只剩最后1个生命方块了!"); + String lastBlockMsg = plugin.getMessageManager().getMessage("game.block.last_block_warning", + "&6⚡ 对方只剩最后1个生命方块了!"); + breaker.sendMessage(lastBlockMsg); breaker.playSound(breaker.getLocation(), 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()); 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); } } diff --git a/src/main/java/com/playerblocklife/CheckLifeBlocksCommand.java b/src/main/java/com/playerblocklife/CheckLifeBlocksCommand.java index dbed19d..81f2340 100644 --- a/src/main/java/com/playerblocklife/CheckLifeBlocksCommand.java +++ b/src/main/java/com/playerblocklife/CheckLifeBlocksCommand.java @@ -19,49 +19,81 @@ public class CheckLifeBlocksCommand implements CommandExecutor { @Override 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)) { - sender.sendMessage("§c只有玩家可以使用此命令!"); + String message = plugin.getMessageManager().getMessage("game.errors.no_permission", + "&c只有玩家可以使用此命令!"); + sender.sendMessage(message); return true; } Player player = (Player) sender; UUID playerId = player.getUniqueId(); - - List blocks = plugin.getBlockManager().getPlayerBlocks(playerId); - int remaining = blocks.size(); - - if (remaining == 0) { - player.sendMessage("§c你还没有设置生命方块!"); - player.sendMessage("§7使用 §e/setlifeblocks §7来设置你的生命方块"); + + // 检查是否允许玩家自己使用 + if (!plugin.getConfigManager().isSelfUseAllowed("checklifeblocks")) { + String message = plugin.getMessageManager().getMessage("game.errors.no_permission", + "&c你没有权限使用此命令!"); + player.sendMessage(message); return true; } - player.sendMessage("§a========== 你的生命方块信息 =========="); + List 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当前生命值: §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) { - player.sendMessage("§c⚠ 警告!生命方块即将耗尽!"); + String warningMsg = msgManager.getMessage("game.block.warning_low_blocks", + "&c⚠ 警告!生命方块即将耗尽!"); + player.sendMessage(warningMsg); } player.sendMessage("§7方块位置:"); for (int i = 0; i < blocks.size(); i++) { Location loc = blocks.get(i); - String worldName = loc.getWorld() != null ? loc.getWorld().getName() : "未知世界"; - player.sendMessage("§7" + (i + 1) + ". §e世界: " + worldName + - " §7坐标: §a" + loc.getBlockX() + " §7, §a" + - loc.getBlockY() + " §7, §a" + loc.getBlockZ()); + String worldName = loc.getWorld() != null ? loc.getWorld().getName() : "未知世界"); + String locationMsg = msgManager.getMessage("game.block.location_item", + "&7- {world} ({x}, {y}, {z})"); + 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) { - player.sendMessage("§e提示:"); - player.sendMessage("§7- 方块距离你: §a" + - (int) player.getLocation().distance(blocks.get(0)) + " §7格"); - player.sendMessage("§7- 使用指南针可以追踪方块位置"); + Location nearestBlock = plugin.getBlockManager().getNearestBlock(player); + if (nearestBlock != null) { + double distance = player.getLocation().distance(nearestBlock); + player.sendMessage("§7最近方块距离: §a" + (int)distance + " §7格"); + } } return true; diff --git a/src/main/java/com/playerblocklife/ConfigManager.java b/src/main/java/com/playerblocklife/ConfigManager.java index 21ede7b..3125bdd 100644 --- a/src/main/java/com/playerblocklife/ConfigManager.java +++ b/src/main/java/com/playerblocklife/ConfigManager.java @@ -77,10 +77,41 @@ public class ConfigManager { */ private void updateConfig(int fromVersion, int toVersion) { if (fromVersion == 1 && toVersion == 2) { - // 示例:添加新配置项 - if (!config.contains("new-feature.enabled")) { - config.set("new-feature.enabled", true); - config.set("new-feature.duration", 60); + // 添加自动生成配置 + if (!config.contains("auto-generation.enabled")) { + config.set("auto-generation.enabled", true); + 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); } + // 自动生成配置获取方法 + 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) { + // 优先从外部消息文件获取 + if (useExternalMessageFile()) { + // 这里应该调用MessageManager来获取消息 + // 暂时返回默认值,MessageManager会处理具体逻辑 + return defaultValue; + } + + // 从config.yml获取 String message = getConfig().getString("messages." + path, defaultValue); if (message != null) { message = message.replace("&", "§"); diff --git a/src/main/java/com/playerblocklife/PlayerBlockLife.java b/src/main/java/com/playerblocklife/PlayerBlockLife.java index 772a9ab..ad5b236 100644 --- a/src/main/java/com/playerblocklife/PlayerBlockLife.java +++ b/src/main/java/com/playerblocklife/PlayerBlockLife.java @@ -11,6 +11,7 @@ public class PlayerBlockLife extends JavaPlugin { private SkinManager skinManager; private LifeSystem lifeSystem; private ConfigManager configManager; + private MessageManager messageManager; @Override public void onEnable() { @@ -21,12 +22,14 @@ public class PlayerBlockLife extends JavaPlugin { // 第二步:初始化管理器(注意顺序!) this.configManager = new ConfigManager(this); + this.messageManager = new MessageManager(this); this.skinManager = new SkinManager(this); this.blockManager = new PlayerBlockManager(this, skinManager); this.lifeSystem = new LifeSystem(this); // 第三步:加载数据(必须在管理器初始化之后) this.configManager.loadConfig(); + this.messageManager.loadMessages(); // 第四步:注册事件监听器 getServer().getPluginManager().registerEvents(new BlockBreakListener(this), this); @@ -83,6 +86,9 @@ public class PlayerBlockLife extends JavaPlugin { if (configManager != null) { configManager.reloadConfig(); } + if (messageManager != null) { + messageManager.reloadMessages(); + } if (blockManager != null) { blockManager.loadData(); } @@ -139,6 +145,10 @@ public class PlayerBlockLife extends JavaPlugin { return configManager; } + public MessageManager getMessageManager() { + return messageManager; + } + public void logInfo(String message) { getLogger().info(message); } diff --git a/src/main/java/com/playerblocklife/PlayerBlockManager.java b/src/main/java/com/playerblocklife/PlayerBlockManager.java index a18fd96..b4b7208 100644 --- a/src/main/java/com/playerblocklife/PlayerBlockManager.java +++ b/src/main/java/com/playerblocklife/PlayerBlockManager.java @@ -34,32 +34,43 @@ public class PlayerBlockManager { } /** - * 为玩家设置生命方块 + * 为玩家设置生命方块(兼容旧方法) */ 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(); String playerName = player.getName(); // 检查是否已有生命方块 if (hasLifeBlocks(playerId)) { - player.sendMessage("§c你已经有生命方块了!"); - player.sendMessage("§e使用 /checklifeblocks 查看位置"); return false; } // 检查玩家皮肤是否已加载 if (!skinManager.isSkinLoaded(playerId)) { - player.sendMessage("§e你的皮肤正在加载中,请稍候..."); - player.sendMessage("§7(如果长时间未加载完成,请重新加入服务器)"); return false; } List blocks = new ArrayList<>(); int blocksPlaced = 0; + int attempts = 0; - // 尝试在中心周围生成5个方块 - for (int attempt = 0; attempt < 20 && blocksPlaced < 5; attempt++) { - Location blockLoc = findSuitableLocation(center); + // 尝试生成指定数量的方块 + while (blocksPlaced < blockAmount && attempts < maxAttempts) { + Location blockLoc = findSurfaceLocation(player.getLocation(), spreadRange, requireOpenSky); + attempts++; if (blockLoc != null && placePlayerHead(blockLoc, playerId, playerName)) { blocks.add(blockLoc); @@ -74,22 +85,70 @@ public class PlayerBlockManager { if (blocksPlaced > 0) { playerBlocks.put(playerId, blocks); 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; } else { - player.sendMessage("§c无法生成生命方块!"); - player.sendMessage("§7请确保周围有足够的空间(至少5个可放置位置)"); 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; + } + /** * 寻找合适的位置 */ diff --git a/src/main/java/com/playerblocklife/PlayerJoinListener.java b/src/main/java/com/playerblocklife/PlayerJoinListener.java index 39f443f..815e09a 100644 --- a/src/main/java/com/playerblocklife/PlayerJoinListener.java +++ b/src/main/java/com/playerblocklife/PlayerJoinListener.java @@ -9,6 +9,8 @@ import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerRespawnEvent; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; public class PlayerJoinListener implements Listener { @@ -26,34 +28,135 @@ public class PlayerJoinListener implements Listener { // 异步加载玩家皮肤 plugin.getSkinManager().loadPlayerSkinAsync(player); - // 延迟发送消息,确保皮肤加载完成 + // 延迟执行,确保皮肤加载完成 Bukkit.getScheduler().runTaskLater(plugin, () -> { int remainingBlocks = plugin.getBlockManager().getRemainingBlocks(playerId); - if (remainingBlocks > 0) { + // 检查是否启用自动生成 + if (plugin.getConfigManager().isAutoGenerationEnabled() && remainingBlocks == 0) { + // 自动生成生命方块 + generateLifeBlocksForPlayer(player); + } else if (remainingBlocks > 0) { + // 已有方块,显示欢迎信息 + Map 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("§e欢迎回来,§6" + player.getName() + "§e!"); - player.sendMessage("§7你还有 §e" + remainingBlocks + " §7个生命方块"); - player.sendMessage("§7使用 §e/checklifeblocks §7查看方块位置"); + player.sendMessage(welcomeMsg); + player.sendMessage(blocksMsg); + player.sendMessage(checkMsg); player.sendMessage("§a========================================"); if (remainingBlocks <= 2) { - player.sendMessage("§c⚠ 警告!你的生命方块即将耗尽!"); + String warningMsg = plugin.getMessageManager().getMessage("game.block.warning_low_blocks", + "&c⚠ 警告!你的生命方块即将耗尽!"); + player.sendMessage(warningMsg); player.playSound(player.getLocation(), org.bukkit.Sound.ENTITY_WITHER_SPAWN, 0.5f, 1.0f); } } else { - player.sendMessage("§e欢迎加入游戏!"); - player.sendMessage("§7使用 §e/setlifeblocks §7来设置你的生命方块"); - player.sendMessage("§6游戏规则:"); - player.sendMessage("§7- 每个玩家有5个生命方块"); - player.sendMessage("§7- 方块被其他玩家挖光时,你将死亡"); - player.sendMessage("§7- 方块使用你的皮肤作为材质"); - player.sendMessage("§7- 你可以自由移动,但方块固定位置"); + // 没有方块且自动生成未启用 + String welcomeMsg = plugin.getMessageManager().getMessage("game.player.welcome_new", + "&e欢迎加入游戏!"); + String setBlocksMsg = plugin.getMessageManager().getMessage("game.player.set_blocks_hint", + "&7使用 &e/setlifeblocks &7来设置你的生命方块"); + String rulesTitle = plugin.getMessageManager().getMessage("game.player.rules_title", + "&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); } + /** + * 为玩家自动生成生命方块 + */ + 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 public void onPlayerRespawn(PlayerRespawnEvent event) { Player player = event.getPlayer(); diff --git a/src/main/java/com/playerblocklife/SetLifeBlocksCommand.java b/src/main/java/com/playerblocklife/SetLifeBlocksCommand.java index fd190f0..810df7b 100644 --- a/src/main/java/com/playerblocklife/SetLifeBlocksCommand.java +++ b/src/main/java/com/playerblocklife/SetLifeBlocksCommand.java @@ -18,8 +18,18 @@ public class SetLifeBlocksCommand implements CommandExecutor { @Override 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)) { - sender.sendMessage("§c只有玩家可以使用此命令!"); + String message = plugin.getMessageManager().getMessage("game.errors.no_permission", + "&c只有玩家可以使用此命令!"); + sender.sendMessage(message); return true; } @@ -31,22 +41,42 @@ public class SetLifeBlocksCommand implements CommandExecutor { return true; } - if (args.length > 0 && player.hasPermission("playerblocklife.admin")) { - if (args[0].equalsIgnoreCase("other")) { - if (args.length < 2) { - player.sendMessage("§c用法: /setlifeblocks other <玩家名>"); - return true; - } - - Player target = Bukkit.getPlayer(args[1]); - if (target == null) { - player.sendMessage("§c找不到玩家: " + args[1]); - return true; - } - - setBlocksForPlayer(target, player); + // 检查管理员权限和配置 + if (args.length > 0 && args[0].equalsIgnoreCase("other")) { + // 检查是否允许管理员使用 + if (!plugin.getConfigManager().isAdminUseAllowed("setlifeblocks") || !player.hasPermission("playerblocklife.admin")) { + String message = plugin.getMessageManager().getMessage("game.errors.no_permission", + "&c你没有权限使用此命令!"); + player.sendMessage(message); 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); @@ -55,21 +85,28 @@ public class SetLifeBlocksCommand implements CommandExecutor { private void setBlocksForPlayer(Player target, Player executor) { UUID targetId = target.getUniqueId(); + MessageManager msgManager = plugin.getMessageManager(); if (plugin.getBlockManager().hasLifeBlocks(targetId)) { 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 { - target.sendMessage("§c你已经有生命方块了!"); - target.sendMessage("§e使用 /checklifeblocks 查看位置"); - target.sendMessage("§e使用 /setlifeblocks reset 重置方块位置"); + String alreadyHas = msgManager.getCommandMessage("setlifeblocks", "already_has", + "&c你已经有生命方块了!使用 /checklifeblocks 查看位置"); + target.sendMessage(alreadyHas); } return; } if (!plugin.getSkinManager().isSkinLoaded(targetId)) { 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 { target.sendMessage("§e你的皮肤正在加载中,请稍候..."); target.sendMessage("§7(如果长时间未加载完成,请重新加入服务器)"); @@ -81,11 +118,23 @@ public class SetLifeBlocksCommand implements CommandExecutor { boolean success = plugin.getBlockManager().setLifeBlocks(target, target.getLocation()); if (success) { 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 { 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 { target.sendMessage("§c生成失败,请稍后再试或联系管理员"); } @@ -99,11 +148,23 @@ public class SetLifeBlocksCommand implements CommandExecutor { if (success) { 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 { 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 { target.sendMessage("§c生成失败,请确保周围有足够空间"); } @@ -111,22 +172,13 @@ public class SetLifeBlocksCommand implements CommandExecutor { } private void showHelp(Player player) { - player.sendMessage("§a========== PlayerBlockLife 帮助 =========="); - player.sendMessage("§e/setlifeblocks §7- 设置你的生命方块"); - player.sendMessage("§e/checklifeblocks §7- 查看你的生命方块位置"); - player.sendMessage("§e/setlifeblocks reset §7- 重置生命方块位置"); - - if (player.hasPermission("playerblocklife.admin")) { - player.sendMessage("§6管理员命令:"); - player.sendMessage("§e/setlifeblocks other <玩家> §7- 为其他玩家设置生命方块"); - 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======================================"); + String helpMessage = plugin.getMessageManager().getCommandMessage("setlifeblocks", "help", + "&6=== PlayerBlockLife 帮助 ===\n" + + "&e/setlifeblocks &7- 设置你的生命方块\n" + + "&e/setlifeblocks reset &7- 重置生命方块位置\n" + + "&e/setlifeblocks other <玩家> &7- 为其他玩家设置(管理员)\n" + + "&e/setlifeblocks help &7- 显示此帮助"); + + player.sendMessage(helpMessage); } } \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index bba24ff..0edf13a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -70,13 +70,62 @@ protection: # 是否保护生命方块不被活塞推动 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: - commands: - setlifeblocks: - success: "&a已为你生成 {blocks} 个生命方块!" - already_has: "&c你已经有生命方块了!使用 /checklifeblocks 查看位置" - game: - block_destroyed: - owner: "&c⚠ 警告!你的生命方块被 {breaker} 破坏了!" - breaker: "&a你破坏了 {owner} 的生命方块!" \ No newline at end of file + # 是否启用独立的消息文件 + use_external_file: true + # 外部消息文件名称 + external_file: "messages.yml" \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml new file mode 100644 index 0000000..ae468ca --- /dev/null +++ b/src/main/resources/messages.yml @@ -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} - 命令用法 \ No newline at end of file