Skip to content

PokeLink (plugin)

Lets a player show off a Pokemon from their party in chat by typing [p1] to [p6]. The token turns into the Pokemon's name, colored by its type, with a hover card that shows its stats.

What it does

  • A player types [p1] through [p6] in chat. Each token is one party slot.
  • The token becomes a link like [Bulbasaur]. The name is colored by the Pokemon's main type. Shiny Pokemon get a gold star after the name. Eggs show as Egg.
  • Hovering the link shows a card with level, types, gender, nature, ability, held item, IVs, EVs, moves and original trainer.
  • The card is drawn by battlecore's shared Pokemon display, so it looks the same as the GTS listing and the Battle Tower team screen. If battlecore is missing, the plugin uses its own card from config.yml instead.
  • An empty slot cancels the message and tells the sender the slot is empty, so [p6] is never sent as plain text.

PokeLink does not touch chat itself. ChatControl owns chat. PokeLink ships six ChatControl "variable" files (p1.yml to p6.yml), the same kind as the stock [item] token, and fills them through PlaceholderAPI.

How players use it

  1. Put the Pokemon you want to show in your party.
  2. Type a message with the slot token, for example: look at my [p1].
  3. Others see look at my [Charizard]. They hover it to see the card.

Things players may notice:

  • The same token only works once per message. [p1] vs [p1] expands only the first one. Different tokens are fine: [p1] vs [p2] expands both. This is how ChatControl works and cannot be changed.
  • If a slot is empty, the message is not sent and you see "You have nothing in party slot N."
  • If you see "Pokemon links are not available right now.", the plugin is not loaded yet (see Troubleshooting).

Staff guide

Task Command Who
Re-read config.yml /pokelink reload pokelink.admin (op by default), or console

/pokelink reload replies with PokeLink config reloaded (8 hover line(s)).

There is nothing to whitelist. [p1] is a chat token, not a command, so CommandWhitelist is not involved.

To limit links to some players, add Sender_Permission: "pokelink.use" to each variable file and grant that node. It is not set today, so everyone can link.

Configuration

Three parts, three ways to go live:

File Where on the server How it goes live
The plugin jar plugins/ Restart
config.yml plugins/PokeLink/config.yml /pokelink reload
p1.yml to p6.yml (in src/main/resources/chatcontrol-variables/) plugins/ChatControl/variables/ /chc reload

Keys people change in config.yml:

Key What it does
slots How many party slots have a token (1 to 6). The variable files must match.
link.format The inline link, in MiniMessage. Tokens use braces, like {name}, {type_color}, {shiny}.
link.shiny-marker, link.egg-name, link.fallback-color Shiny star, egg label, and the color used when the type is unknown.
hover.use-shared-lore true uses battlecore's card. false uses hover.lines.
hover.shared-lore-layout Which battlecore layout to draw. Keep chat_hover (the compact card). standard is the tall GUI card and covers the chat.
hover.lines The fallback card, one row per line. Used on the Paper hub and when battlecore is missing. Keep it filled in even though use-shared-lore is on.
type-colors Override the color for a type. Leave out a type to keep the default.
sprite.* Sprites in chat. Leave enabled: false (see below).

Tokens available in link.format and hover.lines: {name} {species} {nickname} {dex} {level} {types} {gender} {nature} {ability} {held} {ivs} {iv_percent} {evs} {moves} {ot} {friendship} {type_color} {shiny} {sprite} {slot}.

If a token cannot be read, the whole row is dropped. An egg or a missing field makes the card shorter instead of showing "Ability: " with nothing after it. Put optional info on its own hover row, not in link.format, or the whole link disappears.

Which rows the shared card shows is set on the server in config/battlecore/lore/chat_hover.json. Each row there has its own enabled flag. After changing it, run /pokelink reload. A new field added to battlecore shows up here with no PokeLink rebuild.

If you write your own hover.lines, your list replaces the built-in one fully. If you delete the whole hover section, the plugin falls back to its built-in rows.

Sprites cannot be turned on from the server alone. Chat can only draw a picture if the player's client has a resource pack with a font for it. Pixelmon has no such font. With no pack, every player sees a missing-glyph box. A pack would be cheap (pure JSON that points at Pixelmon's own textures) and could ship through resource-pack= in server.properties or the modpack overrides. Glyph = codepoint-base + national dex number, plus shiny-offset for shinies.

