minecraft-src/net/minecraft/world/item/SpawnEggItem.java
2025-07-04 03:45:38 +03:00

193 lines
6.8 KiB
Java

package net.minecraft.world.item;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
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.HolderLookup;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.Registries;
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<EntityType<? extends Mob>, SpawnEggItem> BY_ID = Maps.<EntityType<? extends Mob>, SpawnEggItem>newIdentityHashMap();
private final EntityType<?> defaultType;
public SpawnEggItem(EntityType<? extends Mob> defaultType, Item.Properties properties) {
super(properties);
this.defaultType = defaultType;
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(level.registryAccess(), 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(level.registryAccess(), 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 hand) {
ItemStack itemStack = player.getItemInHand(hand);
BlockHitResult blockHitResult = getPlayerPOVHitResult(level, player, Fluid.SOURCE_ONLY);
if (blockHitResult.getType() != Type.BLOCK) {
return InteractionResult.PASS;
} else if (level instanceof ServerLevel serverLevel) {
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(serverLevel.registryAccess(), itemStack);
Entity entity = entityType.spawn(serverLevel, 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;
}
} else {
return InteractionResult.SUCCESS;
}
}
public boolean spawnsEntity(HolderLookup.Provider registries, ItemStack stack, EntityType<?> entityType) {
return Objects.equals(this.getType(registries, stack), entityType);
}
@Nullable
public static SpawnEggItem byId(@Nullable EntityType<?> type) {
return (SpawnEggItem)BY_ID.get(type);
}
public static Iterable<SpawnEggItem> eggs() {
return Iterables.unmodifiableIterable(BY_ID.values());
}
public EntityType<?> getType(HolderLookup.Provider registries, ItemStack provider) {
CustomData customData = provider.getOrDefault(DataComponents.ENTITY_DATA, CustomData.EMPTY);
if (!customData.isEmpty()) {
EntityType<?> entityType = customData.parseEntityType(registries, Registries.ENTITY_TYPE);
if (entityType != null) {
return entityType;
}
}
return this.defaultType;
}
@Override
public FeatureFlagSet requiredFeatures() {
return this.defaultType.requiredFeatures();
}
public Optional<Mob> spawnOffspringFromSpawnEgg(
Player player, Mob mob, EntityType<? extends Mob> entityType, ServerLevel serverLevel, Vec3 pos, ItemStack stack
) {
if (!this.spawnsEntity(serverLevel.registryAccess(), 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.snapTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F);
mob2.applyComponentsFromItemStack(stack);
serverLevel.addFreshEntityWithPassengers(mob2);
stack.consume(1, player);
return Optional.of(mob2);
}
}
}
}
@Override
public boolean shouldPrintOpWarning(ItemStack stack, @Nullable Player player) {
if (player != null && player.getPermissionLevel() >= 2) {
CustomData customData = stack.get(DataComponents.ENTITY_DATA);
if (customData != null) {
EntityType<?> entityType = customData.parseEntityType(player.level().registryAccess(), Registries.ENTITY_TYPE);
return entityType != null && entityType.onlyOpCanSetNbt();
}
}
return false;
}
}