Why
The standard chest window looks like a chest. If you want your own look — a shop frame, a crafting panel, a background with a logo — the only way without mods is to draw an image as a font glyph right in the inventory title, shifted so it lands over the window.
EffectiveTextureMenu is an EffectiveMenu whose title is assembled for you: shift left, the texture glyph, shift back, and plain text on top. The glyph is registered in the pack automatically.
Minimal example
object ShopMenu : EffectiveTextureMenu() {
override fun getTextureGlyph() = EffectiveGlyph("textures/menu/shop.png", height = 128, ascent = 13)
override fun getTitle() = "Shop"
override fun getNamespacedData() = MyPlugin.instance to "shop"
override fun getSlotsCount() = 27
override fun getFreeSlotSymbol() = null
override fun getPattern(whoOpen: Player?) = listOf(
" ",
" r ",
" ",
)
override fun getSymbolsToItems(whoOpen: Player?) = mapOf(
'r' to SlotData(RubyItem.createItemStack(), listOf(ClickData(ClickType.LEFT) { p -> Shop.buy(p) })),
)
override fun onSlotChanged(player: Player, slot: Int, item: ItemStack, wasPlaced: Boolean) = SlotChangeResult.ALLOW
fun init() {}
}Everything from EffectiveMenu is here too; getTextureGlyph and getTitle are added, getMenuTitle is assembled already. The texture is a PNG the size of the window (176 px wide for a chest, height by row count); blank pattern spots keep the window look while the texture covers it.
override fun getTitleOffset() = -8
override fun getMenuTitle(): String =
getBackspaces(-8) + ChatColor.WHITE + getTextureGlyph().charGlyph() +
getBackspaces(-170) + ChatColor.DARK_GRAY + "Shop" +
BackSpace.R32 * 2 + Forward.R4 + "v2"getTitleOffset — texture shift in pixels (negative is left). For full control override getMenuTitle: getBackspaces(px) builds the shift from glyphs, BackSpace.R128/R32/R4/R1 and Forward.R* can be combined by hand (`R32 * 2` = 64 px left). The colour before the glyph must be white, otherwise the texture gets tinted.
What to override
- getTextureGlyph() *The window texture glyph; registered in the pack for you
- getTitle()Default: nullText over the texture
- getTitleOffset()Default: -8Texture shift in pixels
- getMenuTitle()Default: собранOverride only for full control over the title
* required
Pitfalls
- The inventory title is a string of limited width; too large a shift to the right gets clipped by the client.
- The title glyph is bound by the font texture size limit (see EffectiveGlyph) — 176×166 for a window is fine, 1024×1024 will not load.
- The glyph ascent is tuned by eye to the window height; changing the row count changes it too.
- Shader packs do not interfere: this is a regular font, not a core shader.