Data and storage

None. PokeLink saves nothing. It reads the party Pixelmon already has loaded for the sender.

Troubleshooting

Symptom Cause Fix
"Pokemon links are not available right now." The variable files are live but the jar is not loaded yet, or PlaceholderAPI is down Restart the server so the jar loads. Check the boot log for the ready line
Literal [p1] stays in chat The variable files are missing, or a variable's script broke Check plugins/ChatControl/variables/p1.yml exists, then /chc reload
Second [p1] in a message is plain text ChatControl only expands each token once per message Expected. Use different slots
Card is plain gray, not the colored shared card battlecore is missing or too old, or use-shared-lore is false Check battlecore is installed and has PokemonLoreService
No EVs row on the fallback card Pixelmon has no EVStore.getShorthand Expected. The shared battlecore card shows EVs
Every slot says empty on the Paper hub The hub has no Pixelmon Expected. Do not install the variable files on the Paper hub

Boot log lines that mean it loaded:

[PokeLink] PokeLink ready: 6 slot(s), Pixelmon bound, sprites off.

On the Paper hub it says Pixelmon unavailable instead. That is normal. A boot warning Pixelmon method EVStore.getShorthand is missing; that hover row will be omitted is also normal.

If you see PlaceholderAPI is not installed - party links will not render., install PlaceholderAPI and restart.

Test as a non-op. With a Pokemon in slot 1, type hey look at [p1]. Check the link is colored, the hover has no blank rows, and [p6] with an empty slot 6 cancels the message. Send from a second backend too: the card is built on the sender's backend, so every backend needs both the jar and the variable files.

To remove the feature: delete the six variable files and run /chc reload. Chat goes back to normal right away. The jar can stay; it does nothing without the variables.

Maintainer notes

  • How it talks to ChatControl. ChatControl Type: MESSAGE variables call PlaceholderAPI. The placeholders are %pokelink_name_N% (the link), %pokelink_hover_N% (the card, one string with newlines) and %pokelink_present_N% (true/false). PlaceholderAPI is used instead of Java.type in the variable's JavaScript because ChatControl's script engine classloader may not see other plugins' classes.
  • Value is JavaScript, Hover is not. ChatControl pastes the placeholder into the JavaScript source before running it. Names like Farfetch'd have an apostrophe, so the name placeholder is JS-escaped and must stay inside single quotes. The hover placeholder is not escaped.
  • Deploy-order guard. The first check in each variable file catches the case where ChatControl has the variable but PlaceholderAPI has no pokelink expansion yet (variables go live on /chc reload, the jar only on restart). Without it, the literal %pokelink_name_1% would be posted. It is not dead code.
  • Nicknames are an injection risk. ChatControl strips <click> and <hover> from Value but not from Hover. Sanitizer removes <, > and & from every row. It keeps § color codes on battlecore rows so the shared card stays colored. Custom names keep their colors in the card (battlecore's nickname_formatted), but click and hover events on a name are never read. Hex colors use Spigot's §x§R§R§G§G§B§B form. Row length is capped by visible characters, and a color code cut in half is dropped.
  • One hover placeholder, not eight list entries. One string with newlines lets a dropped row shorten the card. Separate list entries would leave blank rows.
  • The party read never blocks. StorageProxy.getParty can start a disk load, and chat runs on an async thread. The plugin checks isDone() and gives up otherwise. This is safe because ChatControl renders on the sender's backend, where the party is already loaded.
  • All Pixelmon and battlecore access is by reflection. A mod type in a class signature fails while the plugin class loads, before onEnable, so no try/catch can save it. That is how VaultTickets 1.0.0 died. Each Pixelmon getter is bound on its own, so a rename costs one row, not the feature. Keep it that way. battlecore is bound through PokemonLoreService.render(Pokemon, String).
  • IVStore.getPercentage already returns 0 to 100. Do not multiply it again.
  • Defaults live in PokeLinkConfig as well as config.yml, because Bukkit does not fall back to the jar for a missing section. A test pins the two together.
  • The token syntax [key] is fixed by ChatControl's pattern. The Key: in a variable file cannot change the brackets.

Building

./gradlew build

Java 21. Output: build/libs/PokeLink-<version>.jar. Paper API and PlaceholderAPI are compile-only. Unit tests run with the build.

Full command, permission and config tables: Reference.