Skip to content

About

Place2Die server resource pack: assets, validation, deterministic build and release

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

p2d-resourcepack

The Place2Die server resource pack: one pack, required on join, carrying the models and textures of every custom item (and, through BetterModel, every custom mob).

Targets Minecraft Java 26.2 (Paper 26.2): resource pack format 88 (min_format/max_format in pack/pack.mcmeta, the format scheme since 1.21.9).

Layout

pack/                         the pack sources, zipped as-is
  pack.mcmeta
  assets/
    p2d_survival/             one namespace per plugin = the plugin's key namespace
      items/<id>.json         item definition, read by the item_model component
      models/item/<id>.json   the model
      textures/item/<id>.png  the texture
    p2d_gathering/            items (materials, tools) and harvest node models
    p2d_building/             the tool cupboard (item and block display)
      textures/block/<id>.png node textures (cube models shown by an item display)
    p2d_loot/                 loot barrel and crate models (item displays over the containers)
    p2d_zombies/ …            (added with their first asset)
bettermodel/ or bettermodel.zip   optional, BetterModel's generated pack (see below)
tools/p2dpack/                build tooling (Python 3.13, standard library only)
tests/                        unittest suite of the tooling
scripts/placeholders.py       generates the placeholder textures
pack.py                       entry point

Commands

./pack.py validate          # check the sources
./pack.py build             # validate, merge BetterModel's pack, zip, print the SHA-1
./pack.py version           # next release tag computed from the gitmojis since the last tag
python3 -m unittest discover -s tests -t .

build writes build/p2d-resourcepack.zip and build/p2d-resourcepack.zip.sha1. The zip is deterministic (sorted entries, fixed timestamps and permissions), so the same sources always give the same SHA-1.

