Skip to content

Commit

Permalink
[6.1.0][dev] 完善 UI 模块
Browse files Browse the repository at this point in the history
  • Loading branch information
Bkm016 committed Jan 28, 2024
1 parent 3e5152d commit e7e7f20
Show file tree
Hide file tree
Showing 26 changed files with 410 additions and 344 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,12 @@ class KetherLoader : ClassVisitor(0) {

/** 注册 Parser */
fun registerParser(parser: ScriptActionParser<*>, name: Array<String>, namespace: String = "kether", shared: Boolean = false) {
// 共享 Parser 到所有 TabooLib 插件
if (shared) {
sharedParser += name to namespace
getOpenContainers().forEach { it.call(StandardChannel.REMOTE_ADD_ACTION, arrayOf(pluginId, name, namespace)) }
}
// 注册到自己
name.forEach { Kether.addAction(it, parser, namespace) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import org.bukkit.event.inventory.InventoryDragEvent
import org.bukkit.event.inventory.InventoryInteractEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import taboolib.module.ui.type.Basic
import taboolib.module.ui.type.Chest
import taboolib.module.ui.virtual.RemoteInventory
import taboolib.module.ui.virtual.VirtualInventoryInteractEvent

/**
* @author 坏黑
* @since 2019-05-21 18:09
*/
class ClickEvent(private val bukkitEvent: InventoryInteractEvent, val clickType: ClickType, val slot: Char, val builder: Basic) {
class ClickEvent(private val bukkitEvent: InventoryInteractEvent, val clickType: ClickType, val slot: Char, val builder: Chest) {

val clicker: Player
get() = bukkitEvent.whoClicked as Player
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import taboolib.common.platform.PlatformSide
import taboolib.common.platform.event.SubscribeEvent
import taboolib.common.platform.function.submit
import taboolib.common.platform.function.submitAsync
import taboolib.module.ui.type.impl.BasicImpl
import taboolib.module.ui.type.impl.ChestImpl
import taboolib.platform.util.isNotAir
import taboolib.platform.util.setMeta

Expand All @@ -38,7 +38,7 @@ internal object ClickListener {

@SubscribeEvent
fun onOpen(e: InventoryOpenEvent) {
val builder = MenuHolder.fromInventory(e.inventory) as? BasicImpl ?: return
val builder = MenuHolder.fromInventory(e.inventory) as? ChestImpl ?: return
// 构建回调
submit {
builder.buildCallback(e.player as Player, e.inventory)
Expand All @@ -54,7 +54,7 @@ internal object ClickListener {
@Suppress("DuplicatedCode")
@SubscribeEvent
fun onClick(e: InventoryClickEvent) {
val builder = MenuHolder.fromInventory(e.inventory) as? BasicImpl ?: return
val builder = MenuHolder.fromInventory(e.inventory) as? ChestImpl ?: return
// 锁定主手
if (builder.handLocked && (e.rawSlot - e.inventory.size - 27 == e.whoClicked.inventory.heldItemSlot || e.click == org.bukkit.event.inventory.ClickType.NUMBER_KEY && e.hotbarButton == e.whoClicked.inventory.heldItemSlot)) {
e.isCancelled = true
Expand Down Expand Up @@ -101,15 +101,15 @@ internal object ClickListener {

@SubscribeEvent
fun onDrag(e: InventoryDragEvent) {
val menu = MenuHolder.fromInventory(e.inventory) as? BasicImpl ?: return
val menu = MenuHolder.fromInventory(e.inventory) as? ChestImpl ?: return
val clickEvent = ClickEvent(e, ClickType.DRAG, ' ', menu)
menu.clickCallback.forEach { it.invoke(clickEvent) }
menu.selfClickCallback(clickEvent)
}

@SubscribeEvent
fun onClose(e: InventoryCloseEvent) {
val menu = MenuHolder.fromInventory(e.inventory) as? BasicImpl ?: return
val menu = MenuHolder.fromInventory(e.inventory) as? ChestImpl ?: return
// 标题更新 && 跳过关闭回调
if (menu.isUpdateTitle && menu.isSkipCloseCallbackOnUpdateTitle) {
return
Expand Down
6 changes: 3 additions & 3 deletions module/module-ui/src/main/kotlin/taboolib/module/ui/Menu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ interface Menu {

init {
impl[Anvil::class.java] = AnvilImpl::class.java
impl[Basic::class.java] = BasicImpl::class.java
impl[Chest::class.java] = ChestImpl::class.java
impl[Hopper::class.java] = HopperImpl::class.java
impl[Linked::class.java] = LinkedImpl::class.java
impl[Stored::class.java] = StoredImpl::class.java
impl[PageableChest::class.java] = PageableChestImpl::class.java
impl[StorableChest::class.java] = StorableChestImpl::class.java
}

/** 注册实现 */
Expand Down
30 changes: 28 additions & 2 deletions module/module-ui/src/main/kotlin/taboolib/module/ui/MenuBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@ import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import taboolib.common.OpenListener
import taboolib.common.OpenResult
import taboolib.common.event.InternalEventBus
import taboolib.common.platform.Awake
import taboolib.common.platform.function.getOpenContainers
import taboolib.module.nms.PacketSendEvent
import taboolib.module.ui.type.impl.BasicImpl
import taboolib.module.ui.type.impl.ChestImpl
import taboolib.module.ui.virtual.InventoryHandler
import taboolib.module.ui.virtual.VirtualInventory
import taboolib.module.ui.virtual.inject
import taboolib.module.ui.virtual.openVirtualInventory
import taboolib.platform.util.isNotAir

/**
* 允许在 Vanilla Inventory 中使用 Raw Title
*/
var isRawTitleInVanillaInventoryEnabled = false
private set

Expand All @@ -27,7 +34,12 @@ var isRawTitleInVanillaInventoryEnabled = false
* 虚拟菜单不需要开启该选项
*/
fun enableRawTitleInVanillaInventory() {
// 防止重复注册
if (isRawTitleInVanillaInventoryEnabled) {
return
}
isRawTitleInVanillaInventoryEnabled = true
// 监听数据包
InternalEventBus.listen<PacketSendEvent> { e ->
if (e.packet.name == "PacketPlayOutOpenWindow") {
// 全版本都是 c,不错
Expand All @@ -37,6 +49,20 @@ fun enableRawTitleInVanillaInventory() {
}
}
}
// 告知所有 TabooLib 插件,该监听器已被注册
getOpenContainers().forEach { it.call("LISTEN_RAW_TITLE_IN_VANILLA_INVENTORY", emptyArray()) }
}

@Awake
class RawTitleOpenListener : OpenListener {

override fun call(name: String, data: Array<out Any>?): OpenResult {
if (name == "LISTEN_RAW_TITLE_IN_VANILLA_INVENTORY") {
isRawTitleInVanillaInventoryEnabled = true
return OpenResult.successful()
}
return OpenResult.failed()
}
}

/**
Expand Down Expand Up @@ -67,7 +93,7 @@ fun HumanEntity.openMenu(buildMenu: Inventory, changeId: Boolean = true) {
if (buildMenu is VirtualInventory) {
val remoteInventory = openVirtualInventory(buildMenu, changeId)
val basic = MenuHolder.fromInventory(buildMenu)
if (basic is BasicImpl) {
if (basic is ChestImpl) {
remoteInventory.inject(basic)
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package taboolib.module.ui
import org.bukkit.Bukkit
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.InventoryHolder
import taboolib.module.ui.type.Basic
import taboolib.module.ui.type.Chest

/**
* @author 坏黑
* @since 2019-05-21 20:28
*/
@Suppress("LeakingThis")
open class MenuHolder(val menu: Basic) : InventoryHolder {
open class MenuHolder(val menu: Chest) : InventoryHolder {

private val inventory = Bukkit.createInventory(this, if (menu.rows > 0) menu.rows * 9 else menu.slots.size * 9, menu.title)

Expand All @@ -20,7 +20,7 @@ open class MenuHolder(val menu: Basic) : InventoryHolder {

companion object {

fun fromInventory(inventory: Inventory): Basic? {
fun fromInventory(inventory: Inventory): Chest? {
return (inventory.holder as? MenuHolder)?.menu
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.bukkit.inventory.Inventory
/**
* 铁砧容器
*/
interface Anvil : Basic {
interface Anvil : Chest {

/** 当物品被重命名时 */
fun onRename(callback: (Player, String, Inventory) -> Unit)
Expand Down
166 changes: 4 additions & 162 deletions module/module-ui/src/main/kotlin/taboolib/module/ui/type/Basic.kt
Original file line number Diff line number Diff line change
@@ -1,167 +1,9 @@
package taboolib.module.ui.type

import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import taboolib.library.xseries.XMaterial
import taboolib.module.ui.ClickEvent
import taboolib.module.ui.Menu
import taboolib.module.ui.MenuHolder
import taboolib.platform.util.ItemBuilder
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
import taboolib.module.ui.type.impl.ChestImpl

/**
* 标准容器
* 向下兼容
*/
interface Basic : Menu {

/** 获取行数 */
val rows: Int

/** 是否正在使用虚拟化 */
val virtualized: Boolean

/** 虚拟化时玩家背包内容 */
val virtualizedStorageContents: List<ItemStack>?

/** 物品与对应抽象字符关系 **/
val items: ConcurrentHashMap<Char, ItemStack>

/** 抽象字符布局 **/
val slots: CopyOnWriteArrayList<List<Char>>

/** 是否锁定主手 **/
val handLocked: Boolean

/** 是否打开过 **/
val isOpened: Boolean

/**
* 启用虚拟化页面(将自动阻止所有点击行为)
*/
fun virtualize(storageContents: List<ItemStack>? = null)

/**
* 隐藏玩家背包(自动启动虚拟页面)
*/
fun hidePlayerInventory()

/**
* 行数
* 为 1 - 6 之间的整数,并非原版 9 的倍数
*/
fun rows(rows: Int)

/**
* 设置是否锁定玩家手部动作
* 设置为 true 则将阻止玩家在使用菜单时进行包括但不限于
* 丢弃物品,拿出菜单物品等行为
*
* @param handLocked 锁定
*/
fun handLocked(handLocked: Boolean)

/**
* 设置 MenuHolder 创建回调
*/
fun holder(func: (menu: Basic) -> MenuHolder)

/**
* 页面构建时触发回调
* 可选是否异步执行
*/
fun onBuild(async: Boolean = false, callback: (player: Player, inventory: Inventory) -> Unit)

/**
* 页面关闭时触发回调
* 只能触发一次(玩家客户端强制关闭时会触发两次原版 InventoryCloseEvent 事件)
*
* TODO 2023/10/09 若启用虚拟化菜单,则 player.closeInventory() 不会触发该回调函数
*/
fun onClose(once: Boolean = true, skipUpdateTitle: Boolean = true, callback: (event: InventoryCloseEvent) -> Unit)

/**
* 点击事件回调
* 仅在特定位置下触发
*/
fun onClick(bind: Int, callback: (event: ClickEvent) -> Unit = {})

/**
* 点击事件回调
* 仅在特定位置下触发
*/
fun onClick(bind: Char, callback: (event: ClickEvent) -> Unit = {})

/**
* 整页点击事件回调
* 可选是否自动锁定点击位置
*/
fun onClick(lock: Boolean = false, callback: (event: ClickEvent) -> Unit = {})

/**
* 使用抽象字符页面布局
*/
fun map(vararg slots: String)

/**
* 根据抽象符号设置物品
*/
fun set(slot: Char, itemStack: ItemStack)

/**
* 根据位置设置物品
*/
fun set(slot: Int, itemStack: ItemStack)

/**
* 根据抽象符号设置物品
*/
fun set(slot: Char, callback: () -> ItemStack)

/**
* 根据位置设置物品
*/
fun set(slot: Int, callback: () -> ItemStack)

/**
* 根据抽象符号设置物品
*/
fun set(slot: Char, material: XMaterial, itemBuilder: ItemBuilder.() -> Unit = {})

/**
* 根据位置设置物品
*/
fun set(slot: Int, material: XMaterial, itemBuilder: ItemBuilder.() -> Unit = {})

/**
* 根据抽象符号设置物品
*/
fun set(slot: Char, itemStack: ItemStack, onClick: ClickEvent.() -> Unit = {})

/**
* 根据位置设置物品
*/
fun set(slot: Int, itemStack: ItemStack, onClick: ClickEvent.() -> Unit = {})

/**
* 获取位置对应的抽象字符
*/
fun getSlot(slot: Int): Char

/**
* 获取抽象字符对应的位置
*/
fun getSlots(slot: Char): List<Int>

/**
* 获取抽象字符对应的首个位置
*/
fun getFirstSlot(slot: Char): Int

/**
* 更新标题
*/
fun updateTitle(title: String)
}
@Deprecated("Use Chest instead.", ReplaceWith("Chest"))
open class Basic(override var title: String) : ChestImpl(title)
Loading

0 comments on commit e7e7f20

Please sign in to comment.