mojira.dev
MC-247643

Spawn Eggs create ENTITY_PLACE game event at wrong position

The bug

Spawn eggs, when used against a block, use the position of the block as the game event’s starting location instead of using the entity’s $$3.

This means you can use a spawn egg on the side of a wool block and it will be occluded.

Code analysis

As you can see, $$10.spawn() uses $$8 as the entity’s spawning position, although for the game event it uses $$3.

Minecraft 1.21.5, official mappings

net/minecraft/world/item/SpawnEggItem.java

public class SpawnEggItem extends Item {
   // ...
   public InteractionResult useOn(UseOnContext $$0) {
      Level $$1 = $$0.getLevel();
      if ($$1.isClientSide) {
         // ...
      } else {
         ItemStack $$2 = $$0.getItemInHand();
         BlockPos $$3 = $$0.getClickedPos();
         Direction $$4 = $$0.getClickedFace();
         BlockState $$5 = $$1.getBlockState($$3);
         if ($$1.getBlockEntity($$3) instanceof Spawner $$6) {
            // ...
         } else {
            BlockPos $$8;
            if ($$5.getCollisionShape($$1, $$3).isEmpty()) {
               $$8 = $$3;
            } else {
               $$8 = $$3.relative($$4);
            }
            EntityType<?> $$10 = this.getType($$1.registryAccess(), $$2);
            if ($$10.spawn((ServerLevel)$$1, $$2, $$0.getPlayer(), $$8, EntitySpawnReason.SPAWN_ITEM_USE, true, ...) {
               $$2.shrink(1);
               $$1.gameEvent($$0.getPlayer(), GameEvent.ENTITY_PLACE, $$3);
            }
            // ...
         }
      }
   }
   // ...
}

Attachments

Comments 2

Code Analysis (Yarn Mappings 1.18.1)

SpawnEggItem.java

public ActionResult useOnBlock(ItemUsageContext context) {
    World world = context.getWorld();
    ...
    ItemStack stack = context.getStack();
    BlockPos blockPos = context.getBlockPos();
    Direction direction = context.getSide();
    BlockState blockState = world.getBlockState(blockPos);
    ...
    BlockPos spawnPos;
    if (blockState.getCollisionShape(world, blockPos).isEmpty()) {
        spawnPos = blockPos;
    } else {
        spawnPos = blockPos.offset(direction);
    }
    EntityType<?> type = this.getEntityType(stack.getNbt());
    if (type.spawnFromItemStack(world, stack, context.getPlayer(), spawnPos, SPAWN_EGG, true, ...) {
        stack.decrement(1);
        world.emitGameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, blockPos);
    }
    ...
}

As you can see type.spawnFromItemStack() uses spawnPos as the entities spawning position, although for the game event it uses blockPos

Thank god I wrote a comment with the code analysis… Oh great, its gone now

PR0CESS

(Unassigned)

Plausible

Platform

Low

Game Events

1.18.1, 22w03a

Retrieved