跳到主要内容

7信息组件BaseComponent

打印文本:

/**
* ChatColor的基础用法,与字符串常量拼接, 转换某个字符为颜色代码§
*/
public class PrintMessage implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;

if (Objects.nonNull(args) && args.length > 0) {
String arg = args[0];
switch (arg) {
case "1":
fun1(player);
break;
case "2":
fun2(player);
break;
}
return true;
}
return false;
}
return false;
}

private void fun1(Player player) {
// 用法一:ChatColor拼接
String message1 = ChatColor.GOLD + "你好 " + ChatColor.BOLD + ChatColor.RED + "世界"; // 转义后实际得到的文本 §6你好 §c世界
// 等同于
String message11 = ChatColor.GOLD.toString() + "你好 " + ChatColor.BOLD.toString() + ChatColor.RED.toString() + "世界";
player.sendMessage(message1);

// 用法二:ChatColor.translateAlternateColorCodes(字符,字符串)转换颜色代码
String message2 = ChatColor.translateAlternateColorCodes('&', "&6你好 &l&c世界"); // 转义后实际得到的文本 §6你好 §c世界
player.sendMessage(message2);
}

/**
* 完全自定义的色彩 <br><br>
* <p>
* {@link ChatColor}枚举所提供的色彩存在一定的限制<br>
* 如果需要自定义色彩,我们可以通过{@link net.md_5.bungee.api.ChatColor#of(String)}传入十六进制颜色码来细分色彩
*/
private void fun2(Player player) {
net.md_5.bungee.api.ChatColor color1 = net.md_5.bungee.api.ChatColor.of("#FCF3CF"); // 十六进制的颜色码
net.md_5.bungee.api.ChatColor color2 = net.md_5.bungee.api.ChatColor.of("#F9E79F"); // 十六进制的颜色码
net.md_5.bungee.api.ChatColor color3 = net.md_5.bungee.api.ChatColor.of("#F7DC6F"); //...
net.md_5.bungee.api.ChatColor color4 = net.md_5.bungee.api.ChatColor.of("#F4D03F");
net.md_5.bungee.api.ChatColor color5 = net.md_5.bungee.api.ChatColor.of("#F1C40F");
net.md_5.bungee.api.ChatColor color6 = net.md_5.bungee.api.ChatColor.of("#D4AC0D");

// 发送 纯文本 这里也是用了toString()特性
String pureText = MessageFormat.format("{0}大{1}家{2}好{3}啊{4}欢{5}迎", color1, color2, color3, color4, color5, color6);
// pureText.equals(message) == true
String message = color1 + "大" + color2 + "家" + color3 + "好" + color4 + "啊" + color5 + "欢" + color6 + "迎";
player.sendMessage(pureText + ChatColor.translateAlternateColorCodes('&', " &f sent in pure text form!"));


// color1实际对应的颜色代码
MyPlugin.instance.getLogger().info("color1实际对应的颜色代码" + color1);
}
}

效果:

image-20240910001921736

打印标题:

/**
* 在玩家的屏幕中心展示一个标题和一个副标题
*/
public class PrintTitle implements CommandExecutor {

/**
* 屏幕中心区域的标题与副标题
* 需要直接通过{@link org.bukkit.entity.Player#sendTitle(String, String, int, int, int)}来发送,
*/
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
// 标题: §l§6Area Discovered
StringBuilder titleBuilder = new StringBuilder()
.append(ChatColor.BOLD).append(ChatColor.GOLD).append("Area Discovered");
// 副标题: §eRagni
StringBuilder subTitle = new StringBuilder()
.append(ChatColor.YELLOW).append("Ragni");

/**
* 发送标题和副标题
* 参数一:标题
* 参数二:副标题
* 参数三:渐入花费的时间(tick单位)
* 参数四:标题停留的时间(tick单位)
* 参数五:渐出花费的时间(tick单位)
*/
player.sendTitle(titleBuilder.toString(), subTitle.toString(), 24, 60, 24);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1); // 模仿wynncraft的区域发现音效

return true;
}
return false;
}
}

效果:

image-20240910002126056

鼠标悬浮:

