Update to Minecraft 26.3 (14 Fabric game tests regress) - #211
Conversation
Tooling, matching CyclopsCore: - Gradle 9.7.1, needed by Fabric Loom 1.18 (which requires a Java 25 JVM for the build itself) - Fabric Loom 1.18.2, NeoForge ModDev 2.0.147 - NeoForge 26.3.0.7-beta, Forge 26.3-66.0.2, Fabric API 0.161.0+26.3, Fabric Loader 0.19.5, NeoForm 26.3-1, Forge Config API Port 26.3.0 Code: - The block type MapCodec registry and Block#codec were removed, so the codec fields and codec() overrides are dropped from the three blocks - ContextAwarePredicate is gone, so ChestFormedTrigger holds an Optional<Holder<LootItemCondition>> - BlockPos no longer has a Vec3i constructor - PoseStack#mulPose(Quaternionf) replaced by rotateDegrees - submitModel no longer takes the crumbling overlay; it goes to submitCrumblingOverlay, mirroring vanilla's ChestRenderer - FriendlyByteBuf#writeMap/readMap/limitValue are gone, so the changed slots use a ByteBufCodecs map codec. It keeps int keys rather than vanilla's shorts, since a colossal chest has far more than 32767 slots Data: - The minecraft:placed_block trigger takes a single loot condition for "location" rather than a list, and block_state_property became match_block wrapping a BlockPredicate - Missing item tags in recipe ingredients are a hard parse error now, so an empty c:ingots/silver tag is shipped for the silver recipes to be conditionally skipped as intended Known issue: 14 upgrade/downgrade game tests fail on Fabric only, with ItemUpgradeTool reporting "not enough items". NeoForge and Forge pass all 95. The same tests pass on the 26.2 baseline, so this is a genuine 26.3 regression rather than something pre-existing. cyclopscore_version and neoforge_commoncapabilities_version still point at 26.2 builds, since no 26.3 builds are published yet. Building this needs cyclopscore_version_local and commoncapabilities_version_local in secrets.properties until then. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V35MFZ7JSgoLe79J4d1uxf
Appended automatically by clientdevbridge on first use, matching the entry already present in CyclopsCore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V35MFZ7JSgoLe79J4d1uxf
CyclopsMC/CyclopsCore#243 is merged, and its master-26 run published cyclopscore 1.30.0-1159, so the placeholder version and the note about building locally are no longer needed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V35MFZ7JSgoLe79J4d1uxf
CyclopsMC/CommonCapabilities#50 is merged and its master-26 run published commoncapabilities 2.11.8-398. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V35MFZ7JSgoLe79J4d1uxf
The tests compared the result of ItemStack#useOn against the InteractionResult.SUCCESS constant by identity. In 26.3, vanilla's ItemStack#useOn no longer returns the item's result unchanged: for a Success whose wasItemInteraction is set, it returns success.heldItemTransformedTo(stack), a new Success record carrying the held stack. So the constant never matches. NeoForge and Forge patch useOn to route server-side use through CommonHooks#onPlaceItemIntoWorld, which does not apply that transformation, which is why only Fabric failed. The upgrade tool itself was correct on all three loaders: it returned SUCCESS and the chests were transformed. Only the assertion was too strict, so it now checks for an InteractionResult.Success instead. The two assertions on FAIL are left alone, since non-Success results are still passed through unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V35MFZ7JSgoLe79J4d1uxf
| this.changedSlots = changedSlots; | ||
| } | ||
|
|
||
| private static final int MAX_SLOT_COUNT = 128; |
There was a problem hiding this comment.
Why is this here? Won't this cause slot id's above 128 to not be sent anymore?
There was a problem hiding this comment.
Good question, but no: it caps the number of changed-slot entries in the map, not the slot id values. Slot ids well above 128 (and above 32767) are still sent.
The map's key codec is ByteBufCodecs.VAR_INT, so keys are full ints. maxSize is only ever used as an entry count — in ByteBufCodecs.map it is writeCount(output, map.size(), maxSize) on encode and readCount(input, maxSize) on decode. That is exactly what the override exists for, and why the line under it notes we keep int keys rather than vanilla's shorts.
It is also not new. On 26.2 this same 128 was already applied, just on the decode side only and unnamed:
IntFunction<Int2ObjectOpenHashMap<HashedStack>> intfunction = FriendlyByteBuf.limitValue(Int2ObjectOpenHashMap::new, 128);
this.changedSlots = Int2ObjectMaps.unmodifiable(input.readMap(intfunction, FriendlyByteBuf::readInt, ...));I moved it into the stream codec and gave it a name, matching how vanilla now writes the same packet. Vanilla's ServerboundContainerClickPacket on 26.3 is:
private static final int MAX_SLOT_COUNT = 128;
private static final StreamCodec<RegistryFriendlyByteBuf, Int2ObjectMap<HashedStack>> SLOTS_STREAM_CODEC = ByteBufCodecs.map(
Int2ObjectOpenHashMap::new, ByteBufCodecs.SHORT.map(Short::intValue, Integer::shortValue), HashedStack.STREAM_CODEC, 128
);So this override is the same construction with VAR_INT keys where vanilla uses SHORT — which is the whole reason the override exists.
Two honest differences worth recording, neither changing the ceiling:
- The cap now applies on encode as well as decode, because
ByteBufCodecs.mapcallswriteCountwithmaxSize. Previously an oversized map would have encoded happily and blown up on the receiving side; now it fails on the sender. Same effective limit, better failure mode. - Keys go from a fixed 4-byte
writeInttoVAR_INT. Both ends are this mod's own packet, so it stays self-consistent and is smaller on the wire for low slot ids.
If you would rather raise the entry cap above vanilla's 128 for colossal chests, that is a one-line change and I am happy to make it, but it would be a behaviour change rather than part of the port.
Generated by Claude Code
NeoForge 26.3 deprecated logoFile in favour of bannerFile and iconFile, and warns about it on every dev client launch. The logo is square, so iconFile is the fitting replacement. Only the NeoForge manifest changes: Forge 26.3 still only understands logoFile, so its mods.toml is left as is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V35MFZ7JSgoLe79J4d1uxf
Updates all three loaders to Minecraft 26.3, alongside CyclopsMC/CyclopsCore#243 and CyclopsMC/CommonCapabilities#50. All game tests pass on all three loaders (95 on NeoForge and Forge, 96 on Fabric).
Fixed: 14 upgrade/downgrade tests failed on Fabric only
Every
testcolossal*3x3upgradeand*3x3downgradetest failed on Fabric withGameTestAssertException: Interaction must succeed, while NeoForge and Forge passed.This was a bad assertion in the tests, not a defect in the mod. They compared the result of
ItemStack#useOnagainst theInteractionResult.SUCCESSconstant by identity. In 26.3, vanilla'sItemStack#useOnno longer returns the item's result unchanged: when the result is aSuccesswithwasItemInteractionset, it returnssuccess.heldItemTransformedTo(stack), a newSuccessrecord carrying the held stack. SinceSuccessis a record with a now non-nullheldItemTransformedTo, neither==norequalsmatches the constant.NeoForge and Forge patch
ItemStack#useOnto route server-side use throughCommonHooks#onPlaceItemIntoWorld, which skips that transformation, which is exactly why only Fabric failed.The assertions now check for an
InteractionResult.Successinstead. The two assertions onFAILare unchanged, since non-Successresults are still passed through untouched.An earlier revision of this description blamed
consumeItemsrejecting a valid inventory. That was wrong: instrumentingattemptTransformshowed the only test reaching that path is the wood case that is supposed to fail with 22 walls. The upgrade tool returnedSUCCESSand transformed the chests correctly on Fabric all along.Tooling
1.17-SNAPSHOT→1.18.2, NeoForge ModDev2.0.141→2.0.147.26.3.0.7-beta, Forge26.3-66.0.2, Fabric API0.161.0+26.3, Fabric Loader0.19.5, NeoForm26.3-1, Forge Config API Port26.3.0.Code
MapCodecregistry andBlock#codecwere removed, so thecodecfields andcodec()overrides are dropped from the three blocks.ContextAwarePredicateis gone, soChestFormedTriggerholds anOptional<Holder<LootItemCondition>>.BlockPosno longer has aVec3iconstructor.PoseStack#mulPose(Quaternionf)replaced byrotateDegrees.submitModelno longer takes the crumbling overlay; it goes tosubmitCrumblingOverlay, mirroring vanilla'sChestRenderer.FriendlyByteBuf#writeMap/readMap/limitValueare gone, so the changed slots go through aByteBufCodecs.mapcodec. It keeps int keys rather than vanilla's shorts, since a colossal chest has far more than 32767 slots — worth a second opinion, as it is the one place I deliberately diverged from vanilla.Data
minecraft:placed_blocktrigger takes a single loot condition for"location"rather than a list, andblock_state_propertybecamematch_blockwrapping aBlockPredicate.c:ingots/silvertag is shipped for the silver recipes to be conditionally skipped as intended.CI is blocked on CommonCapabilities 26.3
cyclopscore_versionis now1.30.0-1159, the published 26.3 build, and resolves.neoforge_commoncapabilities_versionstill points at a 26.2 build and is the only remaining unresolved dependency, so CI fails on it until CyclopsMC/CommonCapabilities#50 is merged and published. Note that the pinned value is a placeholder and will need bumping to whatever version that run produces.Locally this builds against a
publishToMavenLocalCommonCapabilities throughcommoncapabilities_version_localinsecrets.properties.Generated by Claude Code