2 Commits

Author SHA1 Message Date
xiaobai
2fbf5cfd7d 修复bug:破坏方块无反应 2026-02-13 22:27:03 +08:00
xiaobai
8b502459b0 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========================================
2026-02-13 22:03:17 +08:00
14 changed files with 927 additions and 140 deletions

View File

@@ -4,7 +4,7 @@ plugins {
} }
group = 'com.playerblocklife' group = 'com.playerblocklife'
version = '1.0.1-1.20.4' version = '2.0.0-1.20.4'
sourceCompatibility = 17 sourceCompatibility = 17
targetCompatibility = 17 targetCompatibility = 17

View File

@@ -5,5 +5,5 @@ org.gradle.caching=true
org.gradle.daemon=true org.gradle.daemon=true
# ???? # ????
pluginVersion=1.0.1-1.20.4 pluginVersion=2.0.0-1.20.4
mcVersion=1.20.4 mcVersion=1.20.4

View File

@@ -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; return true;
} }
if (command.getName().equalsIgnoreCase("pblreload")) { // 检查管理员权限和配置
if (!sender.hasPermission("playerblocklife.admin") || config.isAdminOnly(commandName)) {
String message = msgManager.getMessage("game.errors.no_permission",
"&c你没有权限使用此命令");
sender.sendMessage(message);
return true;
}
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;
@@ -91,11 +125,36 @@ 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;
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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;

View File

@@ -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("&", "§");

View File

@@ -0,0 +1,183 @@
package com.playerblocklife;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class MessageManager {
private final PlayerBlockLife plugin;
private FileConfiguration messageConfig;
private File messageFile;
private final Map<String, String> messageCache = new HashMap<>();
public MessageManager(PlayerBlockLife plugin) {
this.plugin = plugin;
this.messageFile = new File(plugin.getDataFolder(), "messages.yml");
}
/**
* 加载消息配置
*/
public void loadMessages() {
ConfigManager config = plugin.getConfigManager();
// 检查是否使用外部消息文件
if (config.useExternalMessageFile()) {
String fileName = config.getExternalMessageFileName();
this.messageFile = new File(plugin.getDataFolder(), fileName);
// 确保配置文件夹存在
if (!plugin.getDataFolder().exists()) {
plugin.getDataFolder().mkdirs();
}
// 如果消息文件不存在从JAR中复制默认配置
if (!messageFile.exists()) {
plugin.saveResource(fileName, false);
plugin.logInfo("创建默认消息配置文件: " + fileName);
}
// 加载消息配置
reloadMessages();
} else {
// 使用config.yml中的消息
plugin.logInfo("使用config.yml中的消息配置");
messageConfig = null;
messageCache.clear();
}
}
/**
* 重新加载消息配置
*/
public void reloadMessages() {
ConfigManager config = plugin.getConfigManager();
if (!config.useExternalMessageFile()) {
return;
}
try {
messageConfig = YamlConfiguration.loadConfiguration(messageFile);
// 加载默认消息作为后备
InputStream defaultStream = plugin.getResource(messageFile.getName());
if (defaultStream != null) {
YamlConfiguration defaultConfig = YamlConfiguration.loadConfiguration(
new InputStreamReader(defaultStream, StandardCharsets.UTF_8));
messageConfig.setDefaults(defaultConfig);
}
// 清空缓存
messageCache.clear();
plugin.logInfo("消息配置已加载: " + messageFile.getName());
} catch (Exception e) {
plugin.logError("加载消息配置文件失败", e);
}
}
/**
* 获取消息
*/
public String getMessage(String path, String defaultValue) {
ConfigManager config = plugin.getConfigManager();
// 检查缓存
String cacheKey = path + "|" + defaultValue;
if (messageCache.containsKey(cacheKey)) {
return messageCache.get(cacheKey);
}
String message;
if (config.useExternalMessageFile() && messageConfig != null) {
// 从外部消息文件获取
message = messageConfig.getString(path, defaultValue);
if (message == null) {
message = defaultValue;
}
} else {
// 从config.yml获取或使用默认值
message = config.getMessage(path, defaultValue);
}
// 替换颜色代码
if (message != null) {
message = message.replace("&", "§");
}
// 缓存结果
messageCache.put(cacheKey, message);
return message;
}
/**
* 获取格式化消息(替换变量)
*/
public String getFormattedMessage(String path, String defaultValue, Map<String, String> variables) {
String message = getMessage(path, defaultValue);
if (message != null && variables != null) {
for (Map.Entry<String, String> entry : variables.entrySet()) {
message = message.replace("{" + entry.getKey() + "}", entry.getValue());
}
}
return message;
}
/**
* 获取控制台消息
*/
public String getConsoleMessage(String path, String defaultValue) {
String message = getMessage("console." + path, defaultValue);
// 移除颜色代码(控制台不需要)
if (message != null) {
message = message.replace("§", "&");
}
return message;
}
/**
* 获取游戏内消息
*/
public String getGameMessage(String path, String defaultValue) {
return getMessage("game." + path, defaultValue);
}
/**
* 获取命令消息
*/
public String getCommandMessage(String command, String path, String defaultValue) {
return getMessage("commands." + command + "." + path, defaultValue);
}
/**
* 获取广播消息
*/
public String getBroadcastMessage(String path, String defaultValue) {
return getMessage("broadcast." + path, defaultValue);
}
/**
* 检查消息文件是否存在
*/
public boolean hasExternalMessageFile() {
return messageFile.exists();
}
/**
* 获取消息文件路径
*/
public String getMessageFilePath() {
return messageFile.getAbsolutePath();
}
}

View File

@@ -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);
} }

View File

@@ -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;
}
/** /**
* 寻找合适的位置 * 寻找合适的位置
*/ */

View File

@@ -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,140 @@ 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));
// 移除颜色代码用于日志
String logMessage = message.replace("&", "");
plugin.getLogger().info(logMessage);
// 发送给玩家
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());
// 移除颜色代码用于日志
String logFailureMsg = failureMsg.replace("&", "");
plugin.getLogger().warning(logFailureMsg);
// 根据配置处理失败
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}");
if (errorMsg != null) {
String errorDetail = e.getMessage() != null ? e.getMessage() : "未知错误";
errorMsg = errorMsg.replace("{player}", player.getName())
.replace("{error}", errorDetail)
.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();

View File

@@ -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" +
"&e/setlifeblocks help &7- 显示此帮助");
if (player.hasPermission("playerblocklife.admin")) { player.sendMessage(helpMessage);
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======================================");
} }
} }

View File

@@ -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} 的生命方块!"

View 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} - 命令用法

View File

@@ -1,5 +1,5 @@
name: PlayerBlockLife name: PlayerBlockLife
version: 1.0.1-1.20.4 version: 2.0.0-1.20.4
main: com.playerblocklife.PlayerBlockLife main: com.playerblocklife.PlayerBlockLife
api-version: 1.20 api-version: 1.20
author: xiaobai author: xiaobai