public class PrintTextComponent implements CommandExecutor {

/**
* {@link TextComponent} 是 {@link BaseComponent}抽象类的一个子类,在继承信息组件所必有的 "文本"、"字体色彩"、"字体样式"<br>
* 的同时,TextComponent还具备了 鼠标的点击以及悬浮事件。</br>
* 最终信息组件需要使用 {@link Player#spigot()} 来发送,这是发送组件与发送字符串常量的区别所在。
*/
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;

//步骤一:创建信息组件,一个用于显示在聊天框,另一个显示在物品栏上方
TextComponent chatMessage = getTextComponent();
BaseComponent[] actionBarMessage = getComponents(player);

//步骤二:获取玩家的Spigot对象
Player.Spigot spigot = player.spigot();

//步骤三:通过Spigot对象将信息组件发送给玩家 [可选位置:聊天框、物品栏上方、系统级提示]
//spigot.sendMessage(textComponent); //默认的发送位置为ChatMessageType.CHAT,也就是在聊天框里显示
spigot.sendMessage(ChatMessageType.CHAT, chatMessage); //还可以将位置改为ChatMessageType.ACTION_BAR,此时就能够显示在经验条、血量条上方的区域
spigot.sendMessage(ChatMessageType.ACTION_BAR, actionBarMessage); //还可以将位置改为ChatMessageType.SYSTEM,实际的效果与ChatMessageType.CHAT一样,区别在于这是系统级别的消息

return true;
}
return false;
}

private TextComponent getTextComponent() {
TextComponent text1 = new TextComponent("你好");
text1.setColor(net.md_5.bungee.api.ChatColor.RED); //设置颜色
text1.setBold(true); //设置粗体
//text1.setItalic(true); //设置斜体
//text1.setObfuscated(true); //设置模糊(效果是不停变换的乱码)
//...

//添加点击事件 其实本质上是让玩家说了一句话,不信你可以把这里"/help TextComponentPlugin"中的斜杠去掉
text1.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/help TextComponentPlugin"));
//添加鼠标悬浮事件
text1.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("这是一个鼠标悬浮提示")));

//拼接下一段信息
TextComponent text2 = new TextComponent("世界");
text2.setBold(false);
text2.setObfuscated(true);
text2.setColor(net.md_5.bungee.api.ChatColor.GREEN);

//组件的拼接会自动继承上一个组件的颜色、粗体、斜体、鼠标事件等属性
text1.addExtra(text2); //拼接下一段信息

//player.spigot().sendMessage(text1, text2); 不想拼接的话,可以这样写,记得不要用text1.addExtra(text2);
return text1;
}

private BaseComponent[] getComponents(Player player) {
//由于组件构造器的特殊性,必须.append()在前,然后在指定[颜色、字体、粗体、斜体、模糊]等样式
return new ComponentBuilder()
.append("当前所在位置:").color(ChatColor.RED).bold(true)
.append(player.getLocation().getBlockX() + " ").color(ChatColor.GOLD).bold(false)
.append(player.getLocation().getBlockY() + " ").color(ChatColor.YELLOW)
.append(player.getLocation().getBlockZ() + " ").color(ChatColor.GREEN)
.append(" ").color(ChatColor.BLUE)
.append("延迟:" + player.getPing()).color(ChatColor.DARK_PURPLE).bold(true)
.append("...").color(ChatColor.LIGHT_PURPLE).italic(true)
.create();
}
}

效果:

image-20240910002226841

image-20240910002233188

建造者:

public class PrintComponentBuilder implements CommandExecutor {
ChatColor color1 = ChatColor.of("#FCF3CF"); //十六进制的颜色码
ChatColor color2 = ChatColor.of("#F9E79F"); //十六进制的颜色码
ChatColor color3 = ChatColor.of("#F7DC6F"); //...
ChatColor color4 = ChatColor.of("#F4D03F");
ChatColor color5 = ChatColor.of("#F1C40F");
ChatColor color6 = ChatColor.of("#D4AC0D");

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {

if (sender instanceof Player) {
Player player = (Player) sender;

executeFun(player);

return true;
}

return false;
}

private void executeFun(Player player) {
BaseComponent[] components1 = new ComponentBuilder()
.append("大").color(color1).bold(true)
.append("家").color(color2).italic(true)
.append("好").color(color3).obfuscated(true)
.append("啊").color(color4).underlined(true)
.create();

//为什么需要单独再构建出一个components2? 是为了防止继承上一个组件的属性,下面的components3同理
BaseComponent[] components2 = new ComponentBuilder()
.append("欢").color(color5)
.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "虽然是发送指令,可实际上只是说了句话罢了"))
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("这个字可以点哦")))
.create();

