mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Improve Ai performance
This commit is contained in:
parent
28532cd890
commit
afcd59206c
5 changed files with 138 additions and 174 deletions
|
@ -7,7 +7,7 @@ import com.minelittlepony.unicopia.ability.magic.Levelled;
|
|||
import com.minelittlepony.unicopia.ability.magic.Spell;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry;
|
||||
import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal;
|
||||
import com.minelittlepony.unicopia.entity.ai.WantItNeedItTargetGoal;
|
||||
import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal;
|
||||
import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal;
|
||||
import com.minelittlepony.unicopia.entity.player.PlayerAttributes;
|
||||
|
||||
|
@ -37,10 +37,11 @@ public class Creature extends Living<LivingEntity> {
|
|||
}
|
||||
|
||||
public void initAi(GoalSelector goals, GoalSelector targets) {
|
||||
targets.add(1, new WantItNeedItTargetGoal((MobEntity)entity));
|
||||
goals.add(1, new WantItTakeItGoal((MobEntity)entity));
|
||||
DynamicTargetGoal targetter = new DynamicTargetGoal((MobEntity)entity);
|
||||
targets.add(1, targetter);
|
||||
goals.add(1, new WantItTakeItGoal((MobEntity)entity, targetter));
|
||||
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
|
||||
goals.add(3, new BreakHeartGoal((MobEntity)entity));
|
||||
goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,95 +1,87 @@
|
|||
package com.minelittlepony.unicopia.entity.ai;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.minelittlepony.unicopia.entity.FloatingArtefactEntity;
|
||||
import com.minelittlepony.unicopia.item.UItems;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.util.Hand;
|
||||
|
||||
public class BreakHeartGoal extends Goal {
|
||||
|
||||
private final MobEntity mob;
|
||||
protected final MobEntity mob;
|
||||
|
||||
@Nullable
|
||||
private FloatingArtefactEntity target;
|
||||
private final DynamicTargetGoal targetter;
|
||||
private final Supplier<Optional<Entity>> target;
|
||||
|
||||
private int cooldown;
|
||||
|
||||
public BreakHeartGoal(MobEntity mob) {
|
||||
public BreakHeartGoal(MobEntity mob, DynamicTargetGoal targetter) {
|
||||
this.mob = mob;
|
||||
this.targetter = targetter;
|
||||
this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK));
|
||||
|
||||
target = targetter.addPredicate(this::canTarget);
|
||||
}
|
||||
|
||||
protected boolean canTarget(Entity e) {
|
||||
return !e.removed
|
||||
&& e instanceof FloatingArtefactEntity
|
||||
&& ((FloatingArtefactEntity)e).getStack().getItem() == UItems.CRYSTAL_HEART
|
||||
&& mob.getVisibilityCache().canSee(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStart() {
|
||||
Optional<FloatingArtefactEntity> item = VecHelper.findInRange(mob, mob.world, mob.getPos(), 16,
|
||||
e -> !e.removed
|
||||
&& e instanceof FloatingArtefactEntity
|
||||
&& ((FloatingArtefactEntity)e).getStack().getItem() == UItems.CRYSTAL_HEART
|
||||
&& mob.getVisibilityCache().canSee(e)
|
||||
)
|
||||
.stream()
|
||||
.map(e -> (FloatingArtefactEntity)e)
|
||||
.sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e)))
|
||||
.findFirst();
|
||||
|
||||
if (item.isPresent()) {
|
||||
this.target = item.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return target.get().isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldContinue() {
|
||||
return (target == null || (target.isAlive() && mob.squaredDistanceTo(target) <= 225)) || canStart();
|
||||
return target.get().map(mob::squaredDistanceTo).orElse(0D) <= 225
|
||||
&& (!mob.getNavigation().isIdle() || canStart());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
target = null;
|
||||
targetter.stop();
|
||||
mob.getNavigation().stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (target == null || target.removed) {
|
||||
target = null;
|
||||
return;
|
||||
}
|
||||
|
||||
target.get().ifPresent(target -> {
|
||||
mob.getLookControl().lookAt(target, 30, 30);
|
||||
|
||||
double reach = mob.getWidth() * 2 * mob.getWidth() * 2;
|
||||
double reach = mob.getWidth() * 2 * mob.getWidth() * 2 * target.getWidth();
|
||||
double distance = mob.squaredDistanceTo(target.getX(), target.getY(), target.getZ());
|
||||
|
||||
attackTarget(target, reach, distance);
|
||||
});
|
||||
}
|
||||
|
||||
protected void attackTarget(Entity target, double reach, double distance) {
|
||||
double speed = 0.9D;
|
||||
|
||||
if (distance > reach && distance < 16) {
|
||||
speed = 1.23;
|
||||
} else if (distance < 225) {
|
||||
speed = 1.6;
|
||||
} else if (distance <= 1) {
|
||||
speed = 0.5;
|
||||
}
|
||||
|
||||
mob.getNavigation().startMovingTo(target, speed);
|
||||
|
||||
cooldown = Math.max(this.cooldown - 1, 0);
|
||||
|
||||
if (target.getY() >= mob.getY() + 2) {
|
||||
reach += 5;
|
||||
}
|
||||
|
||||
if (distance <= reach && cooldown <= 0) {
|
||||
cooldown = 20;
|
||||
if (distance <= reach) {
|
||||
mob.swingHand(Hand.MAIN_HAND);
|
||||
mob.tryAttack(target);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package com.minelittlepony.unicopia.entity.ai;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.TargetPredicate;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
|
||||
public class DynamicTargetGoal extends Goal {
|
||||
|
||||
private final MobEntity mob;
|
||||
|
||||
private int interval;
|
||||
|
||||
private Optional<Entity> target;
|
||||
|
||||
@Nullable
|
||||
private Predicate<Entity> test;
|
||||
|
||||
public DynamicTargetGoal(MobEntity mob) {
|
||||
this.mob = mob;
|
||||
}
|
||||
|
||||
public Supplier<Optional<Entity>> addPredicate(Predicate<Entity> predicate) {
|
||||
test = test == null ? predicate : predicate.or(test);
|
||||
|
||||
return () -> target.filter(Entity::isAlive).filter(predicate);
|
||||
}
|
||||
|
||||
public Optional<Entity> getTarget() {
|
||||
return target.filter(test).filter(Entity::isAlive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStart() {
|
||||
if (interval-- <= 0) {
|
||||
interval = 20;
|
||||
|
||||
target = VecHelper.findInRange(mob, mob.world, mob.getPos(), 26, test)
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(e -> mob.distanceTo(e)))
|
||||
.findFirst();
|
||||
|
||||
if (target.isPresent()) {
|
||||
if (target.get() instanceof LivingEntity) {
|
||||
mob.setTarget((LivingEntity)target.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
target = Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldContinue() {
|
||||
LivingEntity target = mob.getTarget();
|
||||
return target != null && mob.isTarget(target, TargetPredicate.DEFAULT);
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package com.minelittlepony.unicopia.entity.ai;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.EquinePredicates;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.TargetPredicate;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
|
||||
public class WantItNeedItTargetGoal extends Goal {
|
||||
|
||||
private final TargetPredicate predicate;
|
||||
|
||||
private final MobEntity mob;
|
||||
|
||||
private int interval;
|
||||
|
||||
public WantItNeedItTargetGoal(MobEntity mob) {
|
||||
this.predicate = new TargetPredicate()
|
||||
.setBaseMaxDistance(64)
|
||||
.setPredicate(EquinePredicates.HAS_WANT_IT_NEED_IT);
|
||||
this.mob = mob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStart() {
|
||||
if (interval-- <= 0) {
|
||||
interval = 20;
|
||||
Optional<LivingEntity> target = mob.world.getOtherEntities(mob, mob.getBoundingBox().expand(16, 16, 16),
|
||||
e -> e instanceof LivingEntity && predicate.test(mob, (LivingEntity)e))
|
||||
.stream()
|
||||
.map(e -> (LivingEntity)e)
|
||||
.sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e)))
|
||||
.findFirst();
|
||||
|
||||
if (target.isPresent()) {
|
||||
mob.setTarget(target.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldContinue() {
|
||||
LivingEntity target = mob.getTarget();
|
||||
return target != null && mob.isTarget(target, TargetPredicate.DEFAULT);
|
||||
}
|
||||
}
|
|
@ -1,97 +1,42 @@
|
|||
package com.minelittlepony.unicopia.entity.ai;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.AwaitTickQueue;
|
||||
import com.minelittlepony.unicopia.EquinePredicates;
|
||||
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
|
||||
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||
import com.minelittlepony.unicopia.particle.ParticleUtils;
|
||||
import com.minelittlepony.unicopia.particle.UParticles;
|
||||
import com.minelittlepony.unicopia.util.VecHelper;
|
||||
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.ai.TargetPredicate;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Hand;
|
||||
|
||||
public class WantItTakeItGoal extends Goal {
|
||||
public class WantItTakeItGoal extends BreakHeartGoal {
|
||||
|
||||
private final MobEntity mob;
|
||||
private final TargetPredicate predicate = new TargetPredicate()
|
||||
.setBaseMaxDistance(64)
|
||||
.setPredicate(EquinePredicates.HAS_WANT_IT_NEED_IT);
|
||||
|
||||
@Nullable
|
||||
private LivingEntity target;
|
||||
@Nullable
|
||||
private ItemEntity item;
|
||||
protected int cooldown;
|
||||
|
||||
private int cooldown;
|
||||
|
||||
public WantItTakeItGoal(MobEntity mob) {
|
||||
this.mob = mob;
|
||||
this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK));
|
||||
public WantItTakeItGoal(MobEntity mob, DynamicTargetGoal targetter) {
|
||||
super(mob, targetter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStart() {
|
||||
LivingEntity target = mob.getTarget();
|
||||
if (target == null || !EquinePredicates.HAS_WANT_IT_NEED_IT.test(target)) {
|
||||
|
||||
Optional<ItemEntity> item = VecHelper.findInRange(mob, mob.world, mob.getPos(), 16,
|
||||
e -> !e.removed && mob.canSee(e) && e instanceof ItemEntity && EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, ((ItemEntity)e).getStack()) > 0)
|
||||
.stream()
|
||||
.map(e -> (ItemEntity)e)
|
||||
.sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e)))
|
||||
.findFirst();
|
||||
|
||||
if (item.isPresent()) {
|
||||
this.item = item.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.target = target;
|
||||
return true;
|
||||
protected boolean canTarget(Entity e) {
|
||||
return (!e.removed && e instanceof ItemEntity && EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, ((ItemEntity)e).getStack()) > 0)
|
||||
|| (e instanceof LivingEntity && predicate.test(mob, (LivingEntity)e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldContinue() {
|
||||
return (target == null || (
|
||||
target.isAlive()
|
||||
&& EquinePredicates.HAS_WANT_IT_NEED_IT.test(target)
|
||||
&& mob.squaredDistanceTo(target) <= 225))
|
||||
&& (item == null || item.isAlive())
|
||||
&& (!mob.getNavigation().isIdle() || canStart());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
target = null;
|
||||
item = null;
|
||||
mob.getNavigation().stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (target == null && (item == null || item.removed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entity targetEntity = target == null ? item : target;
|
||||
|
||||
mob.getLookControl().lookAt(targetEntity, 30, 30);
|
||||
|
||||
double reach = mob.getWidth() * 2 * mob.getWidth() * 2;
|
||||
double distance = mob.squaredDistanceTo(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ());
|
||||
protected void attackTarget(Entity target, double reach, double distance) {
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1);
|
||||
|
||||
double speed = 0.8D;
|
||||
|
||||
|
@ -100,22 +45,25 @@ public class WantItTakeItGoal extends Goal {
|
|||
} else if (distance < 225) {
|
||||
speed = 0.6;
|
||||
}
|
||||
if (Math.abs(reach - distance) > 1) {
|
||||
speed *= 2;
|
||||
}
|
||||
|
||||
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1);
|
||||
mob.getNavigation().startMovingTo(target, speed);
|
||||
|
||||
mob.getNavigation().startMovingTo(targetEntity, speed);
|
||||
cooldown = Math.max(cooldown - 1, 0);
|
||||
|
||||
cooldown = Math.max(this.cooldown - 1, 0);
|
||||
if (distance <= reach) {
|
||||
if (target != null) {
|
||||
if (target instanceof LivingEntity) {
|
||||
if (cooldown <= 0) {
|
||||
cooldown = 20;
|
||||
mob.tryAttack(target);
|
||||
mob.swingHand(Hand.MAIN_HAND);
|
||||
|
||||
if (mob.world.random.nextInt(20) == 0) {
|
||||
|
||||
for (EquipmentSlot slot : EquipmentSlot.values()) {
|
||||
ItemStack stack = target.getEquippedStack(slot);
|
||||
ItemStack stack = ((LivingEntity)target).getEquippedStack(slot);
|
||||
if (EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, stack) > 0) {
|
||||
target.equipStack(slot, ItemStack.EMPTY);
|
||||
AwaitTickQueue.scheduleTask(mob.world, w -> {
|
||||
|
@ -125,9 +73,11 @@ public class WantItTakeItGoal extends Goal {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ItemStack stack = item.getStack();
|
||||
} else if (target instanceof ItemEntity) {
|
||||
AwaitTickQueue.scheduleTask(mob.world, w -> {
|
||||
ItemEntity item = (ItemEntity)target;
|
||||
ItemStack stack = item.getStack();
|
||||
|
||||
if (!item.removed) {
|
||||
mob.tryEquip(stack);
|
||||
mob.method_29499(item);
|
||||
|
|
Loading…
Reference in a new issue