如何在Kotlin Maven开发的Minecraft插件中修改潜影盒GUI标题
修改潜影盒GUI标题并支持&颜色代码
实现思路
直接打开潜影盒自带的Inventory时,标题是固定的。要修改标题并支持&颜色代码,我们可以通过ProtocolLib拦截窗口打开数据包替换标题内容;同时利用Bukkit的ChatColor.translateAlternateColorCodes方法,将&格式的颜色代码转换为游戏可识别的§符号。
完整修改代码
package me.hoangxuanlam2007.baloshulker import com.comphenix.protocol.PacketType import com.comphenix.protocol.ProtocolLibrary import com.comphenix.protocol.events.PacketAdapter import com.comphenix.protocol.events.PacketEvent import org.bukkit.ChatColor import org.bukkit.Material import org.bukkit.block.ShulkerBox import org.bukkit.command.Command import org.bukkit.command.CommandSender import org.bukkit.entity.Player import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.block.Action import org.bukkit.event.inventory.InventoryCloseEvent import org.bukkit.event.player.PlayerInteractEvent import org.bukkit.inventory.EquipmentSlot import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.BlockStateMeta import org.bukkit.plugin.java.JavaPlugin class BaloShulker : JavaPlugin(), Listener { private val openedShulkers = HashMap<Player, ItemStack>() override fun onEnable() { server.pluginManager.registerEvents(this, this) // 注册ProtocolLib数据包监听器 registerPacketListener() logger.info("BaloShulker plugin enabled!") } override fun onDisable() { logger.info("BaloShulker plugin disabled!") } private fun registerPacketListener() { ProtocolLibrary.getProtocolManager().addPacketListener(object : PacketAdapter(this, PacketType.Play.Server.OPEN_WINDOW) { override fun onPacketSending(event: PacketEvent) { val player = event.player // 仅处理我们插件打开的潜影盒 if (!openedShulkers.containsKey(player)) return val packet = event.packet val windowType = packet.windowType.read(0) // 判断是否是潜影盒窗口 if (windowType != "minecraft:shulker_box") return // 获取潜影盒物品,生成自定义标题 val shulkerItem = openedShulkers[player] ?: return val baseTitle = if (shulkerItem.hasItemMeta() && shulkerItem.itemMeta.hasDisplayName()) { shulkerItem.itemMeta.displayName } else { // 默认标题,可自定义 "&b我的潜影盒" } // 转换&颜色代码 val coloredTitle = ChatColor.translateAlternateColorCodes('&', baseTitle) // 修改数据包中的标题 packet.windowTitle.write(0, coloredTitle) } }) } @EventHandler fun onPlayerInteract(event: PlayerInteractEvent) { val player = event.player val action = event.action val hand = event.hand ?: return val item = if (hand == EquipmentSlot.HAND) player.inventory.itemInMainHand else player.inventory.itemInOffHand if (isShulkerBox(item) && action == Action.RIGHT_CLICK_AIR) { event.isCancelled = true openShulkerBox(player, item) } } private fun isShulkerBox(item: ItemStack): Boolean { return item.type == Material.SHULKER_BOX || item.type.name.endsWith("_SHULKER_BOX") } private fun openShulkerBox(player: Player, shulkerBoxItem: ItemStack) { val shulkerBoxMeta = shulkerBoxItem.itemMeta as? BlockStateMeta ?: return val shulkerBox = shulkerBoxMeta.blockState as? ShulkerBox ?: return player.openInventory(shulkerBox.inventory) openedShulkers[player] = shulkerBoxItem } @EventHandler fun onInventoryClose(event: InventoryCloseEvent) { val player = event.player as? Player ?: return val shulkerBoxItem = openedShulkers.remove(player) ?: return saveShulkerContents(shulkerBoxItem, event.inventory.contents.filterNotNull().toTypedArray()) } override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array<out String>): Boolean { if (command.name.equals("bs", ignoreCase = true) && args.isNotEmpty() && args[0].equals("open", ignoreCase = true)) { if (sender !is Player) { sender.sendMessage("Only players can use this command!") return true } if (!sender.hasPermission("baloshulker.use")) { sender.sendMessage("You don't have permission to use this command!") return true } val mainHandItem = sender.inventory.itemInMainHand val offHandItem = sender.inventory.itemInOffHand when { isShulkerBox(mainHandItem) -> openShulkerBox(sender, mainHandItem) isShulkerBox(offHandItem) -> openShulkerBox(sender, offHandItem) else -> sender.sendMessage("You are not holding a shulker box!") } return true } return false } private fun saveShulkerContents(shulkerItem: ItemStack, contents: Array<ItemStack>) { val shulkerBoxMeta = shulkerItem.itemMeta as? BlockStateMeta ?: return val shulkerBox = shulkerBoxMeta.blockState as? ShulkerBox ?: return shulkerBox.inventory.contents = contents shulkerBox.update() shulkerBoxMeta.blockState = shulkerBox shulkerItem.itemMeta = shulkerBoxMeta } }
关键修改点
- 注册ProtocolLib数据包监听器:在
onEnable中添加registerPacketListener方法,拦截服务器发送的OPEN_WINDOW数据包。 - 标题逻辑处理:
- 优先使用潜影盒物品的自定义名称作为标题
- 无自定义名称时使用默认标题(可自行修改
&b我的潜影盒) - 通过
ChatColor.translateAlternateColorCodes将&转换为§,支持颜色代码
- 精准拦截判断:利用
openedShulkers集合确保只修改我们插件打开的潜影盒窗口,不影响正常放置的潜影盒。
内容的提问来源于stack exchange,提问作者xuanlam2007
相关产品推荐
相关产品推荐

