193 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			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.ClipContext;
 | |
| import net.minecraft.world.level.Level;
 | |
| import net.minecraft.world.level.Spawner;
 | |
| 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.HitResult;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| 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, ClipContext.Fluid.SOURCE_ONLY);
 | |
| 		if (blockHitResult.getType() != HitResult.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;
 | |
| 	}
 | |
| }
 |