181 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
	
		
			5.8 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.entity;
 | |
| 
 | |
| import net.minecraft.core.Direction;
 | |
| import net.minecraft.core.particles.ParticleTypes;
 | |
| import net.minecraft.network.syncher.EntityDataAccessor;
 | |
| import net.minecraft.network.syncher.EntityDataSerializers;
 | |
| import net.minecraft.network.syncher.SynchedEntityData;
 | |
| import net.minecraft.server.level.ServerLevel;
 | |
| import net.minecraft.sounds.SoundEvents;
 | |
| import net.minecraft.sounds.SoundSource;
 | |
| import net.minecraft.world.damagesource.DamageSource;
 | |
| import net.minecraft.world.entity.item.ItemEntity;
 | |
| import net.minecraft.world.entity.projectile.Projectile;
 | |
| import net.minecraft.world.item.ItemStack;
 | |
| import net.minecraft.world.item.ProjectileItem;
 | |
| import net.minecraft.world.level.Level;
 | |
| import net.minecraft.world.level.gameevent.GameEvent;
 | |
| import net.minecraft.world.level.material.PushReaction;
 | |
| import net.minecraft.world.level.storage.ValueInput;
 | |
| import net.minecraft.world.level.storage.ValueOutput;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| 
 | |
| public class OminousItemSpawner extends Entity {
 | |
| 	private static final int SPAWN_ITEM_DELAY_MIN = 60;
 | |
| 	private static final int SPAWN_ITEM_DELAY_MAX = 120;
 | |
| 	private static final String TAG_SPAWN_ITEM_AFTER_TICKS = "spawn_item_after_ticks";
 | |
| 	private static final String TAG_ITEM = "item";
 | |
| 	private static final EntityDataAccessor<ItemStack> DATA_ITEM = SynchedEntityData.defineId(OminousItemSpawner.class, EntityDataSerializers.ITEM_STACK);
 | |
| 	public static final int TICKS_BEFORE_ABOUT_TO_SPAWN_SOUND = 36;
 | |
| 	private long spawnItemAfterTicks;
 | |
| 
 | |
| 	public OminousItemSpawner(EntityType<? extends OminousItemSpawner> entityType, Level level) {
 | |
| 		super(entityType, level);
 | |
| 		this.noPhysics = true;
 | |
| 	}
 | |
| 
 | |
| 	public static OminousItemSpawner create(Level level, ItemStack item) {
 | |
| 		OminousItemSpawner ominousItemSpawner = new OminousItemSpawner(EntityType.OMINOUS_ITEM_SPAWNER, level);
 | |
| 		ominousItemSpawner.spawnItemAfterTicks = level.random.nextIntBetweenInclusive(60, 120);
 | |
| 		ominousItemSpawner.setItem(item);
 | |
| 		return ominousItemSpawner;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void tick() {
 | |
| 		super.tick();
 | |
| 		if (this.level() instanceof ServerLevel serverLevel) {
 | |
| 			this.tickServer(serverLevel);
 | |
| 		} else {
 | |
| 			this.tickClient();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void tickServer(ServerLevel level) {
 | |
| 		if (this.tickCount == this.spawnItemAfterTicks - 36L) {
 | |
| 			level.playSound(null, this.blockPosition(), SoundEvents.TRIAL_SPAWNER_ABOUT_TO_SPAWN_ITEM, SoundSource.NEUTRAL);
 | |
| 		}
 | |
| 
 | |
| 		if (this.tickCount >= this.spawnItemAfterTicks) {
 | |
| 			this.spawnItem();
 | |
| 			this.kill(level);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void tickClient() {
 | |
| 		if (this.level().getGameTime() % 5L == 0L) {
 | |
| 			this.addParticles();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void spawnItem() {
 | |
| 		if (this.level() instanceof ServerLevel serverLevel) {
 | |
| 			ItemStack itemStack = this.getItem();
 | |
| 			if (!itemStack.isEmpty()) {
 | |
| 				Entity entity;
 | |
| 				if (itemStack.getItem() instanceof ProjectileItem projectileItem) {
 | |
| 					entity = this.spawnProjectile(serverLevel, projectileItem, itemStack);
 | |
| 				} else {
 | |
| 					entity = new ItemEntity(serverLevel, this.getX(), this.getY(), this.getZ(), itemStack);
 | |
| 					serverLevel.addFreshEntity(entity);
 | |
| 				}
 | |
| 
 | |
| 				serverLevel.levelEvent(3021, this.blockPosition(), 1);
 | |
| 				serverLevel.gameEvent(entity, GameEvent.ENTITY_PLACE, this.position());
 | |
| 				this.setItem(ItemStack.EMPTY);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Entity spawnProjectile(ServerLevel level, ProjectileItem projectileItem, ItemStack stack) {
 | |
| 		ProjectileItem.DispenseConfig dispenseConfig = projectileItem.createDispenseConfig();
 | |
| 		dispenseConfig.overrideDispenseEvent().ifPresent(i -> level.levelEvent(i, this.blockPosition(), 0));
 | |
| 		Direction direction = Direction.DOWN;
 | |
| 		Projectile projectile = Projectile.spawnProjectileUsingShoot(
 | |
| 			projectileItem.asProjectile(level, this.position(), stack, direction),
 | |
| 			level,
 | |
| 			stack,
 | |
| 			direction.getStepX(),
 | |
| 			direction.getStepY(),
 | |
| 			direction.getStepZ(),
 | |
| 			dispenseConfig.power(),
 | |
| 			dispenseConfig.uncertainty()
 | |
| 		);
 | |
| 		projectile.setOwner(this);
 | |
| 		return projectile;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void defineSynchedData(SynchedEntityData.Builder builder) {
 | |
| 		builder.define(DATA_ITEM, ItemStack.EMPTY);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void readAdditionalSaveData(ValueInput input) {
 | |
| 		this.setItem((ItemStack)input.read("item", ItemStack.CODEC).orElse(ItemStack.EMPTY));
 | |
| 		this.spawnItemAfterTicks = input.getLongOr("spawn_item_after_ticks", 0L);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void addAdditionalSaveData(ValueOutput output) {
 | |
| 		if (!this.getItem().isEmpty()) {
 | |
| 			output.store("item", ItemStack.CODEC, this.getItem());
 | |
| 		}
 | |
| 
 | |
| 		output.putLong("spawn_item_after_ticks", this.spawnItemAfterTicks);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected boolean canAddPassenger(Entity passenger) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected boolean couldAcceptPassenger() {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void addPassenger(Entity passenger) {
 | |
| 		throw new IllegalStateException("Should never addPassenger without checking couldAcceptPassenger()");
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public PushReaction getPistonPushReaction() {
 | |
| 		return PushReaction.IGNORE;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean isIgnoringBlockTriggers() {
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	public void addParticles() {
 | |
| 		Vec3 vec3 = this.position();
 | |
| 		int i = this.random.nextIntBetweenInclusive(1, 3);
 | |
| 
 | |
| 		for (int j = 0; j < i; j++) {
 | |
| 			double d = 0.4;
 | |
| 			Vec3 vec32 = new Vec3(
 | |
| 				this.getX() + 0.4 * (this.random.nextGaussian() - this.random.nextGaussian()),
 | |
| 				this.getY() + 0.4 * (this.random.nextGaussian() - this.random.nextGaussian()),
 | |
| 				this.getZ() + 0.4 * (this.random.nextGaussian() - this.random.nextGaussian())
 | |
| 			);
 | |
| 			Vec3 vec33 = vec3.vectorTo(vec32);
 | |
| 			this.level().addParticle(ParticleTypes.OMINOUS_SPAWNING, vec3.x(), vec3.y(), vec3.z(), vec33.x(), vec33.y(), vec33.z());
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public ItemStack getItem() {
 | |
| 		return this.getEntityData().get(DATA_ITEM);
 | |
| 	}
 | |
| 
 | |
| 	private void setItem(ItemStack item) {
 | |
| 		this.getEntityData().set(DATA_ITEM, item);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
 | |
| 		return false;
 | |
| 	}
 | |
| }
 |