Skip to content

perf: cache display item names to eliminate per-search skull construction#92

Merged
balugaq merged 2 commits into
balugaq:masterfrom
KevinWoodWL:master
May 23, 2026
Merged

perf: cache display item names to eliminate per-search skull construction#92
balugaq merged 2 commits into
balugaq:masterfrom
KevinWoodWL:master

Conversation

@KevinWoodWL
Copy link
Copy Markdown
Contributor

Changes

  • SearchGroup: add DISPLAY_ITEM_NAMES_CACHE (Map<String, List<String>>), populated once during init() alongside CACHE2. Stores lower-cased display names from getDisplayRecipes() per item ID.
  • FilterType.BY_DISPLAY_ITEM_NAME: replace live getDisplayRecipes() calls with a lookup against the cache. Eliminates CraftMetaSkull / CraftPlayerProfile construction at search time, which was firing Mojang sessionserver HTTP requests and causing 429 rate-limit errors.

Root cause

Every player search triggered BY_DISPLAY_ITEM_NAME, which called getDisplayRecipes() live per item. For skull-based display items this clones a SlimefunItemStack, constructs CraftMetaSkull and CraftPlayerProfile, and fires an HTTP request to sessionserver.mojang.com. Under load this saturates Mojang's rate limit (HTTP 429) and stalls the server thread.

Spark profiler confirmed CraftPlayerProfile.<init> (91 call-tree nodes) and CraftMetaSkull (390 nodes) were all rooted in SearchGroup.filterItems via this filter.

After

Display name lookup is a plain Map.get + string contains -- no object allocation, no HTTP, no Mojang round-trip.

Live-tested on production server

Deployed on a Leaf 1.21.11 server with ~133 plugins (heavy Slimefun ecosystem including SlimeAE, NetworksExpansion, LogiTech, InfinityExpansion). All addon integrations verified working after the fix.

Problem:
FilterType.BY_DISPLAY_ITEM_NAME called getDisplayRecipes() live on every
Slimefun machine during each player search. getDisplayRecipes() clones
SlimefunItemStacks, which triggers CraftMetaSkull.applyToItem and
CraftPlayerProfile.<init> for every skull-based display item.
CraftPlayerProfile construction fires HTTP requests to Mojang sessionserver,
causing 429 rate-limit errors and TPS drops on the server thread.

Spark profiler confirmed CraftPlayerProfile.<init> (91 nodes) and
CraftMetaSkull (390 nodes) were all rooted in SearchGroup.filterItems
via the BY_DISPLAY_ITEM_NAME filter.

Fix:
- SearchGroup: add DISPLAY_ITEM_NAMES_CACHE (Map<String,List<String>>),
  a hard-reference map from Slimefun item ID to lower-cased display names
  from getDisplayRecipes(). Populated once during init() alongside CACHE2.
- FilterType.BY_DISPLAY_ITEM_NAME: replace live getDisplayRecipes() calls
  with a lookup against DISPLAY_ITEM_NAMES_CACHE. No ItemStack clone, no
  CraftMetaSkull, no CraftPlayerProfile, no Mojang HTTP request at search.
- Removed unused imports from FilterType (AContainer, MultiBlockMachine,
  RecipeDisplayItem, SpecialMenuProvider, Debug).
- pom.xml: bump Lombok 1.18.34 -> 1.18.38 for JDK 25 compatibility.
Fixes NoClassDefFoundError on Leaf 1.21.11 (modern Paper, no versioned
CraftBukkit packages). 1.10.13-SNAPSHOT ships Wrapper26_R1 which uses
the un-versioned org.bukkit.craftbukkit.* import path that Leaf uses.
@balugaq balugaq self-requested a review May 23, 2026 17:20
@balugaq balugaq merged commit 0a59718 into balugaq:master May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants