Skip to main content
Version: Minecraft 26.2

Tags and creative tabs

Tags​

A tag groups entries of one registry under a name such as #minecraft:mineable/pickaxe. The tag API is in dev.polymodloader.api.tag.

static final TagKey WARDED = TagKey.block(ResourceId.of("my_mod", "warded"));
static final TagKey SPARKLY = TagKey.item(ResourceId.of("my_mod", "sparkly"));
static final TagKey PICKAXE_MINEABLE = TagKey.block(ResourceId.minecraft("mineable/pickaxe"));
static final TagKey SKELETONS = TagKey.entityType(ResourceId.minecraft("skeletons"));
  • A TagKey is only a name: a TagRegistry (BLOCK, ITEM, ENTITY_TYPE) and an ID without the #. Create keys once and keep them in constants.
  • The entries come from data packs and mod jars (data/<namespace>/tags/<block|item|entity_type>/<path>.json) and from addToTag. They change on /reload.
  • Block, item, and entity type tags are supported.

Querying tags​

world.isBlockIn(pos, WARDED); // the block at a position
player.mainHandStack().isIn(SPARKLY); // an item stack (ItemStackRef)
entity.isIn(SKELETONS); // an entity's type
world.tags().contains(SPARKLY, ResourceId.of("my_mod", "spark")); // any entry
world.tags().entries(SPARKLY); // every entry
MethodMeaning
WorldView.tags()A TagView for the tags this world's side loaded
TagView.contains(tag, entry)Whether a block, item, or entity type ID is in the tag, nested tags included
TagView.entries(tag)Every entry of the tag, nested tags resolved, in the game's order. Empty for an unknown tag
WorldView.isBlockIn(pos, tag)Whether the block at pos is in a block tag
ItemStackRef.isIn(tag)Whether the stack's item is in an item tag
EntityView.isIn(tag)Whether the entity's type is in an entity type tag
  • The server reads the tags from its data packs. The client reads the copy the server sent.
  • An unknown tag or entry is simply "not contained".
  • A tag of the wrong kind, such as an item tag for a block position, throws IllegalArgumentException.
  • Use a TagView on the thread of the world that handed it out, once a world is loaded. Results change after /reload, so do not cache them across reloads.

Adding entries from code​

mod.content().addToTag(WARDED, ResourceId.of("my_mod", "warded_block"));
mod.content().addToTag(SPARKLY, ResourceId.of("my_mod", "spark"), ResourceId.of("my_mod", "glow_block"));
mod.content().addToTag(PICKAXE_MINEABLE, ResourceId.of("my_mod", "warded_block")); // a game tag
  • Call addToTag in the common entrypoint, like other declarations. After registration closes it throws IllegalStateException (POLY-CONTENT-002). With no entries it throws IllegalArgumentException.
  • It works like a tag file with "replace": false in the mod jar. Poly Mod Loader writes the entries to its generated data pack (.poly/generated-pack). The tag can be in any namespace. Several calls and several mods add up, and tag files from the mod jar still apply.
  • Entries are written as optional entries and checked when the registries freeze. An entry that is not registered then is reported with POLY-CONTENT-007 and left out. The rest of the tag still loads.

Creative tabs​

The game's tabs​

To list an item at the end of one of the game's tabs, use creativeTab(CreativeTab.…) in its item definition. The tabs are listed in Blocks.

A mod's own tab​

ContentHandle tab = mod.content().creativeTab("showcase", CreativeTabDefinition.builder()
.icon(ResourceId.of("my_mod", "glow_block")) // without an icon: the first entry
.entries(ResourceId.of("my_mod", "glow_block"), ResourceId.of("my_mod", "spark"))
.entry(ResourceId.minecraft("amethyst_shard")) // the game's items work too
.build());
assets/my_mod/lang/en_us.json
{"itemGroup.my_mod.showcase": "My Mod"}
  • creativeTab(path, definition) declares the tab <mod id>:<path> in the common entrypoint. Its title is the translation of itemGroup.<mod id>.<path>.
  • CreativeTabDefinition.builder() takes an optional icon(item) and the entries in order (entry, entries). Entries can be mod items or the game's items. build() throws IllegalArgumentException if no entry was added.
  • An invalid or already used path throws IllegalArgumentException (POLY-CONTENT-001). After registration closes, IllegalStateException (POLY-CONTENT-002).
  • Entries and the icon are checked when the registries freeze. One that is not a registered item then is reported with POLY-CONTENT-008 and left out. A missing icon falls back to the first valid entry. A tab left with no entries is not registered.
  • The tab's items also appear in the creative search tab.

Pages​

The game's creative screen has room for 14 tabs, and the game uses all of them. So Poly Mod Loader puts mod tabs on extra pages:

  • Mod tabs go on pages 1, 2, … in declaration order, ten per page (the left five slots of the top and bottom rows).
  • The game's right-hand tabs (saved hotbars, search, operator items, inventory) are shown on every page.
  • When mod tabs exist, < and > buttons appear above the tab row. Turning the page selects the first tab of that page.
What is verified

Registration and the per-page position check run on the game test server. The client-side transform rules and hooks are checked by unit tests against the real 26.2 classes. How the paged screen looks (button placement, tab drawing) has not been checked by a person yet, because no window-opening test was run.

Buy me a coffee