Related: APIๆฆ่ง.md ยท ๆฐๆฎๅญๅจไธๅ ไฝ็ฌฆ.md ยท ../02-ๆไธปๆๅ/่ชๅฎไนGUI.md ยท ../05-ๅ่/ๆฏ่ฏญ่กจ.md
๐ผ๏ธ GUI Programming API (CustomGuiManager) โ
This page covers programmatic GUI operations โ opening / rendering / feeding data using Kotlin code. For the GUI YAML fields (layout, icons, click actions, etc.), see the server-owner doc ../02-ๆไธปๆๅ/่ชๅฎไนGUI.md; this page only covers the code side.
The core entry point is CustomGuiManager.
1. Initialization and config loading โ
CustomGuiManager.init(plugin) // Usually called once in onEnable
CustomGuiManager.loadAllGuis() // Load all GUI configs
CustomGuiManager.reloadAllGuis() // Reload
CustomGuiManager.loadedGuiCount() // Number already loaded
val config = CustomGuiManager.getGuiConfig("shop") // Get a specific GUI config2. Opening a GUI โ
2.1 openGui โ open an already-loaded config GUI โ
CustomGuiManager.openGui(
player,
"shop", // GUI id
placeholderProvider = null, // Optional: placeholder provider for this open
actionHandler = null // Optional: action handler for this open
)Both placeholderProvider and actionHandler are optional: pass them to use a dedicated one for this open, injecting different data / behavior into the same GUI across different scenarios.
2.2 openGuiFromConfig โ open from a given config section, with session data โ
CustomGuiManager.openGuiFromConfig(
player,
section, // Config section
guiId = "shop",
sessionData = mapOf("page" to 1), // Session data, readable during render
placeholderProvider = null,
actionHandler = null
)2.3 openDynamic โ pure-code dynamic GUI โ
Reads no config, drawn entirely by code:
CustomGuiManager.openDynamic(
player,
rows = 3, // Number of rows
title = "My Backpack",
openSound = null, // Optional open sound
closeSound = null, // Optional close sound
render = { gui, inventory ->
// Fill items into gui / inventory here (see section 5, DynamicGui)
gui.setItem(13, ItemStack(Material.DIAMOND)) { clickType ->
player.sendMessage("Clicked the diamond: $clickType")
false // Return whether to refresh the interface
}
}
)2.4 openDynamicFromConfig โ
openDynamicFromConfig(...) โ takes the basic info (title / rows / sounds, etc.) from config, then draws content with code via render. It is a middle ground between the two above.
3. Registering custom placeholders โ
3.1 CustomGuiManager.registerPlaceholder โ
The simplest one: register a key โ player-related string placeholder.
CustomGuiManager.registerPlaceholder("coins") { player ->
getCoins(player).toString()
}
// Write this key in the GUI text; it gets replaced at render time3.2 PlaceholderManager โ layered placeholders โ
PlaceholderManager provides registration at three granularities:
| Method | Scope |
|---|---|
registerPlaceholder(...) | Global placeholder |
registerGuiPlaceholder(...) | Placeholder within a specific GUI |
registerItemPlaceholder(...) | Placeholder for a specific item / slot |
PlaceholderManager.registerPlaceholder("server_name") { "Qinhuai Server" }
PlaceholderManager.registerGuiPlaceholder(/* guiId, key, resolver */)
PlaceholderManager.registerItemPlaceholder(/* ... */)4. Wiring up a paginated data source (GuiDataProvider) โ
When a GUI needs to display a long, page-turnable list of content (online players, products, leaderboards, etc.), implement GuiDataProvider. It has two sub-interfaces:
4.1 GuiPaginationListProvider โ paginated list โ
interface GuiPaginationListProvider : GuiDataProvider {
fun loadEntries(player: Player, gui: /*Gui*/, sourceValue: String): List<GuiPaginationEntry>
}loadEntries returns a list of GuiPaginationEntry; the framework handles paginated display.
GuiPaginationEntry fields:
| Field | Description |
|---|---|
placeholders: Map | This entry's placeholders (filled into the icon's name / lore) |
displayItem (nullable) | Directly specify the display item |
leftAction (nullable) | Left-click action |
rightAction (nullable) | Right-click action |
action (nullable) | General action |
class FriendListProvider : GuiPaginationListProvider {
override fun loadEntries(player: Player, gui: Gui, sourceValue: String): List<GuiPaginationEntry> {
return getFriends(player).map { friend ->
GuiPaginationEntry(
placeholders = mapOf(
"name" to friend.name,
"status" to friend.statusText()
),
leftAction = "tp ${friend.name}",
rightAction = "msg ${friend.name}"
)
}
}
}๐ Built-in data source
online_players: QCL ships with an online-players data source. Just referenceonline_playersdirectly in the GUI config to paginate the online players โ no need to implement it yourself.
4.2 GuiDynamicSlotProvider โ dynamic single slot โ
interface GuiDynamicSlotProvider : GuiDataProvider {
fun loadItem(/* player, gui, ... */): ItemStack
}Use this when a slot's item needs to change per player / real-time state (e.g. "current party icon").
5. DynamicGui โ drawing with code โ
The gui given to you by openDynamic / openDynamicFromConfig is a DynamicGui. Use setItem to place an item into a slot and attach a click callback:
gui.setItem(slot, itemStack) { clickType ->
// Handle the click
when (clickType) {
ClickType.LEFT -> doBuy(player)
ClickType.RIGHT -> doInfo(player)
else -> {}
}
true // Return Boolean: true = refresh the interface after the click, false = don't refresh
}- The third parameter is the click callback
(clickType) -> Boolean. - The return value indicates whether to refresh:
trueredraws the interface (good for switching pages, changing state),falsekeeps it unchanged.
Full dynamic GUI example:
CustomGuiManager.openDynamic(
player,
rows = 6,
title = "Shop",
render = { gui, inventory ->
shopItems.forEachIndexed { i, item ->
gui.setItem(i, item.icon) { click ->
if (click == ClickType.LEFT) {
buy(player, item)
true // Refresh after buying (update stock / balance display)
} else false
}
}
}
)6. Summary of placeholderProvider / actionHandler injection โ
When opening a GUI you can inject two kinds of callbacks, letting the same GUI config adapt to different scenarios:
placeholderProviderโ the placeholder source dedicated to this open (overrides / supplements the global placeholders).actionHandlerโ the action handler dedicated to this open (clicks go through it).
CustomGuiManager.openGui(player, "profile",
placeholderProvider = { key -> profileData[key] },
actionHandler = myActionHandler
)๐ Continue reading โ
- ../02-ๆไธปๆๅ/่ชๅฎไนGUI.md โ GUI YAML fields and server-owner configuration
- ๆฐๆฎๅญๅจไธๅ ไฝ็ฌฆ.md โ PapiBridge and %qcl_xxx% placeholders
- ๅจไฝไธๆ่ฝๆกฅ.md โ the action system behind click actions
- ../05-ๅ่/ๆฏ่ฏญ่กจ.md โ terminology definitions