16 Commits

Author SHA1 Message Date
xiaobai
f899540449 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 21:02:28 +08:00
xiaobai
1fbd92ec72 1.0.1:Fix error:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:59:33 +08:00
xiaobai
c15b30f666 1.0.1:Fix error:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:58:03 +08:00
xiaobai
8d8cdcb244 1.0.1:Fix error:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:56:03 +08:00
xiaobai
c7d09c3039 1.0.1:Fix error:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:34:20 +08:00
xiaobai
a3cb82c1b7 1.0.1:Fix error:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:33:56 +08:00
xiaobai
c9035d488c 1.0.0 2026-02-13 20:32:43 +08:00
xiaobai
e3b46b6946 1.0.0 2026-02-13 20:32:18 +08:00
xiaobai
f92fdb40c6 1.0.0 2026-02-13 20:31:46 +08:00
xiaobai
dd6c570fa7 修复报错:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:30:45 +08:00
xiaobai
68fadf4e1a Merge remote-tracking branch 'origin/master' 2026-02-13 20:29:50 +08:00
xiaobai
1e6b0cb19e 修复报错:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:29:10 +08:00
xiaobai
e588ca9866 修复报错:[DirectoryProviderSource] Error loading plugin: name is not defined 2026-02-13 20:28:17 +08:00
9e113fc37d 更新 LICENSE 2026-02-13 19:41:02 +08:00
xiaobai
e40fcb344f Merge remote-tracking branch 'origin/master' 2026-02-13 19:39:16 +08:00
xiaobai
231e1acdf5 MIT License 2026-02-13 19:37:46 +08:00
9 changed files with 329 additions and 358 deletions

18
LICENSE Normal file
View File

@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2026 xiaobai
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -4,7 +4,7 @@ plugins {
} }
group = 'com.playerblocklife' group = 'com.playerblocklife'
version = '1.0.0' version = '1.0.1-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.0 pluginVersion=1.0.1-1.20.4
mcVersion=1.20.4 mcVersion=1.20.4

View File

@@ -23,10 +23,9 @@ public class AdminCommands implements CommandExecutor {
} }
if (command.getName().equalsIgnoreCase("pblreload")) { if (command.getName().equalsIgnoreCase("pblreload")) {
plugin.reloadConfig(); // 调用插件的完整重载方法
plugin.getBlockManager().loadData(); plugin.reloadPluginConfig();
plugin.getSkinManager().loadAllSkins(); sender.sendMessage("§a插件配置已完全重载");
sender.sendMessage("§a插件配置已重载");
return true; return true;
} }
@@ -44,7 +43,12 @@ public class AdminCommands implements CommandExecutor {
targetId = target.getUniqueId(); targetId = target.getUniqueId();
} else { } else {
// 尝试从离线玩家获取UUID // 尝试从离线玩家获取UUID
try {
targetId = Bukkit.getOfflinePlayer(targetName).getUniqueId(); targetId = Bukkit.getOfflinePlayer(targetName).getUniqueId();
} catch (Exception e) {
sender.sendMessage("§c找不到玩家: " + targetName);
return true;
}
} }
plugin.getBlockManager().clearPlayerBlocks(targetId); plugin.getBlockManager().clearPlayerBlocks(targetId);
@@ -69,12 +73,21 @@ public class AdminCommands implements CommandExecutor {
} }
} }
if (plugin.getLifeSystem() != null) {
plugin.getLifeSystem().revivePlayer(target); plugin.getLifeSystem().revivePlayer(target);
sender.sendMessage("§a玩家 " + target.getName() + " 已复活!"); sender.sendMessage("§a玩家 " + target.getName() + " 已复活!");
} else {
sender.sendMessage("§c复活失败生命系统未初始化");
}
return true; return true;
} }
if (command.getName().equalsIgnoreCase("pblstats")) { if (command.getName().equalsIgnoreCase("pblstats")) {
if (plugin.getBlockManager() == null) {
sender.sendMessage("§c方块管理器未初始化");
return true;
}
int totalPlayers = plugin.getBlockManager().getPlayerBlocksCount(); int totalPlayers = plugin.getBlockManager().getPlayerBlocksCount();
int totalBlocks = plugin.getBlockManager().getTotalBlocksCount(); int totalBlocks = plugin.getBlockManager().getTotalBlocksCount();
@@ -85,9 +98,11 @@ public class AdminCommands implements CommandExecutor {
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
int blocks = plugin.getBlockManager().getRemainingBlocks(player.getUniqueId()); int blocks = plugin.getBlockManager().getRemainingBlocks(player.getUniqueId());
sender.sendMessage("§7- " + player.getName() + ": §e" + blocks + " §7/ §a5"); String status = blocks > 0 ? "§a存活" : "§c已淘汰";
sender.sendMessage("§7- " + player.getName() + ": §e" + blocks + " §7/ §a5 §7(" + status + "§7)");
} }
sender.sendMessage("§a=================================");
return true; return true;
} }

