pta-1.21.1-2.4.0.jar
Curse Maven Snippet
What's new
[1.21.1-2.4.0] — NeoForge
The six things a pack maker runs into within an hour of the 2.3.0 offsets: patterns needing nine entries, a set that only half-happens, no way to gate on the surroundings, and no way to move a block rather than replace it.
Added
Tooltips you can actually read, in two lengths. An interaction can carry a dozen facts, and the viewer used to end with +1 more transformation(s) — telling the player something was hidden and then hiding it. The summary now names the block each transformation writes (Places Torch, not Places a block); holding a key expands it into every transformation, numbered and in order, each with its destination, its condition and what it drops. A region says how many blocks it covers, and a set-level chance is stated before the entries it gates.
pta-client.toml, a client-side config file.detail_keypicks which key expands a tooltip andmax_drop_rowshow tall a recipe box gets before its drops scroll. A separate file because a server has no business deciding which key a player holds to read a tooltip.A troubleshooting guide, troubleshooting.md: why a file did not load, why a click did nothing, why the drops or the block are not what you wrote, and a table of every message the mod logs with what it means.
The wiki is generated from the documentation, by
tools/sync-wiki.sh. It had drifted to 2.0.0 while the mod shipped 2.4.0, and nothing could notice;--checknow exits non-zero when it falls behind.LICENSE-ASSETS, covering the logo and the JEI artwork, and both licence files now travel inside the jar. A jar found in a modpack could not say what you were allowed to do with it.A permissions section in the README and on the store page: modpacks yes, servers yes, forks yes, reuploading as your own mod please no. Credit appreciated, never required.
Four in-world tests for the protection guard. A listener that cancels the vanilla break and place events is, from this mod side, exactly what a claim mod is — so the veto is now tested rather than asserted, including that it stops only the blocks it protects.
Two new documents, and thirteen worked examples. capabilities.md says what the mod can and cannot do, the things that look possible and are not, and every hard limit — so an impossible idea is cheap to rule out rather than expensive to discover. cookbook.md is whole interactions organised by what you are building, each combining several fields; every one of them ships as a runnable
combo_*.json.conditions.neighbours— gate an interaction on the blocks around it.requireasks about a block a transformation is going to change; this asks whether the recipe applies at all, which is what multi-block setups are made of:"conditions": { "neighbours": [ { "at": { "y": -1 }, "block": { "match": "minecraft:obsidian" } }, { "at": { "y": 1 }, "block": { "match": "#minecraft:logs" }, "invert": true } ] }The
blockhalf is atarget, so states and tags work exactly as they do there. All of them must hold;invertflips one. A neighbour in an unloaded chunk or outside the world counts as not matching, so a recipe never fires on evidence nobody could see.Regions. An offset can name a second corner with
to, and then covers the box between the two, corners included — a 3x3 is one entry rather than nine. Both corners read in the same frame, so a box in a rotating frame turns as a whole and a shape drawn one way lands that way. Every block counts againstmax_transformations_per_interaction, and each is checked on its own: aplaceover a region fills the gaps and leaves the rest alone rather than failing outright.A chance for a whole set.
transformationaccepts{ "chance": 0.7, "all": [ ... ] }. Each entry still rolls its own chance; this one decides whether the set is attempted. Without it, "a seven-in-ten chance the pattern appears" was only expressible as "each block of it, independently", which for a pattern means a different half-built shape every time.into: { "kind": "copy" }— write the block that is already somewhere rather than naming one. Paired with a break of its own source, that moves a block:"transformation": [ { "chance": 1.0, "at": { "y": 1 }, "into": { "kind": "copy" } }, { "chance": 1.0, "op": "break", "drops": false } ]The copy is read while planning, before anything is written, so the break cannot empty the source first.
fromreads somewhere other than the interacted block.rewards.at— where the drops land. They appeared at the interacted block and nowhere else, which reads oddly once the interaction is really acting three blocks away.drops: "tool"onop: break— the block's loot as broken by the held item, Fortune and Silk Touch included.true/falsestill mean what they meant ("vanilla"/"none") and still round-trip as booleans. Off by default on purpose: mining at a distance with an enchanted tool is a fine thing for a pack to choose and a poor one to inherit by accident.Four examples sized to the drop grid (9, 12, 18 and 27 drops), so the layout above is something you can look at rather than reason about.
A test that every feature of the format has a runnable example. Fifty-seven of them, matched against the example pack as text — a field documented but never demonstrated is invisible by inspection once there are sixty files, and the gap opens every time a feature is added.
Eight more in-world tests, covering regions, copying, tool drops and neighbour conditions. Twenty-four in all, still about two seconds.
Changed
A recipe no longer inherits the height of the widest one in the category. JEI sizes a category rather than a recipe, so a single interaction with thirty drops made every other one three rows tall and the list became a column of mostly empty boxes. The box is now capped by
max_drop_rows(three by default), and the drops past the cap share a slot: JEI cycles the stacks in a slot on its own, which is how a tag ingredient is drawn, so an overflowing recipe animates through its drops with nothing to find and nothing to click. Guaranteed and weighted drops are laid out separately, guaranteed first, so a square never alternates between you always get this and one time in four, and what a player can count on is not read after a column of maybes. The tooltip follows whichever drop is on screen, and when the item is ambiguous — the same id listed twice — it describes every entry that could have produced it rather than guessing at the odds. A pack whose interactions all fit in fewer rows is untouched: the cap is a maximum, not a constant.Upgrading: config files keep the values already written in them. An existing
pta-common.tomlstill says8, and regions will quietly stop at the eighth block — with a line in the log underDebug.log_skipped_interactions. Raise it by hand, or delete the file and let it regenerate.
Fixed
- Regions never worked.
at.toparsed, the box maths was right, and the resolver between them never read the second corner — so every region shipped as a single block.combo_excavator_3x3advertised nine and broke one. Every layer was individually correct and all three test suites were green, because none of them crossed that seam: the codec test stopped at the spec, the offset test built a box by hand, and the game tests did too. There is now a test that resolves each shipped example and fails if atocorner does not survive. - JEI and EMI crashed on a
copytransformation. A copy is neither air nor a named block, so both viewers fell through to the fluid branch and dereferenced a null — JEI showed This recipe crashed in place of the recipe. It now reads The block that was there, which is what a copy writes. - The sneak requirement was shown in two places that could disagree. The icon came from the
click type, a tooltip line came from
conditions.requires_sneaking, and nothing tied them together: an interaction using the type showed the sneaking figure and no tooltip, while one using the condition showed the standing figure and a tooltip saying sneaking was required. Sneaking is now folded into the type at load, so there is one source of truth, the icon is always right, and the duplicate tooltip line is gone. - An interaction whose
requires_sneakingdisagreed with its type could never fire, and was listed in the viewers as a working recipe anyway. The condition is now taken as the intent and the type adjusted to match, with a warning naming the type to write instead. - Removed a Minecraft texture that had been sitting in the mod resources. A copy of the vanilla grass side was shipping in every jar, referenced by nothing. Mojang assets are not redistributable, so this was a licensing problem rather than dead weight — though it was also dead weight.
- Removed
CREDITS.txt. It was the Minecraft Forge 1.12 credits file, inherited from the old MDK: it thanked the Forge authors, described MCP redistribution terms, and had nothing to do with this mod. Attribution that names the wrong project is worse than none. - A neighbour or copy source that cannot be read — unloaded, out of the world — is treated as absent rather than as air, so nothing fires or writes on the strength of a chunk that was not there.
[1.21.1-2.3.0] — NeoForge
Added
Transformations can act on a block other than the one you clicked, and can break or place rather than only overwrite.
transformationgains four fields:"transformation": { "chance": 1.0, "op": "place", "at": { "y": 1 }, "require": { "match": "minecraft:air" }, "into": { "id": "minecraft:torch" } }opisreplace(the previous and still default behaviour),break(destroys what is there, with its particles, sound and — unless"drops": false— its loot) orplace(writes only where there is room).atmoves the destination:xis right,yis up,zis forward, read in the world axes by default or against the player's facing (relative_to: "player") or the clicked face (relative_to: "face").requireis the same shape astarget, asked of the destination.transformationalso accepts a list, applied in declaration order, each entry rolling its ownchance. Every destination is resolved and checked against the world as it was when the click happened, before any of them is written, so declaration order does not change whatrequiresees.Air-target interactions can now carry transformations, as long as they are offset — their origin is the player, so "place a block above me" is expressible. A zero-offset transformation on an air target is still dropped, as it was before: there is no block there to change.
Four config keys, under
PunchThemAll.Interactions:allow_offset_transformations,max_transformation_offset(default 8),max_transformations_per_interaction(default 8) andfire_protection_events(default true).In-world automated tests.
./gradlew runGameTestServerruns the transformation pipeline against a realServerLevelon a headless server — no client, no clicking. Sixteen tests cover breaking, placing and replacing, offsets,require, the offset cap, and blocks being claimed once per click; they take about two seconds../gradlew verifyruns them after the unit suite. This is the first automated coverage of anything that needs a live world.
Changed
- Transformations post block break/place events, so claim and protection mods can veto them, and
they respect
Level.mayInteract. This matters more than it used to: an offset transformation can reach a block the player never pointed at, including across a claim boundary. Turn it off withfire_protection_eventsonly on a single-player world. - A click now transforms any one block at most once, rather than performing at most one transformation. Two interactions matching the same click still cannot both act on the same block, but they no longer block each other when they act on different ones.
- JEI and EMI say what a transformation does and where. Both drew it as one output slot next to
the target, which reads as "this becomes that" — untrue for a break, an offset, or a list. The
slot is unchanged; the tooltip now carries the operation, the offset with its frame, the
requirement and a count of any further transformations. JEI's placeholder for a transformation
that writes nothing now reads Broken for
op: "break"rather than Air, since a break leaves the block's drops behind and air does not. op: "place"refuses a destination the block cannot survive on, instead of placing it and letting the next block update pop it a tick later. A floating torch that vanishes reads as a mod bug; a skipped placement with a line in the debug log reads as a rule.
Fixed
- A transformation reaching outside the world height, or into an unloaded chunk, is skipped instead of acting. Chunks are never force-loaded from a click.
- Two entries of one transformation list that resolve to the same block no longer both apply; the second is skipped, the same way two interactions on one click already were.
- A transformation whose write is refused by the world no longer counts as having happened, so its sound does not play and the block is not marked as changed for the rest of the click.
- Every reason a transformation declines to act is reported under
Debug.log_skipped_interactions, naming the block and the reason. A transformation that quietly does nothing was previously indistinguishable from a mod bug.
All Relations
- All Relations
- Embedded Library
- Optional Dependency
- Required Dependency
- Tool
- Incompatible
- Include

