← Roadmap

EffectiveResourcepack

Resource pack

Why

A custom texture means an item model json, the texture in the right folder, blockstates for blocks, a font for glyphs, sounds.json, then zip, sha1, hosting and sending it to the player on join. All of that per plugin, and a player can receive several packs.

The framework builds a pack per plugin from what EffectiveItem, EffectiveBlock, addGlyph and addSpaceProvider registered. The HTTP server enabled in config.yml serves it, and the player receives the pack on join.

Minimal example

Enable the pack for the plugin
override fun onEnable() {
    RubyItem.init()
    RubyOre.init()

    EffectiveResourcepack.addServerResourcepack(this, "", "")
}

One call per plugin, after all items, blocks and glyphs are initialised. With the HTTP server enabled url and sha1 are ignored — the pack is built from what was registered; with it disabled an external pack at that url and sha1 is registered.

EffectiveSpigot config.yml
resourcepack:
  http-server:
    enable: true
    ip: "203.0.113.10"
    port: 25566

ip is the public server address the client will use. The port must be open.

Own glyph
val LOGO = EffectiveGlyph("font/logo.png", height = 32, ascent = 16)

override fun onEnable() {
    EffectiveResourcepack.addGlyph(this, LOGO)
}

player.sendMessage(Component.text(LOGO.charGlyph()))
External pack (HTTP server disabled)
EffectiveResourcepack.addServerResourcepack(
    this,
    "https://example.com/pack.zip",
    "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
)

Glyphs, offsets, models

EffectiveGlyph — glyph
val ICON = EffectiveGlyph("textures/font/coin.png", height = 8, ascent = 7)

EffectiveResourcepack.addGlyph(MyPlugin.instance, ICON)

player.sendMessage(Component.text(ICON.charGlyph() + " 120"))
meta.displayName(Component.text(ICON.charGlyph()).append(Component.text(" Coin")))

A glyph is a PNG bound to a free Unicode private-area character (EffectiveFontChar). height — height in text pixels, ascent — lift above the baseline (at most height). charGlyph() returns a string with that character — put it anywhere: chat, lore, title, screen.

addSpaceProvider — offsets
val BACK_10 = EffectiveFontChar.getNextFree()
val FWD_3 = EffectiveFontChar.getNextFree()

EffectiveResourcepack.addSpaceProvider(MyPlugin.instance, mapOf(BACK_10 to -10, FWD_3 to 3))

val title = BACK_10() + ICON.charGlyph() + FWD_3() + "Balance"

A character with a negative or positive pixel width — shifts everything after it. This is how glyphs are overlaid and text aligned over a texture. EffectiveTextureMenu ships a ready BackSpace/Forward set.

Own models
override fun getResourcePackData() = ResourcePackData(
    texturePath = "textures/item/wand.png",
    modelJson = """{ "parent": "minecraft:item/handheld", "textures": { "layer0": "myplugin:item/wand" } }""",
)

override fun getResourcePackData() = ResourcePackData(
    modelPath = "models/item/wand.json",
    textureBytes = generatedPng,
)

Item ResourcePackData: texturePath — PNG from the jar (generated model by default), modelJson or modelPath — own model, textureBytes — PNG from memory. The model lands in assets/<plugin>/models/item/<id>.json, item_model is set automatically.

Pitfalls

  • Without addServerResourcepack in onEnable no pack is built for the plugin — items exist, textures do not.
  • addServerResourcepack must come after init() of items and blocks: the pack includes what is already registered.
  • While http-server.enable = false pack generation is off: addServerResourcepack registers an external pack by url instead of building one.
  • Glyph textures are size-limited — the client will not load 4096×4096, the glyph turns into "tofu". Downscale the PNG.
  • The client caches the pack by sha1 — if it did not update, the content did not change or an old zip was served.
  • Vanilla note-block sounds are muted by the framework pack — by design, custom blocks play required.wood.*.