mojira.dev
MC-313001

Sulfur cubes holding TNT can be fused after being sheared, causing permanent fused state

By shearing a sulfur cube holding a TNT block and then igniting it with a flint and steel or firecharge in quick succession, it is possible to put the sulfur cube into a permanent fused state, also making it invulnerable in the process. This can only happen in specific cirumstances, specifically when there occurs no server tick between shearing and igniting interaction.

Reproduction:
There are two ways to reproduce this on a vanilla client.

  1. Hold a flint and steel in your main hand and a shear in your offhand, then right click the sulfur cube at the same time as pressing the hotkey to swap items with your offhand.

  2. Make the server lag (e.g. by using the command /gamerule random_tick_speed 100000) and then right click the sulfur cube with the shears, followed by another rightclick with the flint and steel in quick succession.


Code analysis:
The SulfurCube Entity class contains an Optional field explosionData that is only ever set in the method SulfurCube::collectEquipmentChanges. To determine whether the sulfur cube can be primed, it checks if an explosionData value is present in the primeTime() method:

public boolean primeTime(final boolean imminent) {
    if (!this.explosionData.isEmpty()
        && this.isAlive()
        && this.level() instanceof ServerLevel serverLevel
        && serverLevel.getGameRules().get(GameRules.TNT_EXPLODES)
        && !this.isPrimed()) {
        int fuse = ((ExplosionData)this.explosionData.get()).fuse();
        int fuseTime = imminent ? PrimedTnt.getRandomShortFuse(fuse, this.getRandom()) : fuse;
        this.setPermanentlyInvulnerable(true);
        this.setFuse(fuseTime);
        this.entityData.set(MAX_FUSE, fuseTime);
        this.makeSound(SoundEvents.TNT_PRIMED);
        this.gameEvent(GameEvent.PRIME_FUSE);
        return true;
    } else {
        return false;
    }
}

However, the collectEquipmentChanges() method is only ever called when the sulfur cube entity is ticked (or when its block is swapped) and not immediately after the sulfur cube was sheared.
A potential fix would thus need to make sure that the explosionData is field is updated right after the interaction is handled (similarly to how that was done for the SulfurCube::equipItem method, which also calls collectEquipmentChanges()). So one could e.g. add a call to collectEquipmentChanges() at the end of the SulfurCube::shear method:

public void shear(final ServerLevel level, final SoundSource soundSource, final ItemStack tool) {
    Vec3 equipmentSpawnOffset = this.getAttachments().getAverage(EntityAttachment.PASSENGER);
    ItemStack itemStackToShear = this.getItemBySlot(EquipmentSlot.BODY);
    this.setItemSlot(EquipmentSlot.BODY, ItemStack.EMPTY);

    // call collectEquipmentChanges() from here or otherwise update explosionData

    if (this.spawnAtLocation(level, itemStackToShear, equipmentSpawnOffset) != null) {
        this.playSound(this.getEjectSound());
        this.pickupTimer = 100;
    }
}

Attachments

Comments 1

Thank you for helping us improve Minecraft! We saved your files:

[media][media]

Z0rty

(Unassigned)

Unconfirmed

26.4 Snapshot 6

Retrieved