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

View file

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

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