/* * Decompiled with CFR 0.152. * * Could not load the following classes: * org.jspecify.annotations.Nullable */ package net.minecraft.world.entity.animal; import net.minecraft.core.BlockPos; 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.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.attribute.EnvironmentAttributes; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.Shearable; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.RangedAttackGoal; import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.animal.AbstractGolem; import net.minecraft.world.entity.monster.Enemy; import net.minecraft.world.entity.monster.RangedAttackMob; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.projectile.Snowball; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.level.storage.loot.BuiltInLootTables; import net.minecraft.world.phys.Vec3; import org.jspecify.annotations.Nullable; public class SnowGolem extends AbstractGolem implements RangedAttackMob, Shearable { private static final EntityDataAccessor DATA_PUMPKIN_ID = SynchedEntityData.defineId(SnowGolem.class, EntityDataSerializers.BYTE); private static final byte PUMPKIN_FLAG = 16; private static final boolean DEFAULT_PUMPKIN = true; public SnowGolem(EntityType type, Level level) { super((EntityType)type, level); } @Override protected void registerGoals() { this.goalSelector.addGoal(1, new RangedAttackGoal(this, 1.25, 20, 10.0f)); this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal((PathfinderMob)this, 1.0, 1.0000001E-5f)); this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0f)); this.goalSelector.addGoal(4, new RandomLookAroundGoal(this)); this.targetSelector.addGoal(1, new NearestAttackableTargetGoal(this, Mob.class, 10, true, false, (target, level) -> target instanceof Enemy)); } public static AttributeSupplier.Builder createAttributes() { return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 4.0).add(Attributes.MOVEMENT_SPEED, 0.2f); } @Override protected void defineSynchedData(SynchedEntityData.Builder entityData) { super.defineSynchedData(entityData); entityData.define(DATA_PUMPKIN_ID, (byte)16); } @Override protected void addAdditionalSaveData(ValueOutput output) { super.addAdditionalSaveData(output); output.putBoolean("Pumpkin", this.hasPumpkin()); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); this.setPumpkin(input.getBooleanOr("Pumpkin", true)); } @Override public boolean isSensitiveToWater() { return true; } @Override public void aiStep() { super.aiStep(); Level level = this.level(); if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; if (serverLevel.environmentAttributes().getValue(EnvironmentAttributes.SNOW_GOLEM_MELTS, this.position()).booleanValue()) { this.hurtServer(serverLevel, this.damageSources().onFire(), 1.0f); } if (!serverLevel.getGameRules().get(GameRules.MOB_GRIEFING).booleanValue()) { return; } BlockState snow = Blocks.SNOW.defaultBlockState(); for (int i = 0; i < 4; ++i) { int xx = Mth.floor(this.getX() + (double)((float)(i % 2 * 2 - 1) * 0.25f)); int yy = Mth.floor(this.getY()); int zz = Mth.floor(this.getZ() + (double)((float)(i / 2 % 2 * 2 - 1) * 0.25f)); BlockPos snowPos = new BlockPos(xx, yy, zz); if (!this.level().getBlockState(snowPos).isAir() || !snow.canSurvive(this.level(), snowPos)) continue; this.level().setBlockAndUpdate(snowPos, snow); this.level().gameEvent(GameEvent.BLOCK_PLACE, snowPos, GameEvent.Context.of(this, snow)); } } } @Override public void performRangedAttack(LivingEntity target, float power) { double xd = target.getX() - this.getX(); double yd = target.getEyeY() - (double)1.1f; double zd = target.getZ() - this.getZ(); double yo = Math.sqrt(xd * xd + zd * zd) * (double)0.2f; Level level = this.level(); if (level instanceof ServerLevel) { ServerLevel serverLevel = (ServerLevel)level; ItemStack itemStack = new ItemStack(Items.SNOWBALL); Projectile.spawnProjectile(new Snowball(serverLevel, this, itemStack), serverLevel, itemStack, projectile -> projectile.shoot(xd, yd + yo - projectile.getY(), zd, 1.6f, 12.0f)); } this.playSound(SoundEvents.SNOW_GOLEM_SHOOT, 1.0f, 0.4f / (this.getRandom().nextFloat() * 0.4f + 0.8f)); } @Override protected InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemStack = player.getItemInHand(hand); if (itemStack.is(Items.SHEARS) && this.readyForShearing()) { Level level = this.level(); if (level instanceof ServerLevel) { ServerLevel level2 = (ServerLevel)level; this.shear(level2, SoundSource.PLAYERS, itemStack); this.gameEvent(GameEvent.SHEAR, player); itemStack.hurtAndBreak(1, (LivingEntity)player, hand.asEquipmentSlot()); } return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void shear(ServerLevel level, SoundSource soundSource, ItemStack tool) { level.playSound(null, this, SoundEvents.SNOW_GOLEM_SHEAR, soundSource, 1.0f, 1.0f); this.setPumpkin(false); this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_SNOW_GOLEM, tool, (l, drop) -> this.spawnAtLocation((ServerLevel)l, (ItemStack)drop, this.getEyeHeight())); } @Override public boolean readyForShearing() { return this.isAlive() && this.hasPumpkin(); } public boolean hasPumpkin() { return (this.entityData.get(DATA_PUMPKIN_ID) & 0x10) != 0; } public void setPumpkin(boolean pumpkin) { byte current = this.entityData.get(DATA_PUMPKIN_ID); if (pumpkin) { this.entityData.set(DATA_PUMPKIN_ID, (byte)(current | 0x10)); } else { this.entityData.set(DATA_PUMPKIN_ID, (byte)(current & 0xFFFFFFEF)); } } @Override protected @Nullable SoundEvent getAmbientSound() { return SoundEvents.SNOW_GOLEM_AMBIENT; } @Override protected @Nullable SoundEvent getHurtSound(DamageSource source) { return SoundEvents.SNOW_GOLEM_HURT; } @Override protected @Nullable SoundEvent getDeathSound() { return SoundEvents.SNOW_GOLEM_DEATH; } @Override public Vec3 getLeashOffset() { return new Vec3(0.0, 0.75f * this.getEyeHeight(), this.getBbWidth() * 0.4f); } }