What validate checks

  • pack.mcmeta parses and its min_format..max_format range includes 88.
  • Every .json / .mcmeta parses, with no duplicate keys.
  • Namespaces use [a-z0-9_.-] and asset paths [a-z0-9_./-] (lowercase): Minecraft silently ignores anything else. Only pack.mcmeta, pack.png and assets/ at the root.
  • Every .png is a real PNG.
  • Every item definition (assets/<ns>/items/*.json) points to models that exist, at any depth (select cases, condition, range_dispatch, composite, special bases).
  • Every model's parent and textures exist. A texture outside item/ or block/ is a warning: it is only stitched into the atlas if the pack adds an atlas source for it.

References into the minecraft namespace (item/generated, vanilla textures) are vanilla assets, so they are trusted, not checked.

Adding an item model

Every custom item has its own model and texture (rule decided on 2026-10-15). For an item p2d_<plugin>:<id>:

  1. Texture: pack/assets/p2d_<plugin>/textures/item/<id>.png, 16x16 (or a larger power of two). Lowercase file names.
  2. Model: pack/assets/p2d_<plugin>/models/item/<id>.json
    {
      "parent": "minecraft:item/generated",
      "textures": { "layer0": "p2d_<plugin>:item/<id>" }
    }
    (minecraft:item/handheld for tools and weapons; a Blockbench export for 3D items.)
  3. Item definition: pack/assets/p2d_<plugin>/items/<id>.json
    { "model": { "type": "minecraft:model", "model": "p2d_<plugin>:item/<id>" } }
  4. ./pack.py build and python3 -m unittest discover -s tests -t . must pass.
  5. Commit with :bento: (assets, patch release) or :sparkles:, ending with the ticket id, and open a PR. Once it is merged and released, the plugin can set the model: CustomItem.Builder#model(ItemModel.model(Key.key("p2d_<plugin>", "<id>"))). Never set item_model before the released pack ships the asset: the item renders as the missing texture.

World objects shown by an item display

Core custom blocks can be rendered by an item display whose item_model is the block's key (harvest nodes do: an invisible barrier hitbox under the model; p2d-loot's barrels too, and its crates show theirs over the chest that holds the loot). They follow the same three steps; a block-shaped placeholder uses "parent": "minecraft:block/cube_all" with "textures": { "all": "p2d_<plugin>:block/<id>" } and its texture under textures/block/.

Tree nodes come in sizes (PERSO-113): tree_small, tree (medium) and tree_large, each with a _depleted model. Their placeholders are boxes of different sizes (elements with parent: minecraft:block/block) so the sizes read apart in game before the real models exist.

Each tree size also has a _falling model (PERSO-114): the part of the tree above its stump, shown by a display p2d-gathering spawns over the stump when the tree is cut, then tilts to the ground around the middle of the block's bottom face. Keep its foot at the stump's top and the trunk centred on x/z = 8, or it will not fall from the stump.

Placeholders

These textures are placeholders generated by scripts/placeholders.py, waiting for real art (PERSO-83). Replace the PNG and remove its entry from the script.

Item Texture
p2d_survival:canteen assets/p2d_survival/textures/item/canteen.png
p2d_survival:bandage assets/p2d_survival/textures/item/bandage.png
p2d_survival:medicine assets/p2d_survival/textures/item/medicine.png
p2d_gathering:wood assets/p2d_gathering/textures/item/wood.png
p2d_gathering:stone assets/p2d_gathering/textures/item/stone.png
p2d_gathering:raw_metal assets/p2d_gathering/textures/item/raw_metal.png
p2d_gathering:hatchet assets/p2d_gathering/textures/item/hatchet.png
p2d_gathering:pickaxe assets/p2d_gathering/textures/item/pickaxe.png
p2d_gathering:tree (node display) assets/p2d_gathering/textures/block/tree.png
p2d_gathering:tree_depleted (node display) assets/p2d_gathering/textures/block/tree_depleted.png
p2d_gathering:tree_small (node display) assets/p2d_gathering/textures/block/tree_small.png
p2d_gathering:tree_small_depleted (node display) assets/p2d_gathering/textures/block/tree_small_depleted.png
p2d_gathering:tree_large (node display) assets/p2d_gathering/textures/block/tree_large.png
p2d_gathering:tree_large_depleted (node display) assets/p2d_gathering/textures/block/tree_large_depleted.png
p2d_gathering:tree_falling (falling tree display) assets/p2d_gathering/textures/block/tree_falling.png
p2d_gathering:tree_small_falling (falling tree display) assets/p2d_gathering/textures/block/tree_small_falling.png
p2d_gathering:tree_large_falling (falling tree display) assets/p2d_gathering/textures/block/tree_large_falling.png
p2d_gathering:rock (node display) assets/p2d_gathering/textures/block/rock.png
p2d_gathering:rock_depleted (node display) assets/p2d_gathering/textures/block/rock_depleted.png
p2d_gathering:ore (node display) assets/p2d_gathering/textures/block/ore.png
p2d_gathering:ore_depleted (node display) assets/p2d_gathering/textures/block/ore_depleted.png
p2d_loot:barrel (loot barrel display) assets/p2d_loot/textures/block/barrel.png
p2d_loot:crate (loot crate display) assets/p2d_loot/textures/block/crate.png
p2d_building:tool_cupboard (item and block display) assets/p2d_building/textures/block/tool_cupboard.png

BetterModel (3D mobs)

BetterModel (PERSO-84) renders the Blockbench mob models and generates its own pack. Players must get one pack, so build merges it into ours:

  • Input: ./bettermodel/ (BetterModel's pack-type: folder output) or ./bettermodel.zip (pack-type: zip), or any path with ./pack.py build --bettermodel <path>. Absent = nothing merged.
  • Only its assets/ are merged. Its pack.mcmeta and pack.png are replaced by ours.
  • A file both packs ship with different content is a conflict and fails the build; a byte-identical file is kept once.
  • Anything else at its root (overlay folders) fails the build: set BetterModel's pack.generate-legacy-model: false, we only target 26.2.
  • The merged pack is validated again before zipping.

Releases

CI (.github/workflows/build.yml) runs the tests and the build on every PR and push, checks the zip is reproducible, and uploads it as an artifact. On main, the version is computed from the gitmojis since the last vX.Y.Z tag (:boom: major, :sparkles: minor, patch gitmojis such as :bento: and :bug: patch, others no release) and a GitHub release vX.Y.Z is published with the zip and its SHA-1. Nobody tags by hand.

The repository is private, so release assets are not downloadable by Minecraft clients: the pack must be served from a public URL (see the open question in PERSO-81).

About

Place2Die server resource pack: assets, validation, deterministic build and release

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages