139 lines
5.5 KiB
Java
139 lines
5.5 KiB
Java
package net.minecraft.world.entity.ai.behavior;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.effect.MobEffects;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
|
import net.minecraft.world.entity.ai.memory.MemoryStatus;
|
|
import net.minecraft.world.entity.npc.Villager;
|
|
import net.minecraft.world.entity.npc.VillagerProfession;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
|
|
import net.minecraft.world.level.storage.loot.LootTable;
|
|
|
|
public class GiveGiftToHero extends Behavior<Villager> {
|
|
private static final int THROW_GIFT_AT_DISTANCE = 5;
|
|
private static final int MIN_TIME_BETWEEN_GIFTS = 600;
|
|
private static final int MAX_TIME_BETWEEN_GIFTS = 6600;
|
|
private static final int TIME_TO_DELAY_FOR_HEAD_TO_FINISH_TURNING = 20;
|
|
private static final Map<ResourceKey<VillagerProfession>, ResourceKey<LootTable>> GIFTS = ImmutableMap.<ResourceKey<VillagerProfession>, ResourceKey<LootTable>>builder()
|
|
.put(VillagerProfession.ARMORER, BuiltInLootTables.ARMORER_GIFT)
|
|
.put(VillagerProfession.BUTCHER, BuiltInLootTables.BUTCHER_GIFT)
|
|
.put(VillagerProfession.CARTOGRAPHER, BuiltInLootTables.CARTOGRAPHER_GIFT)
|
|
.put(VillagerProfession.CLERIC, BuiltInLootTables.CLERIC_GIFT)
|
|
.put(VillagerProfession.FARMER, BuiltInLootTables.FARMER_GIFT)
|
|
.put(VillagerProfession.FISHERMAN, BuiltInLootTables.FISHERMAN_GIFT)
|
|
.put(VillagerProfession.FLETCHER, BuiltInLootTables.FLETCHER_GIFT)
|
|
.put(VillagerProfession.LEATHERWORKER, BuiltInLootTables.LEATHERWORKER_GIFT)
|
|
.put(VillagerProfession.LIBRARIAN, BuiltInLootTables.LIBRARIAN_GIFT)
|
|
.put(VillagerProfession.MASON, BuiltInLootTables.MASON_GIFT)
|
|
.put(VillagerProfession.SHEPHERD, BuiltInLootTables.SHEPHERD_GIFT)
|
|
.put(VillagerProfession.TOOLSMITH, BuiltInLootTables.TOOLSMITH_GIFT)
|
|
.put(VillagerProfession.WEAPONSMITH, BuiltInLootTables.WEAPONSMITH_GIFT)
|
|
.build();
|
|
private static final float SPEED_MODIFIER = 0.5F;
|
|
private int timeUntilNextGift = 600;
|
|
private boolean giftGivenDuringThisRun;
|
|
private long timeSinceStart;
|
|
|
|
public GiveGiftToHero(int duration) {
|
|
super(
|
|
ImmutableMap.of(
|
|
MemoryModuleType.WALK_TARGET,
|
|
MemoryStatus.REGISTERED,
|
|
MemoryModuleType.LOOK_TARGET,
|
|
MemoryStatus.REGISTERED,
|
|
MemoryModuleType.INTERACTION_TARGET,
|
|
MemoryStatus.REGISTERED,
|
|
MemoryModuleType.NEAREST_VISIBLE_PLAYER,
|
|
MemoryStatus.VALUE_PRESENT
|
|
),
|
|
duration
|
|
);
|
|
}
|
|
|
|
protected boolean checkExtraStartConditions(ServerLevel level, Villager owner) {
|
|
if (!this.isHeroVisible(owner)) {
|
|
return false;
|
|
} else if (this.timeUntilNextGift > 0) {
|
|
this.timeUntilNextGift--;
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
protected void start(ServerLevel level, Villager entity, long gameTime) {
|
|
this.giftGivenDuringThisRun = false;
|
|
this.timeSinceStart = gameTime;
|
|
Player player = (Player)this.getNearestTargetableHero(entity).get();
|
|
entity.getBrain().setMemory(MemoryModuleType.INTERACTION_TARGET, player);
|
|
BehaviorUtils.lookAtEntity(entity, player);
|
|
}
|
|
|
|
protected boolean canStillUse(ServerLevel level, Villager entity, long gameTime) {
|
|
return this.isHeroVisible(entity) && !this.giftGivenDuringThisRun;
|
|
}
|
|
|
|
protected void tick(ServerLevel level, Villager owner, long gameTime) {
|
|
Player player = (Player)this.getNearestTargetableHero(owner).get();
|
|
BehaviorUtils.lookAtEntity(owner, player);
|
|
if (this.isWithinThrowingDistance(owner, player)) {
|
|
if (gameTime - this.timeSinceStart > 20L) {
|
|
this.throwGift(level, owner, player);
|
|
this.giftGivenDuringThisRun = true;
|
|
}
|
|
} else {
|
|
BehaviorUtils.setWalkAndLookTargetMemories(owner, player, 0.5F, 5);
|
|
}
|
|
}
|
|
|
|
protected void stop(ServerLevel level, Villager entity, long gameTime) {
|
|
this.timeUntilNextGift = calculateTimeUntilNextGift(level);
|
|
entity.getBrain().eraseMemory(MemoryModuleType.INTERACTION_TARGET);
|
|
entity.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET);
|
|
entity.getBrain().eraseMemory(MemoryModuleType.LOOK_TARGET);
|
|
}
|
|
|
|
private void throwGift(ServerLevel level, Villager villager, LivingEntity target) {
|
|
villager.dropFromGiftLootTable(
|
|
level, getLootTableToThrow(villager), (serverLevel, itemStack) -> BehaviorUtils.throwItem(villager, itemStack, target.position())
|
|
);
|
|
}
|
|
|
|
private static ResourceKey<LootTable> getLootTableToThrow(Villager villager) {
|
|
if (villager.isBaby()) {
|
|
return BuiltInLootTables.BABY_VILLAGER_GIFT;
|
|
} else {
|
|
Optional<ResourceKey<VillagerProfession>> optional = villager.getVillagerData().profession().unwrapKey();
|
|
return optional.isEmpty() ? BuiltInLootTables.UNEMPLOYED_GIFT : (ResourceKey)GIFTS.getOrDefault(optional.get(), BuiltInLootTables.UNEMPLOYED_GIFT);
|
|
}
|
|
}
|
|
|
|
private boolean isHeroVisible(Villager villager) {
|
|
return this.getNearestTargetableHero(villager).isPresent();
|
|
}
|
|
|
|
private Optional<Player> getNearestTargetableHero(Villager villager) {
|
|
return villager.getBrain().getMemory(MemoryModuleType.NEAREST_VISIBLE_PLAYER).filter(this::isHero);
|
|
}
|
|
|
|
private boolean isHero(Player player) {
|
|
return player.hasEffect(MobEffects.HERO_OF_THE_VILLAGE);
|
|
}
|
|
|
|
private boolean isWithinThrowingDistance(Villager villager, Player hero) {
|
|
BlockPos blockPos = hero.blockPosition();
|
|
BlockPos blockPos2 = villager.blockPosition();
|
|
return blockPos2.closerThan(blockPos, 5.0);
|
|
}
|
|
|
|
private static int calculateTimeUntilNextGift(ServerLevel level) {
|
|
return 600 + level.random.nextInt(6001);
|
|
}
|
|
}
|