Skip to content

Item icons from Mojang's client jar, not a CDN (#127) - #148

Merged
CaYatur merged 1 commit into
mainfrom
feat/client-jar-textures
Jul 29, 2026
Merged

Item icons from Mojang's client jar, not a CDN (#127)#148
CaYatur merged 1 commit into
mainfrom
feat/client-jar-textures

Conversation

@CaYatur

@CaYatur CaYatur commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Half of #127 — the half that was reported.

The reported symptom was not a network problem

The Players tab hot-linked assets.mcasset.cloud, asked for item/<id>.png, then block/<id>.png, and gave up. Minecraft does not name textures that way: grass_block has only _top and _side, a furnace is _front, a log's inventory face is _top. Every one of those fell through to a three-letter text chip whether or not the CDN answered.

So the candidate list is the actual fix, and it is pure and tested. The CDN removal is what the issue was opened for.

Where the pictures come from now

The client jar Mojang publishes for every version. MSMS already downloads and sha1-verifies jars from that same manifest, so this adds no new trust and no new dependency — downloads.client is the sibling of the downloads.server key versions.ts already reads.

Measured on 1.21.4, not guessed:

download 27.0 MB, sha1 verifies
kept 644 item + 1039 block textures
on disk 0.4 MB

One download per Minecraft version, shared by every server on it, behind a button rather than automatic — 27 MB is not a thing to spend on somebody's behalf. Concurrent callers share one in-flight promise rather than racing two downloads into the same directory.

Nothing here is required for the app to work: with no assets downloaded the lookup answers null and the inventory draws the chips it drew before.

What the smoke pins down

  • An id from hand-edited NBT must not become a path. ../../etc/passwd, a/b, .., a b and an 80-character id all produce no candidates at all — the only thing between a crafted inventory entry and the cache directory.
  • The extractor's filter keeps exactly two folders: an entity texture, an .mcmeta, a lang file and a nested path are all refused.
  • Version reduction: 1.21.4-pre21.21.4, 1.20.1-forge-47.2.01.20.1, nonsense → '' and no exception.
  • The lookup round trip, including the case the CDN got wrong — grass_block found via block/grass_block_side, not by exact name.

Still open on #127

Block map colours averaged from these same textures, replacing the hand-written table in regionFormat.ts. That needs a PNG decoder and touches the renderer this session spent its time stabilising, so it lands as its own PR rather than riding along with this one.

12/12 gates.

The Players tab hot-linked `assets.mcasset.cloud` for every inventory
slot. Three things wrong with that, and the reported symptom was the
third: a third party in the middle of a private server's inventory, a
grid of broken images on an air-gapped LAN, and — the one an operator
actually sees — most items rendering as a three-letter text chip.

That last one is not a network problem. The component asked for
`item/<id>.png` and then `block/<id>.png` and gave up. Minecraft does not
name textures that way: `grass_block` has only `_top` and `_side`, a
furnace is `_front`, a log's inventory face is `_top`. Every one of those
fell through to the chip whether or not the CDN answered.

So the candidate list is the fix, and it is pure and tested:
`textureCandidates` tries the item folder, then the block folder, then
the faces, plus a short alias table for the handful whose texture shares
no prefix with the id at all.

Textures now come out of the client jar Mojang publishes for every
version. MSMS already downloads and sha1-verifies jars from that same
manifest, so this adds no new trust and no new dependency — `downloads.
client` is the sibling of the `downloads.server` key `versions.ts`
already reads.

Measured on 1.21.4 rather than guessed: a 27 MB download, sha1 verified,
of which 644 item and 1039 block textures are kept — 0.4 MB on disk. One
download per Minecraft version, shared by every server on it, behind a
button rather than automatic, because 27 MB is not a thing to spend on
somebody's behalf.

Nothing here is required for the app to work. With no assets downloaded
the lookup answers null and the inventory draws the chips it drew
before.

Two things the smoke pins down. An id from hand-edited NBT must not
become a path — `../../etc/passwd`, `a/b`, `..` and friends produce no
candidates at all, which is the only thing between a crafted inventory
entry and the cache directory. And the extractor's filter keeps exactly
the two folders: an entity texture, an `.mcmeta`, a lang file and a
nested path are all refused.

This is half of #127. The other half — block map colours averaged from
the same textures instead of the hand-written table — needs a PNG decoder
and touches the renderer that took this session to stabilise, so it lands
separately.

Verified: 12/12 gates.
Copilot AI review requested due to automatic review settings July 29, 2026 14:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CaYatur
CaYatur merged commit 3c4cf31 into main Jul 29, 2026
1 check passed
@CaYatur
CaYatur deleted the feat/client-jar-textures branch July 29, 2026 14:14
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