203 lines
8.3 KiB
Java
203 lines
8.3 KiB
Java
/*
|
|
* 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<Byte> 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<? extends SnowGolem> type, Level level) {
|
|
super((EntityType<? extends AbstractGolem>)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<Mob>(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);
|
|
}
|
|
}
|
|
|