minecraft-src/net/minecraft/world/entity/ai/behavior/UseBonemeal.java
2025-07-04 01:41:11 +03:00

120 lines
4.2 KiB
Java

package net.minecraft.world.entity.ai.behavior;
import com.google.common.collect.ImmutableMap;
import java.util.Optional;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.ai.memory.MemoryStatus;
import net.minecraft.world.entity.ai.memory.WalkTarget;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.item.BoneMealItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.CropBlock;
import net.minecraft.world.level.block.state.BlockState;
public class UseBonemeal extends Behavior<Villager> {
private static final int BONEMEALING_DURATION = 80;
private long nextWorkCycleTime;
private long lastBonemealingSession;
private int timeWorkedSoFar;
private Optional<BlockPos> cropPos = Optional.empty();
public UseBonemeal() {
super(ImmutableMap.of(MemoryModuleType.LOOK_TARGET, MemoryStatus.VALUE_ABSENT, MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT));
}
protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) {
if (owner.tickCount % 10 == 0 && (this.lastBonemealingSession == 0L || this.lastBonemealingSession + 160L <= owner.tickCount)) {
if (owner.getInventory().countItem(Items.BONE_MEAL) <= 0) {
return false;
} else {
this.cropPos = this.pickNextTarget(level, owner);
return this.cropPos.isPresent();
}
} else {
return false;
}
}
protected boolean canStillUse(ServerLevel level, Villager entity, long gameTime) {
return this.timeWorkedSoFar < 80 && this.cropPos.isPresent();
}
private Optional<BlockPos> pickNextTarget(ServerLevel level, Villager villager) {
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
Optional<BlockPos> optional = Optional.empty();
int i = 0;
for (int j = -1; j <= 1; j++) {
for (int k = -1; k <= 1; k++) {
for (int l = -1; l <= 1; l++) {
mutableBlockPos.setWithOffset(villager.blockPosition(), j, k, l);
if (this.validPos(mutableBlockPos, level)) {
if (level.random.nextInt(++i) == 0) {
optional = Optional.of(mutableBlockPos.immutable());
}
}
}
}
}
return optional;
}
private boolean validPos(BlockPos pos, ServerLevel level) {
BlockState blockState = level.getBlockState(pos);
Block block = blockState.getBlock();
return block instanceof CropBlock && !((CropBlock)block).isMaxAge(blockState);
}
protected void start(ServerLevel level, Villager entity, long gameTime) {
this.setCurrentCropAsTarget(entity);
entity.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.BONE_MEAL));
this.nextWorkCycleTime = gameTime;
this.timeWorkedSoFar = 0;
}
private void setCurrentCropAsTarget(Villager villager) {
this.cropPos.ifPresent(blockPos -> {
BlockPosTracker blockPosTracker = new BlockPosTracker(blockPos);
villager.getBrain().setMemory(MemoryModuleType.LOOK_TARGET, blockPosTracker);
villager.getBrain().setMemory(MemoryModuleType.WALK_TARGET, new WalkTarget(blockPosTracker, 0.5F, 1));
});
}
protected void stop(ServerLevel level, Villager entity, long gameTime) {
entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
this.lastBonemealingSession = entity.tickCount;
}
protected void tick(ServerLevel level, Villager owner, long gameTime) {
BlockPos blockPos = (BlockPos)this.cropPos.get();
if (gameTime >= this.nextWorkCycleTime && blockPos.closerToCenterThan(owner.position(), 1.0)) {
ItemStack itemStack = ItemStack.EMPTY;
SimpleContainer simpleContainer = owner.getInventory();
int i = simpleContainer.getContainerSize();
for (int j = 0; j < i; j++) {
ItemStack itemStack2 = simpleContainer.getItem(j);
if (itemStack2.is(Items.BONE_MEAL)) {
itemStack = itemStack2;
break;
}
}
if (!itemStack.isEmpty() && BoneMealItem.growCrop(itemStack, level, blockPos)) {
level.levelEvent(1505, blockPos, 15);
this.cropPos = this.pickNextTarget(level, owner);
this.setCurrentCropAsTarget(owner);
this.nextWorkCycleTime = gameTime + 40L;
}
this.timeWorkedSoFar++;
}
}
}