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.core.GlobalPos; import net.minecraft.core.Holder; import net.minecraft.network.protocol.game.DebugPackets; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.memory.MemoryModuleType; import net.minecraft.world.entity.ai.memory.MemoryStatus; import net.minecraft.world.entity.ai.village.poi.PoiType; import net.minecraft.world.entity.ai.village.poi.PoiTypes; import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.level.pathfinder.Path; public class VillagerMakeLove extends Behavior { private long birthTimestamp; public VillagerMakeLove() { super( ImmutableMap.of(MemoryModuleType.BREED_TARGET, MemoryStatus.VALUE_PRESENT, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryStatus.VALUE_PRESENT), 350, 350 ); } protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) { return this.isBreedingPossible(owner); } protected boolean canStillUse(ServerLevel level, Villager entity, long gameTime) { return gameTime <= this.birthTimestamp && this.isBreedingPossible(entity); } protected void start(ServerLevel level, Villager entity, long gameTime) { AgeableMob ageableMob = (AgeableMob)entity.getBrain().getMemory(MemoryModuleType.BREED_TARGET).get(); BehaviorUtils.lockGazeAndWalkToEachOther(entity, ageableMob, 0.5F, 2); level.broadcastEntityEvent(ageableMob, (byte)18); level.broadcastEntityEvent(entity, (byte)18); int i = 275 + entity.getRandom().nextInt(50); this.birthTimestamp = gameTime + i; } protected void tick(ServerLevel level, Villager owner, long gameTime) { Villager villager = (Villager)owner.getBrain().getMemory(MemoryModuleType.BREED_TARGET).get(); if (!(owner.distanceToSqr(villager) > 5.0)) { BehaviorUtils.lockGazeAndWalkToEachOther(owner, villager, 0.5F, 2); if (gameTime >= this.birthTimestamp) { owner.eatAndDigestFood(); villager.eatAndDigestFood(); this.tryToGiveBirth(level, owner, villager); } else if (owner.getRandom().nextInt(35) == 0) { level.broadcastEntityEvent(villager, (byte)12); level.broadcastEntityEvent(owner, (byte)12); } } } private void tryToGiveBirth(ServerLevel level, Villager parent, Villager partner) { Optional optional = this.takeVacantBed(level, parent); if (optional.isEmpty()) { level.broadcastEntityEvent(partner, (byte)13); level.broadcastEntityEvent(parent, (byte)13); } else { Optional optional2 = this.breed(level, parent, partner); if (optional2.isPresent()) { this.giveBedToChild(level, (Villager)optional2.get(), (BlockPos)optional.get()); } else { level.getPoiManager().release((BlockPos)optional.get()); DebugPackets.sendPoiTicketCountPacket(level, (BlockPos)optional.get()); } } } protected void stop(ServerLevel level, Villager entity, long gameTime) { entity.getBrain().eraseMemory(MemoryModuleType.BREED_TARGET); } private boolean isBreedingPossible(Villager villager) { Brain brain = villager.getBrain(); Optional optional = brain.getMemory(MemoryModuleType.BREED_TARGET).filter(ageableMob -> ageableMob.getType() == EntityType.VILLAGER); return optional.isEmpty() ? false : BehaviorUtils.targetIsValid(brain, MemoryModuleType.BREED_TARGET, EntityType.VILLAGER) && villager.canBreed() && ((AgeableMob)optional.get()).canBreed(); } private Optional takeVacantBed(ServerLevel level, Villager villager) { return level.getPoiManager() .take(holder -> holder.is(PoiTypes.HOME), (holder, blockPos) -> this.canReach(villager, blockPos, holder), villager.blockPosition(), 48); } private boolean canReach(Villager villager, BlockPos pos, Holder poiType) { Path path = villager.getNavigation().createPath(pos, poiType.value().validRange()); return path != null && path.canReach(); } private Optional breed(ServerLevel level, Villager parent, Villager partner) { Villager villager = parent.getBreedOffspring(level, partner); if (villager == null) { return Optional.empty(); } else { parent.setAge(6000); partner.setAge(6000); villager.setAge(-24000); villager.snapTo(parent.getX(), parent.getY(), parent.getZ(), 0.0F, 0.0F); level.addFreshEntityWithPassengers(villager); level.broadcastEntityEvent(villager, (byte)12); return Optional.of(villager); } } private void giveBedToChild(ServerLevel level, Villager villager, BlockPos pos) { GlobalPos globalPos = GlobalPos.of(level.dimension(), pos); villager.getBrain().setMemory(MemoryModuleType.HOME, globalPos); } }