mojira.dev

Rasmus Kjær Damgaard

Assigned

No issues.

Comments

Same two null-attacker paths as MC-207034 , see my comment there; the same lastHurtByPlayer fallback fixes both the Looting loss and the missing kill statistic for fall deaths.

Verified a minimal fix for this on 26.2 with a Fabric mixin. The root cause is that two paths only consult the killing blow's direct attacker, which is null when the fatal tick is the fire your own Fire Aspect lit: the ATTACKING_ENTITY loot parameter in LivingEntity.dropFromLootTable (that's the Looting loss) and the source.getEntity() read in LivingEntity.die (that's the missing per-mob kill statistic). Falling back to lastHurtByPlayer in exactly those two null cases restores Looting drops and the kill stat, while deaths with a real direct attacker are untouched. Vanilla already keeps lastHurtByPlayer with its own memory window and already uses it for advancements and the generic mob_kills counter via getKillCredit(), so those work today; only these two paths forget the player. For comparison, TNT ignited by your flame arrow does credit you, because the TNT inherits the arrow's owner as direct attacker. This does not touch MC-163573, which is the mirror case: there the direct attacker is present and the issue is the killing blow's damage type not counting as fire.

This is fixed in 26.3 Snapshot 10, alongside the MC-310693 fix. RegionFileStorage.getRegionFile now takes a create flag, every read and scan path passes false, and a region whose file does not exist is cached as absent instead of being created.

Verified with the reproduction from the description, on a fresh vanilla server with the same seed and commands on both versions (buried_treasure and pillager_outpost from spawn, mansion from x=200000): 26.2 ends with 82 empty 0-byte .mca files across the region, poi and entities folders; Snapshot 10 ends with zero. This can be resolved as Fixed for 26.3 Snapshot 10.

Re-verified on 26.3 Snapshot 10, in code and empirically: the ordering is unchanged. tryLoadFromStorage still runs before applyAdditionalChunkRestrictions on the first check of any chunk.

What the MC-310693 fix did add: repeated checks of the same chunk now skip the scan (a capped negative cache), and reads no longer create region files, absent regions are cached as a plain existence check. That fixes the empty-file side effect and makes ungenerated terrain much cheaper: same seed and commands on both versions, the outpost locate drops from 220 ms to 49 ms and the empty 0-byte files from 82 to none.

Still present: candidates in generated terrain pay the full NBT parse and datafix attempt before the frequency check, so for frequency < 1.0 sets most parses on a first pass over explored terrain are discarded right after.

Thanks for confirming. MC-176255 is the same root cause, and the plate on top slots straight into the explanation: the neighbor update order is west, east, down, up, north, south, so for a plate sitting on TNT the supporting block is "down", which primes and removes itself before north and south are ever notified, and the plate pops off just like the button does.

The button is not the important part. Any attached component that pops off when its support disappears (buttons, levers, pressure plates, torches) will cut the update sweep short the moment a TNT earlier in the order removes itself, because the popped item stops powering the rest. That is also why the first fix shape in the description covers both reports at once: defer the prime and removal to the end of the current update sweep. The sweep already has a natural completion boundary (CollectingNeighborUpdater.runUpdates unwinding), so collecting TNT primes during the sweep and running them when it completes means every neighbor is notified while the attachment still has its support, ignition stays in the same game tick, and both reproductions ignite everything for every orientation with no timing change at all. Tracking the two reports together sounds right to me.

Thank you for the review - I believe the report was read as a suggestion because of my closing note about a fix, which I should have left out. The core of the report is a defect in existing behavior:

Wall-mounted bells, when rung by redstone, swing along their FACING axis - the axis pointing into the wall. That is a direction the game itself rejects as invalid for ringing: BellBlock.isProperHit refuses it for player interaction, which is why no player action can ever make a wall bell swing that way. Redstone-triggered rings bypass that validity check (attemptToRing receives a null direction and falls back to raw FACING), so redstone animates a swing state the game otherwise defines as impossible.

Steps to reproduce:

  1. Place a bell on a wall.

  2. Ring it by hand: it swings along the wall, in either of the two valid directions.

  3. Power it with redstone: it swings into the wall axis instead - a swing no player interaction can produce.

Observed: redstone rings ignore the validity rule that player rings are checked against. This is an internal inconsistency in current behavior, not a proposed feature.

The mechanism behind this bug (and its duplicates MC-248797, MC-239836) is visible in ChunkGenerator (Mojang mappings, 26.1.2, unchanged in 26.2). Three independent causes:

  1. First hit wins inside a ring. getNearestGeneratedStructure for random-spread placements walks each Chebyshev ring of placement regions in x-then-z raster order and returns the first structure it finds. It never compares distances between members of the same ring, so the answer is the most north-west hit in the ring, not the nearest. This is the direct cause of the quadrant dependence reported in MC-248797.

  2. The radius loop stops at the first radius that finds anything. In findNearestMapStructure, a hit at radius R returns immediately. A ring at radius R spans real distances from roughly (R-1) x spacing x 16 to 1.41 x (R+1) x spacing x 16 blocks, so ring R+1 regularly contains nearer structures than the one returned from ring R.

  3. Radius is counted in each placement's own spacing. When a tag spans placements with different spacing values, "radius 3" is a different real distance for each placement, and the shared loop returns the first placement to hit. This is the tag case. The concentric-rings path (strongholds) does compare exhaustively by distance, so strongholds are not affected.

Reproduction, vanilla only, calculator only. Seed 20260821, default world gen, any version from 1.19 through 26.2 (verified on 26.1.2):

/execute positioned 8000 100 0 run locate structure minecraft:jungle_pyramid

Returns [4320, ~, -3024], reported as 4763 blocks away.

/execute positioned 12300 100 1400 run locate structure minecraft:jungle_pyramid

Returns [12336, ~, 1392], which proves that structure exists. Its distance from the first position (8000, 0) is sqrt(4336^2 + 1392^2) = 4554 blocks - 209 blocks nearer than the structure the command returned.

Second instance on the same seed: from positioned -5000 100 -5000 the command returns [-688, ~, -8928] (5833 blocks), while [-8144, ~, -144] (provable the same way from positioned -8100 100 -100) is 5785 blocks away.

Cause 1 alone has a one-line-scale fix: collect all hits in the current ring and return the minimum instead of the first. Causes 2 and 3 need the loop to continue until the next ring's minimum possible distance exceeds the best hit so far.

That fix shape is not hypothetical: I have it running as a Fabric mod that routes findNearestMapStructure through an exact-distance-order enumeration of the same placement candidates, verified with vanilla's own presence checks. At both positions above it returns the provably nearer structure while agreeing with vanilla's checks at every candidate. Source (also how these coordinates were found): https://github.com/RasmusKD/locate-more

This is still present in 26.2, and the cause is a fixed 0.2 offset.

Both particle paths sample their block through Entity.getOnPosLegacy(), which is getOnPos(0.2F): it looks 0.2 blocks below the feet. Landing particles come from doCheckFallDamage, which takes the block state at that position and hands it to checkFallDamage, where the server spawns ParticleTypes.BLOCK particles of that state. Sprint particles come from spawnSprintParticle, which uses the same call. Any block whose collision is lower than 0.2 is therefore skipped and the particles come from the block below it: bottom trapdoors are 0.1875, carpet is 0.0625, and snow layers only pass the threshold at three layers, since their collision box is one layer lower than the visual shape (SHAPES[layers - 1], so 0.25 at three layers). A clear example: landing on a lily pad shows water particles, because the sample lands in the water under the pad.

The game already has both halves of the fix. Entity.mainSupportingBlockPos tracks which block actually supports the entity, and the step sound system already solves the perception cases: Entity.getPrimaryStepSoundBlockPos checks the block above the given position against the inside_step_sound_blocks and combination_step_sound_blocks tags, which is how snow layers, carpets and lily pads get their own step sounds today. Replacing the getOnPosLegacy() call in doCheckFallDamage and spawnSprintParticle with getPrimaryStepSoundBlockPos applied to the supporting block (falling back to the legacy sample when airborne) makes the particles pick exactly the block the step sound system already picks.

Verified in game with a client mod implementing this: trapdoors, carpet, snow layers and lily pads show their own particles when landing and sprinting, and blocks without collision such as pressure plates keep their current attribution, consistent with their step sounds. Since the fix is tag driven, any future block added to the step sound tags would get correct particles automatically.

Note: I checked every other inflated layer bake in LayerDefinitions (armor sets, wither armor, cat collar). The tropical fish models are the only vanilla case where zero thickness parts are baked with an inflation, so the suggested fix cannot affect any other mob.

[media: {F034A1C4-028A-44F2-9519-9F85557CA2ED}-20260819-140325.png]
[media: Unavngivet.png]