Improve Ai performance

This commit is contained in:
Sollace 2021-02-20 01:34:30 +02:00
parent 28532cd890
commit afcd59206c
5 changed files with 138 additions and 174 deletions

View file

@ -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;
import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; 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.ai.WantItTakeItGoal;
import com.minelittlepony.unicopia.entity.player.PlayerAttributes; import com.minelittlepony.unicopia.entity.player.PlayerAttributes;
@ -37,10 +37,11 @@ public class Creature extends Living<LivingEntity> {
} }
public void initAi(GoalSelector goals, GoalSelector targets) { public void initAi(GoalSelector goals, GoalSelector targets) {
targets.add(1, new WantItNeedItTargetGoal((MobEntity)entity)); DynamicTargetGoal targetter = new DynamicTargetGoal((MobEntity)entity);
goals.add(1, new WantItTakeItGoal((MobEntity)entity)); targets.add(1, targetter);
goals.add(1, new WantItTakeItGoal((MobEntity)entity, targetter));
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) { if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
goals.add(3, new BreakHeartGoal((MobEntity)entity)); goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter));
} }
} }

View file

@ -1,95 +1,87 @@
package com.minelittlepony.unicopia.entity.ai; package com.minelittlepony.unicopia.entity.ai;
import java.util.Comparator;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Optional; import java.util.Optional;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.entity.FloatingArtefactEntity; import com.minelittlepony.unicopia.entity.FloatingArtefactEntity;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ai.goal.Goal; import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.util.Hand;
public class BreakHeartGoal extends Goal { public class BreakHeartGoal extends Goal {
private final MobEntity mob; protected final MobEntity mob;
@Nullable private final DynamicTargetGoal targetter;
private FloatingArtefactEntity target; private final Supplier<Optional<Entity>> target;
private int cooldown; public BreakHeartGoal(MobEntity mob, DynamicTargetGoal targetter) {
public BreakHeartGoal(MobEntity mob) {
this.mob = mob; this.mob = mob;
this.targetter = targetter;
this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK)); 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 @Override
public boolean canStart() { public boolean canStart() {
Optional<FloatingArtefactEntity> item = VecHelper.findInRange(mob, mob.world, mob.getPos(), 16, return target.get().isPresent();
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;
} }
@Override @Override
public boolean shouldContinue() { 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 @Override
public void stop() { public void stop() {
target = null; targetter.stop();
mob.getNavigation().stop(); mob.getNavigation().stop();
} }
@Override @Override
public void tick() { public void tick() {
if (target == null || target.removed) { target.get().ifPresent(target -> {
target = null;
return;
}
mob.getLookControl().lookAt(target, 30, 30); 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()); 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; double speed = 0.9D;
if (distance > reach && distance < 16) { if (distance > reach && distance < 16) {
speed = 1.23; speed = 1.23;
} else if (distance < 225) { } else if (distance < 225) {
speed = 1.6; speed = 1.6;
} else if (distance <= 1) {
speed = 0.5;
} }
mob.getNavigation().startMovingTo(target, speed); mob.getNavigation().startMovingTo(target, speed);
cooldown = Math.max(this.cooldown - 1, 0);
if (target.getY() >= mob.getY() + 2) { if (target.getY() >= mob.getY() + 2) {
reach += 5; reach += 5;
} }
if (distance <= reach && cooldown <= 0) { if (distance <= reach) {
cooldown = 20; mob.swingHand(Hand.MAIN_HAND);
mob.tryAttack(target); mob.tryAttack(target);
} }
} }

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -1,97 +1,42 @@
package com.minelittlepony.unicopia.entity.ai; 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.AwaitTickQueue;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments; import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect; import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity; 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.entity.mob.MobEntity;
import net.minecraft.item.ItemStack; 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 protected int cooldown;
private LivingEntity target;
@Nullable
private ItemEntity item;
private int cooldown; public WantItTakeItGoal(MobEntity mob, DynamicTargetGoal targetter) {
super(mob, targetter);
public WantItTakeItGoal(MobEntity mob) {
this.mob = mob;
this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK));
} }
@Override @Override
public boolean canStart() { protected boolean canTarget(Entity e) {
LivingEntity target = mob.getTarget(); return (!e.removed && e instanceof ItemEntity && EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, ((ItemEntity)e).getStack()) > 0)
if (target == null || !EquinePredicates.HAS_WANT_IT_NEED_IT.test(target)) { || (e instanceof LivingEntity && predicate.test(mob, (LivingEntity)e));
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;
} }
@Override @Override
public boolean shouldContinue() { protected void attackTarget(Entity target, double reach, double distance) {
return (target == null || ( ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1);
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());
double speed = 0.8D; double speed = 0.8D;
@ -100,22 +45,25 @@ public class WantItTakeItGoal extends Goal {
} else if (distance < 225) { } else if (distance < 225) {
speed = 0.6; speed = 0.6;
} }
if (Math.abs(reach - distance) > 1) {
speed *= 2; 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 (distance <= reach) {
if (target != null) { if (target instanceof LivingEntity) {
if (cooldown <= 0) { if (cooldown <= 0) {
cooldown = 20; cooldown = 20;
mob.tryAttack(target); mob.tryAttack(target);
mob.swingHand(Hand.MAIN_HAND);
if (mob.world.random.nextInt(20) == 0) { if (mob.world.random.nextInt(20) == 0) {
for (EquipmentSlot slot : EquipmentSlot.values()) { 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) { if (EnchantmentHelper.getLevel(UEnchantments.WANT_IT_NEED_IT, stack) > 0) {
target.equipStack(slot, ItemStack.EMPTY); target.equipStack(slot, ItemStack.EMPTY);
AwaitTickQueue.scheduleTask(mob.world, w -> { AwaitTickQueue.scheduleTask(mob.world, w -> {
@ -125,9 +73,11 @@ public class WantItTakeItGoal extends Goal {
} }
} }
} }
} else { } else if (target instanceof ItemEntity) {
ItemStack stack = item.getStack();
AwaitTickQueue.scheduleTask(mob.world, w -> { AwaitTickQueue.scheduleTask(mob.world, w -> {
ItemEntity item = (ItemEntity)target;
ItemStack stack = item.getStack();
if (!item.removed) { if (!item.removed) {
mob.tryEquip(stack); mob.tryEquip(stack);
mob.method_29499(item); mob.method_29499(item);