minecraft-src/net/minecraft/world/entity/animal/MushroomCow.java
2025-07-04 02:49:36 +03:00

267 lines
9.6 KiB
Java

package net.minecraft.world.entity.animal;
import java.util.Optional;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.SynchedEntityData.Builder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.ConversionParams;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.entity.Shearable;
import net.minecraft.world.entity.VariantHolder;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemUtils;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.SuspiciousStewEffects;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.SuspiciousEffectHolder;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import org.jetbrains.annotations.Nullable;
public class MushroomCow extends Cow implements Shearable, VariantHolder<MushroomCow.Variant> {
private static final EntityDataAccessor<String> DATA_TYPE = SynchedEntityData.defineId(MushroomCow.class, EntityDataSerializers.STRING);
private static final int MUTATE_CHANCE = 1024;
private static final String TAG_STEW_EFFECTS = "stew_effects";
@Nullable
private SuspiciousStewEffects stewEffects;
/**
* Stores the UUID of the most recent lightning bolt to strike
*/
@Nullable
private UUID lastLightningBoltUUID;
public MushroomCow(EntityType<? extends MushroomCow> entityType, Level level) {
super(entityType, level);
}
@Override
public float getWalkTargetValue(BlockPos pos, LevelReader level) {
return level.getBlockState(pos.below()).is(Blocks.MYCELIUM) ? 10.0F : level.getPathfindingCostFromLightLevels(pos);
}
public static boolean checkMushroomSpawnRules(
EntityType<MushroomCow> entityType, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random
) {
return level.getBlockState(pos.below()).is(BlockTags.MOOSHROOMS_SPAWNABLE_ON) && isBrightEnoughToSpawn(level, pos);
}
@Override
public void thunderHit(ServerLevel level, LightningBolt lightning) {
UUID uUID = lightning.getUUID();
if (!uUID.equals(this.lastLightningBoltUUID)) {
this.setVariant(this.getVariant() == MushroomCow.Variant.RED ? MushroomCow.Variant.BROWN : MushroomCow.Variant.RED);
this.lastLightningBoltUUID = uUID;
this.playSound(SoundEvents.MOOSHROOM_CONVERT, 2.0F, 1.0F);
}
}
@Override
protected void defineSynchedData(Builder builder) {
super.defineSynchedData(builder);
builder.define(DATA_TYPE, MushroomCow.Variant.RED.type);
}
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack itemStack = player.getItemInHand(hand);
if (itemStack.is(Items.BOWL) && !this.isBaby()) {
boolean bl = false;
ItemStack itemStack2;
if (this.stewEffects != null) {
bl = true;
itemStack2 = new ItemStack(Items.SUSPICIOUS_STEW);
itemStack2.set(DataComponents.SUSPICIOUS_STEW_EFFECTS, this.stewEffects);
this.stewEffects = null;
} else {
itemStack2 = new ItemStack(Items.MUSHROOM_STEW);
}
ItemStack itemStack3 = ItemUtils.createFilledResult(itemStack, player, itemStack2, false);
player.setItemInHand(hand, itemStack3);
SoundEvent soundEvent;
if (bl) {
soundEvent = SoundEvents.MOOSHROOM_MILK_SUSPICIOUSLY;
} else {
soundEvent = SoundEvents.MOOSHROOM_MILK;
}
this.playSound(soundEvent, 1.0F, 1.0F);
return InteractionResult.SUCCESS;
} else if (itemStack.is(Items.SHEARS) && this.readyForShearing()) {
if (this.level() instanceof ServerLevel serverLevel) {
this.shear(serverLevel, SoundSource.PLAYERS, itemStack);
this.gameEvent(GameEvent.SHEAR, player);
itemStack.hurtAndBreak(1, player, getSlotForHand(hand));
}
return InteractionResult.SUCCESS;
} else if (this.getVariant() == MushroomCow.Variant.BROWN && itemStack.is(ItemTags.SMALL_FLOWERS)) {
if (this.stewEffects != null) {
for (int i = 0; i < 2; i++) {
this.level()
.addParticle(
ParticleTypes.SMOKE,
this.getX() + this.random.nextDouble() / 2.0,
this.getY(0.5),
this.getZ() + this.random.nextDouble() / 2.0,
0.0,
this.random.nextDouble() / 5.0,
0.0
);
}
} else {
Optional<SuspiciousStewEffects> optional = this.getEffectsFromItemStack(itemStack);
if (optional.isEmpty()) {
return InteractionResult.PASS;
}
itemStack.consume(1, player);
for (int j = 0; j < 4; j++) {
this.level()
.addParticle(
ParticleTypes.EFFECT,
this.getX() + this.random.nextDouble() / 2.0,
this.getY(0.5),
this.getZ() + this.random.nextDouble() / 2.0,
0.0,
this.random.nextDouble() / 5.0,
0.0
);
}
this.stewEffects = (SuspiciousStewEffects)optional.get();
this.playSound(SoundEvents.MOOSHROOM_EAT, 2.0F, 1.0F);
}
return InteractionResult.SUCCESS;
} else {
return super.mobInteract(player, hand);
}
}
@Override
public void shear(ServerLevel level, SoundSource soundSource, ItemStack shears) {
level.playSound(null, this, SoundEvents.MOOSHROOM_SHEAR, soundSource, 1.0F, 1.0F);
this.convertTo(EntityType.COW, ConversionParams.single(this, false, false), cow -> {
level.sendParticles(ParticleTypes.EXPLOSION, this.getX(), this.getY(0.5), this.getZ(), 1, 0.0, 0.0, 0.0, 0.0);
this.dropFromShearingLootTable(level, BuiltInLootTables.SHEAR_MOOSHROOM, shears, (serverLevelx, itemStackx) -> {
for (int i = 0; i < itemStackx.getCount(); i++) {
serverLevelx.addFreshEntity(new ItemEntity(this.level(), this.getX(), this.getY(1.0), this.getZ(), itemStackx.copyWithCount(1)));
}
});
});
}
@Override
public boolean readyForShearing() {
return this.isAlive() && !this.isBaby();
}
@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
tag.putString("Type", this.getVariant().getSerializedName());
if (this.stewEffects != null) {
SuspiciousStewEffects.CODEC.encodeStart(NbtOps.INSTANCE, this.stewEffects).ifSuccess(tagx -> tag.put("stew_effects", tagx));
}
}
@Override
public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
this.setVariant(MushroomCow.Variant.byName(tag.getString("Type")));
if (tag.contains("stew_effects", 9)) {
SuspiciousStewEffects.CODEC.parse(NbtOps.INSTANCE, tag.get("stew_effects")).ifSuccess(suspiciousStewEffects -> this.stewEffects = suspiciousStewEffects);
}
}
private Optional<SuspiciousStewEffects> getEffectsFromItemStack(ItemStack stack) {
SuspiciousEffectHolder suspiciousEffectHolder = SuspiciousEffectHolder.tryGet(stack.getItem());
return suspiciousEffectHolder != null ? Optional.of(suspiciousEffectHolder.getSuspiciousEffects()) : Optional.empty();
}
public void setVariant(MushroomCow.Variant variant) {
this.entityData.set(DATA_TYPE, variant.type);
}
public MushroomCow.Variant getVariant() {
return MushroomCow.Variant.byName(this.entityData.get(DATA_TYPE));
}
@Nullable
public MushroomCow getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
MushroomCow mushroomCow = EntityType.MOOSHROOM.create(level, EntitySpawnReason.BREEDING);
if (mushroomCow != null) {
mushroomCow.setVariant(this.getOffspringVariant((MushroomCow)otherParent));
}
return mushroomCow;
}
private MushroomCow.Variant getOffspringVariant(MushroomCow partner) {
MushroomCow.Variant variant = this.getVariant();
MushroomCow.Variant variant2 = partner.getVariant();
MushroomCow.Variant variant3;
if (variant == variant2 && this.random.nextInt(1024) == 0) {
variant3 = variant == MushroomCow.Variant.BROWN ? MushroomCow.Variant.RED : MushroomCow.Variant.BROWN;
} else {
variant3 = this.random.nextBoolean() ? variant : variant2;
}
return variant3;
}
public static enum Variant implements StringRepresentable {
RED("red", Blocks.RED_MUSHROOM.defaultBlockState()),
BROWN("brown", Blocks.BROWN_MUSHROOM.defaultBlockState());
public static final StringRepresentable.EnumCodec<MushroomCow.Variant> CODEC = StringRepresentable.fromEnum(MushroomCow.Variant::values);
final String type;
private final BlockState blockState;
private Variant(final String type, final BlockState blockState) {
this.type = type;
this.blockState = blockState;
}
public BlockState getBlockState() {
return this.blockState;
}
@Override
public String getSerializedName() {
return this.type;
}
static MushroomCow.Variant byName(String name) {
return (MushroomCow.Variant)CODEC.byName(name, RED);
}
}
}