View File

@@ -1,60 +1,209 @@
package com.playerblocklife; package com.playerblocklife;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class ConfigManager { public class ConfigManager {
private final PlayerBlockLife plugin; private final PlayerBlockLife plugin;
private FileConfiguration config; private FileConfiguration config;
private File configFile;
public ConfigManager(PlayerBlockLife plugin) { public ConfigManager(PlayerBlockLife plugin) {
this.plugin = plugin; this.plugin = plugin;
loadConfig(); this.configFile = new File(plugin.getDataFolder(), "config.yml");
} }
/**
* 加载配置
*/
public void loadConfig() { public void loadConfig() {
plugin.saveDefaultConfig(); // 确保配置文件夹存在
config = plugin.getConfig(); if (!plugin.getDataFolder().exists()) {
plugin.getDataFolder().mkdirs();
} }
public void reloadConfig() { // 如果配置文件不存在从JAR中复制默认配置
plugin.reloadConfig(); if (!configFile.exists()) {
config = plugin.getConfig(); plugin.saveDefaultConfig();
plugin.logInfo("创建默认配置文件");
} }
// 重新加载配置
reloadConfig();
}
/**
* 重新加载配置
*/
public void reloadConfig() {
// 重新从磁盘加载配置
config = YamlConfiguration.loadConfiguration(configFile);
// 加载默认配置作为后备
InputStream defaultConfigStream = plugin.getResource("config.yml");
if (defaultConfigStream != null) {
YamlConfiguration defaultConfig = YamlConfiguration.loadConfiguration(
new InputStreamReader(defaultConfigStream, StandardCharsets.UTF_8));
config.setDefaults(defaultConfig);
}
// 检查配置版本,如果需要则更新
checkConfigVersion();
plugin.logInfo("配置已加载");
}
/**
* 检查配置版本并更新
*/
private void checkConfigVersion() {
int currentVersion = config.getInt("config-version", 1);
int latestVersion = 1; // 最新配置版本
if (currentVersion < latestVersion) {
plugin.logWarning("检测到旧版配置文件,正在更新...");
updateConfig(currentVersion, latestVersion);
}
}
/**
* 更新配置文件
*/
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);
}
// 更新版本号
config.set("config-version", toVersion);
try {
config.save(configFile);
plugin.logInfo("配置文件已更新到版本 " + toVersion);
} catch (IOException e) {
plugin.logError("保存更新后的配置文件失败", e);
}
}
}
/**
* 保存配置
*/
public void saveConfig() {
try {
config.save(configFile);
} catch (IOException e) {
plugin.logError("保存配置文件失败", e);
}
}
/**
* 获取配置对象
*/
public FileConfiguration getConfig() {
if (config == null) {
reloadConfig();
}
return config;
}
// 以下为配置项的获取方法
public int getBlocksPerPlayer() { public int getBlocksPerPlayer() {
return config.getInt("blocks.amount", 5); return getConfig().getInt("blocks.amount", 5);
} }
public int getSpreadRange() { public int getSpreadRange() {
return config.getInt("blocks.spread", 5); return getConfig().getInt("blocks.spread", 5);
} }
public int getDepth() { public int getDepth() {
return config.getInt("blocks.depth", -1); return getConfig().getInt("blocks.depth", -1);
}
public String getBlockMaterial() {
return getConfig().getString("blocks.material", "player_head");
} }
public boolean isDieWhenBlocksGone() { public boolean isDieWhenBlocksGone() {
return config.getBoolean("game.die_when_blocks_gone", true); return getConfig().getBoolean("game.die_when_blocks_gone", true);
} }
public boolean isBecomeSpectator() { public boolean isBecomeSpectator() {
return config.getBoolean("game.become_spectator", true); return getConfig().getBoolean("game.become_spectator", true);
} }
public boolean isHealthSystemEnabled() { public boolean isHealthSystemEnabled() {
return config.getBoolean("game.health_system", true); return getConfig().getBoolean("game.health_system", true);
} }
public boolean isSkinSystemEnabled() { public boolean isSkinSystemEnabled() {
return config.getBoolean("skin.enabled", true); return getConfig().getBoolean("skin.enabled", true);
} }
public String getSkinSource() { public String getSkinSource() {
return config.getString("skin.source", "player_profile"); return getConfig().getString("skin.source", "player_profile");
}
public int getCacheExpireDays() {
return getConfig().getInt("skin.cache.expire_days", 7);
}
public boolean isAutoSaveEnabled() {
return getConfig().getBoolean("storage.auto_save.enabled", true);
}
public int getAutoSaveInterval() {
return getConfig().getInt("storage.auto_save.interval", 300);
}
public String getStorageType() {
return getConfig().getString("storage.type", "yaml");
}
public boolean isBroadcastOnBlockBreak() {
return getConfig().getBoolean("game.broadcast.on_block_break", true);
}
public boolean isBroadcastOnPlayerDeath() {
return getConfig().getBoolean("game.broadcast.on_player_death", true);
}
public int getBroadcastRange() {
return getConfig().getInt("game.broadcast.range", 30);
}
public boolean isGiveExpReward() {
return getConfig().getBoolean("game.break_rewards.give_exp", true);
}
public int getExpRewardAmount() {
return getConfig().getInt("game.break_rewards.exp_amount", 5);
}
public boolean isProtectFromExplosions() {
return getConfig().getBoolean("protection.protect_from_explosions", true);
}
public boolean isProtectFromFire() {
return getConfig().getBoolean("protection.protect_from_fire", true);
}
public boolean isProtectFromPistons() {
return getConfig().getBoolean("protection.protect_from_pistons", true);
} }
public String getMessage(String path, String defaultValue) { public String getMessage(String path, String defaultValue) {
String message = config.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

@@ -1,6 +1,8 @@
package com.playerblocklife; package com.playerblocklife;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.util.logging.Level; import java.util.logging.Level;
public class PlayerBlockLife extends JavaPlugin { public class PlayerBlockLife extends JavaPlugin {
@@ -10,36 +12,40 @@ public class PlayerBlockLife extends JavaPlugin {
private LifeSystem lifeSystem; private LifeSystem lifeSystem;
private ConfigManager configManager; private ConfigManager configManager;
// 在 PlayerBlockLife.java 中添加:
@Override
public void reloadConfig() {
super.reloadConfig();
configManager.reloadConfig();
getLogger().info("配置已重新加载");
}
@Override @Override
public void onEnable() { public void onEnable() {
instance = this; instance = this;
// 第一步:保存默认配置
saveDefaultConfig(); saveDefaultConfig();
// 第二步:初始化管理器(注意顺序!)
this.configManager = new ConfigManager(this); this.configManager = new ConfigManager(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();
// 第四步:注册事件监听器
getServer().getPluginManager().registerEvents(new BlockBreakListener(this), this); getServer().getPluginManager().registerEvents(new BlockBreakListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this); getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerQuitListener(this), this); getServer().getPluginManager().registerEvents(new PlayerQuitListener(this), this);
// 第五步:注册命令
getCommand("setlifeblocks").setExecutor(new SetLifeBlocksCommand(this)); getCommand("setlifeblocks").setExecutor(new SetLifeBlocksCommand(this));
getCommand("checklifeblocks").setExecutor(new CheckLifeBlocksCommand(this)); getCommand("checklifeblocks").setExecutor(new CheckLifeBlocksCommand(this));
getCommand("pblreload").setExecutor(new AdminCommands(this)); getCommand("pblreload").setExecutor(new AdminCommands(this));
getCommand("pbldelete").setExecutor(new AdminCommands(this)); getCommand("pbldelete").setExecutor(new AdminCommands(this));
getCommand("pblrevive").setExecutor(new AdminCommands(this));
getCommand("pblstats").setExecutor(new AdminCommands(this));
// 第六步:加载其他数据
blockManager.loadData(); blockManager.loadData();
skinManager.loadAllSkins(); skinManager.loadAllSkins();
// 第七步:启动定时任务
startScheduler(); startScheduler();
getLogger().info("§a========================================"); getLogger().info("§a========================================");
@@ -50,6 +56,7 @@ public class PlayerBlockLife extends JavaPlugin {
@Override @Override
public void onDisable() { public void onDisable() {
// 保存数据
if (blockManager != null) { if (blockManager != null) {
blockManager.saveData(); blockManager.saveData();
} }
@@ -59,15 +66,57 @@ public class PlayerBlockLife extends JavaPlugin {
getLogger().info("§cPlayerBlockLife 插件已禁用"); getLogger().info("§cPlayerBlockLife 插件已禁用");
} }
/**
* 重写 reloadConfig 方法,避免循环依赖
*/
@Override
public void reloadConfig() {
// 只调用父类的reloadConfig不调用configManager的方法
super.reloadConfig();
getLogger().info("基础配置文件已重新加载");
}
/**
* 插件的完整重载方法(用于命令)
*/
public void reloadPluginConfig() {
if (configManager != null) {
configManager.reloadConfig();
}
if (blockManager != null) {
blockManager.loadData();
}
if (skinManager != null) {
skinManager.loadAllSkins();
}
getLogger().info("插件配置已完全重载");
}
private void startScheduler() { private void startScheduler() {
// 每5分钟自动保存数据
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> { getServer().getScheduler().runTaskTimerAsynchronously(this, () -> {
if (blockManager != null) {
blockManager.saveData(); blockManager.saveData();
}
if (skinManager != null) {
skinManager.saveSkinData(); skinManager.saveSkinData();
}
getLogger().info("数据已自动保存");
}, 6000L, 6000L); }, 6000L, 6000L);
// 每10秒检查玩家生命方块
getServer().getScheduler().runTaskTimer(this, () -> { getServer().getScheduler().runTaskTimer(this, () -> {
if (lifeSystem != null) {
lifeSystem.checkAllPlayers(); lifeSystem.checkAllPlayers();
}
}, 200L, 200L); }, 200L, 200L);
// 每分钟清理一次过期缓存
getServer().getScheduler().runTaskTimerAsynchronously(this, () -> {
if (skinManager != null) {
skinManager.cleanupOldCache();
}
}, 1200L, 1200L);
} }
public static PlayerBlockLife getInstance() { public static PlayerBlockLife getInstance() {

View File

@@ -1,5 +1,5 @@
# PlayerBlockLife 配置文件 # PlayerBlockLife 配置文件
# 版本: 1.0.0 config-version: 1
# 方块设置 # 方块设置
blocks: blocks:
@@ -10,28 +10,7 @@ blocks:
# 方块埋藏深度0为地面负数为地下 # 方块埋藏深度0为地面负数为地下
depth: -1 depth: -1
# 方块材质类型 # 方块材质类型
# 可选值: player_head, custom_block, default
material: player_head material: player_head
# 是否在生成方块时自动填充周围的方块
fill_around: true
# 当使用玩家头颅时的设置
player_head:
# 是否随机旋转头颅方向
random_rotation: true
# 是否显示玩家名字
show_player_name: true
# 是否显示特殊效果
show_effects: true
# 当使用自定义方块时的设置
custom_block:
# 自定义方块材质
material: DIAMOND_BLOCK
# 是否发光
glowing: true
# 发光等级 (0-15)
light_level: 3
# 游戏规则 # 游戏规则
game: game:
@@ -39,59 +18,8 @@ game:
die_when_blocks_gone: true die_when_blocks_gone: true
# 死亡后是否变成观察者 # 死亡后是否变成观察者
become_spectator: true become_spectator: true
# 观察者模式
spectator_mode:
# 是否可以飞行
can_fly: true
# 是否可以看到其他玩家
can_see_players: true
# 是否可以穿墙
can_clip: true
# 是否启用生命值系统 # 是否启用生命值系统
health_system: true health_system: true
# 生命值计算公式
health_formula:
# 方块数量与生命值的关系
# 格式: 方块数量:生命值
5: 20
4: 16
3: 12
2: 8
1: 4
0: 0
# 状态效果
status_effects:
# 当剩余2个方块时
two_blocks_left:
- type: SLOW
amplifier: 1
duration: 100
# 当剩余1个方块时
one_block_left:
- type: SLOW
amplifier: 2
duration: 100
- type: WEAKNESS
amplifier: 0
duration: 100
- type: BLINDNESS
amplifier: 0
duration: 100
# 挖掘奖励
break_rewards:
# 是否给予经验
give_exp: true
# 经验数量
exp_amount: 5
# 是否给予物品
give_items: false
# 物品列表
items:
- DIAMOND:1
- GOLD_INGOT:3
# 广播设置 # 广播设置
broadcast: broadcast:
@@ -101,58 +29,29 @@ game:
range: 30 range: 30
# 玩家死亡时是否全服广播 # 玩家死亡时是否全服广播
on_player_death: true on_player_death: true
# 新玩家加入时是否广播
on_player_join: false # 挖掘奖励
break_rewards:
# 是否给予经验
give_exp: true
# 经验数量
exp_amount: 5
# 皮肤系统 # 皮肤系统
skin: skin:
# 是否启用皮肤系统 # 是否启用皮肤系统
enabled: true enabled: true
# 皮肤来源 # 皮肤来源 (player_profile, local_cache)
source: player_profile source: player_profile
# 可选值: player_profile, mojang_api, local_cache
# player_profile: 从玩家本地缓存获取推荐不调用外部API
# mojang_api: 从Mojang API获取需要网络
# local_cache: 从本地缓存获取
# 缓存设置 # 缓存设置
cache: cache:
# 是否启用缓存
enabled: true
# 缓存过期时间(天) # 缓存过期时间(天)
expire_days: 7 expire_days: 7
# 缓存最大大小MB
max_size_mb: 100
# 默认皮肤(当无法获取玩家皮肤时)
default_skin:
# 使用哪个玩家的皮肤作为默认
player_name: Steve
# 或使用自定义UUID
uuid: 8667ba71-b85a-4004-af54-457a9734eed7
# 是否随机分配默认皮肤
random_default: false
# 可选的默认皮肤列表
available_skins:
- Steve
- Alex
- Enderman
# 皮肤处理
processing:
# 是否异步处理皮肤
async: true
# 处理线程数
threads: 2
# 超时时间(秒)
timeout: 10
# 重试次数
retry_times: 3
# 数据存储 # 数据存储
storage: storage:
# 存储类型 # 存储类型 (yaml, json, sqlite)
# 可选值: yaml, json, sqlite, mysql
type: yaml type: yaml
# 自动保存 # 自动保存
@@ -162,221 +61,22 @@ storage:
# 保存间隔(秒) # 保存间隔(秒)
interval: 300 interval: 300
# YAML存储设置
yaml:
# 数据文件编码
encoding: UTF-8
# 是否压缩
compress: false
# SQLite设置
sqlite:
# 数据库文件路径
file: plugins/PlayerBlockLife/data.db
# 连接池大小
pool_size: 5
# MySQL设置
mysql:
# 数据库主机
host: localhost
# 数据库端口
port: 3306
# 数据库名
database: minecraft
# 用户名
username: root
# 密码
password: password
# 表前缀
table_prefix: pbl_
# 连接池设置
pool:
max_connections: 10
min_connections: 2
connection_timeout: 30000
idle_timeout: 600000
# 消息配置
messages:
# 消息前缀
prefix: "&6[&ePlayerBlockLife&6]&r "
# 消息颜色
colors:
success: "&a"
error: "&c"
warning: "&e"
info: "&7"
highlight: "&6"
# 命令消息
commands:
setlifeblocks:
success: "&a已为你生成 {blocks} 个生命方块!"
already_has: "&c你已经有生命方块了使用 /checklifeblocks 查看位置"
no_skin: "&e你的皮肤正在加载中请稍候..."
failed: "&c无法生成生命方块请确保周围有足够空间"
checklifeblocks:
no_blocks: "&c你还没有设置生命方块使用 /setlifeblocks 来设置"
info: "&a你的生命方块信息"
location: "&7{index}. &e世界: {world} &7坐标: &a{x}&7, &a{y}&7, &a{z}"
remaining: "&7剩余方块: &e{remaining}&7/&a5"
health: "&7当前生命值: &c{health} ❤"
admin:
reload: "&a插件配置已重载"
delete_success: "&a已删除玩家 {player} 的生命方块"
delete_failed: "&c删除失败玩家不存在或没有生命方块"
revive_success: "&a玩家 {player} 已复活!"
revive_failed: "&c复活失败玩家不存在或未死亡"
# 游戏消息
game:
block_destroyed:
owner: "&c⚠ 警告!你的生命方块被 {breaker} 破坏了!"
breaker: "&a你破坏了 {owner} 的生命方块!"
remaining: "&7对方剩余生命方块: &a{remaining}"
broadcast: "&7[附近] &e一个生命方块被破坏了"
death:
title: "&4☠ 你死了!"
subtitle: "&c所有生命方块已被挖光"
broadcast: "&4☠ 玩家 {player} 的生命方块已被全部挖光,惨遭淘汰!"
spectator: "&e你已被淘汰可以观察其他玩家。等待下一轮游戏开始..."
warning:
low_blocks: "&c⚠ 警告!生命方块即将耗尽!"
last_block: "&4⚠ 警告!这是最后一个生命方块!"
health_low: "&4⚠ 警告!生命值过低!"
# 加入消息
join:
welcome: "&e欢迎加入游戏"
welcome_back: "&e欢迎回来{player}"
rules: |
&6游戏规则
&7- 每个玩家有5个生命方块
&7- 方块被其他玩家挖光时,你将死亡
&7- 方块使用你的皮肤作为材质
&7- 你可以自由移动,但方块固定位置
remaining_blocks: "&7你还有 {blocks} 个生命方块"
commands: "&7使用 &e/setlifeblocks &7来设置你的生命方块"
# 效果设置
effects:
# 方块放置效果
place:
particles:
- type: ENCHANTMENT_TABLE
count: 30
offset_x: 0.3
offset_y: 0.3
offset_z: 0.3
speed: 0.1
sounds:
- type: BLOCK_ANVIL_PLACE
volume: 0.5
pitch: 1.2
# 方块破坏效果
break:
particles:
- type: BLOCK_CRACK
count: 50
offset_x: 0.5
offset_y: 0.5
offset_z: 0.5
speed: 0.5
data: PLAYER_HEAD
- type: SMOKE_LARGE
count: 20
offset_x: 0.3
offset_y: 0.3
offset_z: 0.3
speed: 0.05
sounds:
- type: ENTITY_ITEM_BREAK
volume: 1.0
pitch: 0.8
- type: BLOCK_GLASS_BREAK
volume: 0.8
pitch: 1.0
knockback:
enabled: true
power: 0.5
vertical: 0.3
# 玩家受伤效果
damage:
particles:
- type: DAMAGE_INDICATOR
count: 10
sounds:
- type: ENTITY_PLAYER_HURT
volume: 1.0
pitch: 1.0
# 玩家死亡效果
player_death:
particles:
- type: EXPLOSION_HUGE
count: 5
sounds:
- type: ENTITY_WITHER_DEATH
volume: 0.7
pitch: 0.8
- type: ENTITY_LIGHTNING_BOLT_THUNDER
volume: 1.0
pitch: 0.5
# 保护设置 # 保护设置
protection: protection:
# 是否保护生命方块不被非玩家破坏
protect_from_non_players: true
# 是否保护生命方块不被爆炸破坏 # 是否保护生命方块不被爆炸破坏
protect_from_explosions: true protect_from_explosions: true
# 是否保护生命方块不被火焰烧毁 # 是否保护生命方块不被火焰烧毁
protect_from_fire: true protect_from_fire: true
# 是否保护生命方块不被活塞推动 # 是否保护生命方块不被活塞推动
protect_from_pistons: true protect_from_pistons: true
# 是否允许TNT破坏生命方块
allow_tnt_damage: false
# 是否允许苦力怕爆炸破坏生命方块
allow_creeper_explosions: false
# 是否允许末影龙破坏生命方块
allow_ender_dragon_damage: false
# 是否允许其他插件修改生命方块
allow_plugin_modification: false
# 世界保护 # 消息配置(可选,插件会使用默认消息)
world_guard: messages:
# 是否与WorldGuard集成 commands:
enabled: false setlifeblocks:
# 需要保护的地区标志 success: "&a已为你生成 {blocks} 个生命方块!"
region_flags: already_has: "&c你已经有生命方块了使用 /checklifeblocks 查看位置"
- block-break game:
- block-place block_destroyed:
- pvp owner: "&c⚠ 警告!你的生命方块被 {breaker} 破坏了!"
# 白名单地区(允许破坏生命方块的地区) breaker: "&a你破坏了 {owner} 的生命方块!"
whitelist_regions: []
# 黑名单地区(不允许破坏生命方块的地区)
blacklist_regions: []
# 调试设置
debug:
# 是否启用调试模式
enabled: false
# 调试级别
# 可选值: INFO, WARNING, ERROR, DEBUG
level: INFO
# 是否记录到文件
log_to_file: true
# 日志文件路径
log_file: plugins/PlayerBlockLife/debug.log
# 是否显示详细事件日志
verbose_events: false
# 是否记录性能数据
log_performance: false
# 性能日志间隔(秒)
performance_log_interval: 60

View File

@@ -1,35 +1,75 @@
name: PlayerBlockLife
version: 1.0.1-1.20.4
main: com.playerblocklife.PlayerBlockLife
api-version: 1.20
author: xiaobai
description: 玩家生命方块系统 - 方块被挖光则死亡
website: https://github.com/yourname/PlayerBlockLife
prefix: PBL
commands: commands:
setlifeblocks: setlifeblocks:
description: 设置你的生命方块(使用你的皮肤) description: 设置你的生命方块(使用你的皮肤)
usage: /<command> usage: |
/<command> - 设置你的生命方块
/<command> help - 显示帮助
/<command> reset - 重置生命方块位置
/<command> other <玩家> - 为其他玩家设置(管理员)
aliases: [sbl, lifeblocks, setblocks] aliases: [sbl, lifeblocks, setblocks]
permission: playerblocklife.set permission: playerblocklife.set
permission-message: "§c你没有权限使用此命令"
checklifeblocks: checklifeblocks:
description: 查看你的生命方块位置 description: 查看你的生命方块位置
usage: /<command> usage: /<command>
aliases: [cbl, checklife, myblocks] aliases: [cbl, checklife, myblocks]
permission: playerblocklife.check permission: playerblocklife.check
permission-message: "§c你没有权限使用此命令"
pblreload: pblreload:
description: 重载插件配置 description: 重载插件配置
usage: /<command> usage: /<command>
aliases: [pblr, pblreload] aliases: [pblr]
permission: playerblocklife.admin permission: playerblocklife.admin
permission-message: "§c你没有权限使用此命令"
pbldelete: pbldelete:
description: 删除指定玩家的生命方块 description: 删除指定玩家的生命方块
usage: /<command> <玩家> usage: /<command> <玩家>
aliases: [pbldel, deleteblocks] aliases: [pbldel, deleteblocks]
permission: playerblocklife.admin permission: playerblocklife.admin
permission-message: "§c你没有权限使用此命令"
pblrevive: pblrevive:
description: 复活被淘汰的玩家 description: 复活被淘汰的玩家
usage: /<command> [玩家] usage: /<command> [玩家]
aliases: [revive] aliases: [revive]
permission: playerblocklife.admin permission: playerblocklife.admin
permission-message: "§c你没有权限使用此命令"
pblstats: pblstats:
description: 查看插件统计信息 description: 查看插件统计信息
usage: /<command> usage: /<command>
permission: playerblocklife.admin permission: playerblocklife.admin
permission-message: "§c你没有权限使用此命令"
permissions:
playerblocklife.*:
description: 所有 PlayerBlockLife 权限
children:
playerblocklife.set: true
playerblocklife.check: true
playerblocklife.admin: true
default: op
playerblocklife.set:
description: 允许设置生命方块
default: true
playerblocklife.check:
description: 允许查看生命方块
default: true
playerblocklife.admin:
description: 管理员权限
default: op