BaseComponent[] components3 = new ComponentBuilder()
.append("迎").color(color6) //不单独构造,则会继承上一个组件的event事件等属性
.create();

TextComponent[] result = new TextComponent[]{new TextComponent(components1), new TextComponent(components2), new TextComponent(components3)};
//发送 组件
player.spigot().sendMessage(result);
}

}

打印Boss血条:

public class PrintBossBar implements CommandExecutor {

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;

executeFun(player);

return true;
}
return false;
}

/**
* BossBar 也就是打末影龙、凋零时出现的boss血条<br>
* 创建好的bossBar默认不会提示给所有玩家,需要使用 {@link BossBar#addPlayer(Player)}来指定谁会收到提示。<br>
* 同理,不想让玩家看到bossBar就要用到 {@link BossBar#removePlayer(Player)} 或 {@link BossBar#removeAll()} <br><br>
* 如果只是单纯的将进度条设置为0,玩家依旧能看到进度条。<br>
* <code>
* bossBar.setProgress(0d); // 仍会显示,所以一定要记得手动removePlayer
* </code>
*/
private void executeFun(Player player) {
// 通过Bukkit创建BossBar
BossBar bossBar = Bukkit.createBossBar("这是BOSS条的名字", BarColor.GREEN, BarStyle.SEGMENTED_6, BarFlag.DARKEN_SKY);
bossBar.addPlayer(player); // 用bossBar对象添加玩家,只有该玩家才能看见boss进度条

// 创建定时任务
Plugin plugin = MyPlugin.instance; // 拿到插件实例
BukkitScheduler scheduler = Bukkit.getScheduler(); // 拿到Schedule线程调度器
AtomicInteger atomicInteger = new AtomicInteger(6);

// 执行异步循环任务,拿到taskId
int taskId = scheduler.scheduleSyncRepeatingTask(plugin, new Runnable() {
@Override
public void run() {
player.sendMessage("当前的boss bar进度:" + atomicInteger.get() * (1d / 6d)); // 发送消息
bossBar.setProgress(atomicInteger.decrementAndGet() * (1d / 6d)); // 修改进度条进度,实参是double类型
}
}, 0, 2 * 20); // 0秒后执行,每2秒执行一次

// 根据taskId取消 repeatAsyncTask的重复执行
scheduler.runTaskLater(plugin, new Runnable() {
@Override
public void run() {
bossBar.removePlayer(player); // 移除玩家,不让玩家继续看到进度条
bossBar.setVisible(false); // 设置进度条不可见
scheduler.cancelTask(taskId); // 取消任务
}
}, 6 * 2 * 20); // 6秒后执行
}
}

效果:

image-20240910002427218

打印键盘绑定:

/**
* 按键绑定信息
*/
public class PrintKeyBind implements CommandExecutor {


/**
* 玩家绑定的按键 <br>
* Spigot可以获取到玩家的 攻击、丢弃物品等快捷键所绑定的案件是什么。<br>
* 按键key的类型可以参考 <a href="https://minecraft.fandom.com/zh/wiki/%E6%8E%A7%E5%88%B6">MC wiki</a> 以及{@link Keybinds} <br>
* 服务器可以根据客户端的 ”语言和绑定的按键” 来决定应该输出哪种语言的按键名称。
*/
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;

executeFun(player);

return true;
}
return false;
}

private void executeFun(Player player) {
KeybindComponent key1 = new KeybindComponent();
key1.setKeybind(Keybinds.ATTACK); // 攻击,默认左键
key1.addExtra(":攻击键");

KeybindComponent key2 = new KeybindComponent();
key2.setKeybind("key.drop"); // 丢弃物品,默认Q键------ 我自定义的是R键 英文:r 中文:r
key2.addExtra(":丢弃物品");

KeybindComponent key3 = new KeybindComponent("key.playerlist");
key3.addExtra(":玩家列表"); // 玩家列表,默认Tab键---- 我定义的是`键

player.spigot().sendMessage(key1);
player.spigot().sendMessage(key2);
player.spigot().sendMessage(key3);
}
}

效果:

image-20240910002404521