package net.minecraft.world.item; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.mojang.serialization.MapCodec; import java.util.Map; import java.util.Objects; import java.util.Optional; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.server.level.ServerLevel; import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.player.Player; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.Spawner; import net.minecraft.world.level.ClipContext.Fluid; import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.HitResult.Type; import org.jetbrains.annotations.Nullable; public class SpawnEggItem extends Item { private static final Map, SpawnEggItem> BY_ID = Maps., SpawnEggItem>newIdentityHashMap(); private static final MapCodec> ENTITY_TYPE_FIELD_CODEC = BuiltInRegistries.ENTITY_TYPE.byNameCodec().fieldOf("id"); private final int backgroundColor; private final int highlightColor; private final EntityType defaultType; public SpawnEggItem(EntityType defaultType, int backgroundColor, int highlightColor, Item.Properties properties) { super(properties); this.defaultType = defaultType; this.backgroundColor = backgroundColor; this.highlightColor = highlightColor; BY_ID.put(defaultType, this); } @Override public InteractionResult useOn(UseOnContext context) { Level level = context.getLevel(); if (level.isClientSide) { return InteractionResult.SUCCESS; } else { ItemStack itemStack = context.getItemInHand(); BlockPos blockPos = context.getClickedPos(); Direction direction = context.getClickedFace(); BlockState blockState = level.getBlockState(blockPos); if (level.getBlockEntity(blockPos) instanceof Spawner spawner) { EntityType entityType = this.getType(itemStack); spawner.setEntityId(entityType, level.getRandom()); level.sendBlockUpdated(blockPos, blockState, blockState, 3); level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, blockPos); itemStack.shrink(1); return InteractionResult.SUCCESS; } else { BlockPos blockPos2; if (blockState.getCollisionShape(level, blockPos).isEmpty()) { blockPos2 = blockPos; } else { blockPos2 = blockPos.relative(direction); } EntityType entityType = this.getType(itemStack); if (entityType.spawn( (ServerLevel)level, itemStack, context.getPlayer(), blockPos2, EntitySpawnReason.SPAWN_ITEM_USE, true, !Objects.equals(blockPos, blockPos2) && direction == Direction.UP ) != null) { itemStack.shrink(1); level.gameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, blockPos); } return InteractionResult.SUCCESS; } } } @Override public InteractionResult use(Level level, Player player, InteractionHand interactionHand) { ItemStack itemStack = player.getItemInHand(interactionHand); BlockHitResult blockHitResult = getPlayerPOVHitResult(level, player, Fluid.SOURCE_ONLY); if (blockHitResult.getType() != Type.BLOCK) { return InteractionResult.PASS; } else if (level.isClientSide) { return InteractionResult.SUCCESS; } else { BlockPos blockPos = blockHitResult.getBlockPos(); if (!(level.getBlockState(blockPos).getBlock() instanceof LiquidBlock)) { return InteractionResult.PASS; } else if (level.mayInteract(player, blockPos) && player.mayUseItemAt(blockPos, blockHitResult.getDirection(), itemStack)) { EntityType entityType = this.getType(itemStack); Entity entity = entityType.spawn((ServerLevel)level, itemStack, player, blockPos, EntitySpawnReason.SPAWN_ITEM_USE, false, false); if (entity == null) { return InteractionResult.PASS; } else { itemStack.consume(1, player); player.awardStat(Stats.ITEM_USED.get(this)); level.gameEvent(player, GameEvent.ENTITY_PLACE, entity.position()); return InteractionResult.SUCCESS; } } else { return InteractionResult.FAIL; } } } public boolean spawnsEntity(ItemStack stack, EntityType entityType) { return Objects.equals(this.getType(stack), entityType); } public int getColor(int tintIndex) { return tintIndex == 0 ? this.backgroundColor : this.highlightColor; } @Nullable public static SpawnEggItem byId(@Nullable EntityType type) { return (SpawnEggItem)BY_ID.get(type); } public static Iterable eggs() { return Iterables.unmodifiableIterable(BY_ID.values()); } public EntityType getType(ItemStack stack) { CustomData customData = stack.getOrDefault(DataComponents.ENTITY_DATA, CustomData.EMPTY); return !customData.isEmpty() ? (EntityType)customData.read(ENTITY_TYPE_FIELD_CODEC).result().orElse(this.defaultType) : this.defaultType; } @Override public FeatureFlagSet requiredFeatures() { return this.defaultType.requiredFeatures(); } public Optional spawnOffspringFromSpawnEgg( Player player, Mob mob, EntityType entityType, ServerLevel serverLevel, Vec3 pos, ItemStack stack ) { if (!this.spawnsEntity(stack, entityType)) { return Optional.empty(); } else { Mob mob2; if (mob instanceof AgeableMob) { mob2 = ((AgeableMob)mob).getBreedOffspring(serverLevel, (AgeableMob)mob); } else { mob2 = entityType.create(serverLevel, EntitySpawnReason.SPAWN_ITEM_USE); } if (mob2 == null) { return Optional.empty(); } else { mob2.setBaby(true); if (!mob2.isBaby()) { return Optional.empty(); } else { mob2.moveTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F); serverLevel.addFreshEntityWithPassengers(mob2); mob2.setCustomName(stack.get(DataComponents.CUSTOM_NAME)); stack.consume(1, player); return Optional.of(mob2); } } } } }