When an explosion destroys (at least one of) the end crystals used to resummon the dragon, an incomplete exit portal is generated.
How to reproduce
Create a new world, go to the end dimension, and kill the ender dragon
Place four end crystals on the edges of the exit portal to resummon the ender dragon
Cancel the respawn sequence by running the following:
/summon minecraft:tnt 2 63 2
Notice that only one end portal block has appeared, in the corner opposite where you summoned the TNT
Source code analysis
The following code was being deobfuscated and decompiled using the official obfuscation map, but still did not accomplish a good result in terms of restoring the local variable table. Apologies for the inconvenience
Huge thanks to Nickid and his video
As shown in the following code as in the behavior definition java file of the end crystals, after activating the end crystal using the piston, the explosion range would be calculated first, marking some blocks in the exit portal as candidates for being exploded
However, the two positions with the end portal shown in the screenshot can never be marked, since they are being blocked by the bedrock pillar at the middle of the portal (in fact, any block with a very high blast resistance can also lead to the same result, such as obsidians as being featured in the video above)
public boolean hurt(DamageSource var0, float var1) {
if (this.isInvulnerableTo(var0)) {
return false;
}
if (var0.getEntity() instanceof EnderDragon) {
return false;
}
if (!this.isRemoved() && !this.level.isClientSide) {
this.remove(Entity.RemovalReason.KILLED);
if (!var0.isExplosion()) {
DamageSource var2 = var0.getEntity() != null ? DamageSource.explosion(this, var0.getEntity()) : null;
this.level.explode(this, var2, null, this.getX(), this.getY(), this.getZ(), 6.0f, false, Level.ExplosionInteraction.BLOCK);
}
this.onDestroyedBy(var0);
}
return true;
}
Then the explosion would also kill other end crystals, making the following tryRespawn() return, which prevents the dragon to respawn. Since the ender dragon match was not triggered, the portal blocks would also be placed by this function
public void tryRespawn() {
if (this.dragonKilled && this.respawnStage == null) {
BlockPos var0 = this.portalLocation;
if (var0 == null) {
LOGGER.debug("Tried to respawn, but need to find the portal first.");
BlockPattern.BlockPatternMatch var1 = this.findExitPortal();
if (var1 == null) {
LOGGER.debug("Couldn't find a portal, so we made one.");
this.spawnExitPortal(true);
} else {
LOGGER.debug("Found the exit portal & saved its location for next time.");
}
var0 = this.portalLocation;
}
ArrayList var2 = Lists.newArrayList();
BlockPos var3 = var0.above(1);
for (Direction var4 : Direction.Plane.HORIZONTAL) {
List<EndCrystal> var5 = this.level.getEntitiesOfClass(EndCrystal.class, new AABB(var3.relative(var4, 2)));
if (var5.isEmpty()) {
return;
}
var2.addAll(var5);
}
LOGGER.debug("Found all crystals, respawning dragon.");
this.respawnDragon(var2);
}
}
Finally, the explosion of the activated end crystal occurs, destroying some of the end portal blocks that have been placed and marked earlier as to be exploded, but those who did not receive the explosion mark remain
Linked issues
is duplicated by 9
relates to 2
Attachments
Comments 6
I didn't have a code analysis, but I think the positions of the portal blocks have to be hardcoded instead of relating to crystals.
I can't reproduce this with pistons in 1.21-pre2, since they seem to consistently push the crystals rather than destroying them, but I do get a partial portal when the sequence is cancelled because an external explosion destroys one or more of the crystals,
Relates to MC-252472.