Configure skeletons to target flying players over players on the ground, and fire at them with more accuracy

This commit is contained in:
Sollace 2024-05-19 20:21:46 +01:00
parent 5d4c0d0dd0
commit b4126b839b
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
6 changed files with 112 additions and 1 deletions

View file

@ -17,6 +17,8 @@ import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal;
import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal;
import com.minelittlepony.unicopia.entity.ai.EatMuffinGoal; import com.minelittlepony.unicopia.entity.ai.EatMuffinGoal;
import com.minelittlepony.unicopia.entity.ai.FleeExplosionGoal; import com.minelittlepony.unicopia.entity.ai.FleeExplosionGoal;
import com.minelittlepony.unicopia.entity.ai.PrioritizedActiveTargetGoal;
import com.minelittlepony.unicopia.entity.ai.TargettingUtil;
import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal;
import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
@ -152,6 +154,9 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned.Mutabl
} }
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) { if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter)); goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter));
if (entity instanceof AbstractSkeletonEntity) {
targets.add(1, new PrioritizedActiveTargetGoal<>((MobEntity)entity, PlayerEntity.class, TargettingUtil.FLYING_PREFERRED, true));
}
} }
if (entity instanceof PigEntity pig) { if (entity instanceof PigEntity pig) {
eatMuffinGoal = new EatMuffinGoal(pig, targetter); eatMuffinGoal = new EatMuffinGoal(pig, targetter);

View file

@ -98,7 +98,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this)); private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this));
private final Enchantments enchants = addTicker(new Enchantments(this)); private final Enchantments enchants = addTicker(new Enchantments(this));
private final ItemTracker armour = addTicker(new ItemTracker(this)); private final ItemTracker armour = addTicker(new ItemTracker(this));
//private final Transportation<T> transportation = new Transportation<>(this);
private final Transportation<T> transportation = new Transportation<>(this); private final Transportation<T> transportation = new Transportation<>(this);
protected Living(T entity, TrackedData<NbtCompound> effect) { protected Living(T entity, TrackedData<NbtCompound> effect) {

View file

@ -0,0 +1,35 @@
package com.minelittlepony.unicopia.entity.ai;
import java.util.Comparator;
import java.util.function.Predicate;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.ActiveTargetGoal;
import net.minecraft.entity.mob.MobEntity;
public class PrioritizedActiveTargetGoal<T extends LivingEntity> extends ActiveTargetGoal<T> {
private final Comparator<T> prioritySorting;
public PrioritizedActiveTargetGoal(MobEntity mob, Class<T> targetClass, Comparator<T> prioritySorting, boolean checkVisibility) {
super(mob, targetClass, checkVisibility);
this.prioritySorting = prioritySorting;
}
public PrioritizedActiveTargetGoal(MobEntity mob, Class<T> targetClass, Comparator<T> prioritySorting, boolean checkVisibility, Predicate<LivingEntity> targetPredicate) {
super(mob, targetClass, 10, checkVisibility, false, targetPredicate);
this.prioritySorting = prioritySorting;
}
public PrioritizedActiveTargetGoal(MobEntity mob, Class<T> targetClass, Comparator<T> prioritySorting, boolean checkVisibility, boolean checkCanNavigate) {
super(mob, targetClass, 10, checkVisibility, checkCanNavigate, null);
this.prioritySorting = prioritySorting;
}
@Override
protected void findClosestTarget() {
targetEntity = TargettingUtil.getTargets(targetClass, targetPredicate, mob, getSearchBox(getFollowRange()))
.sorted(prioritySorting.thenComparing(TargettingUtil.nearestTo(mob)))
.findFirst()
.orElse(null);
}
}

View file

@ -0,0 +1,40 @@
package com.minelittlepony.unicopia.entity.ai;
import java.util.Comparator;
import java.util.stream.Stream;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
public interface TargettingUtil {
Comparator<PlayerEntity> FLYING_PREFERRED = Comparator.comparing(e -> Pony.of(e).getPhysics().isFlying() ? 0 : 1);
@SuppressWarnings("unchecked")
static <T extends LivingEntity> Stream<T> getTargets(Class<T> type, TargetPredicate predicate, LivingEntity subject, Box searchArea) {
if (type == PlayerEntity.class || type == ServerPlayerEntity.class) {
return (Stream<T>)subject.getWorld().getPlayers(predicate, subject, searchArea).stream();
}
return subject.getWorld().getTargets(type, predicate, subject, searchArea).stream();
}
static <T extends Entity> Comparator<T> nearestTo(LivingEntity subject) {
Vec3d fromPos = subject.getEyePos();
return Comparator.comparing(e -> fromPos.distanceTo(e.getPos()));
}
static Vec3d getProjectedPos(LivingEntity entity) {
if (entity instanceof PlayerEntity player) {
Vec3d velocity = Pony.of(player).getPhysics().getClientVelocity();
System.out.println(velocity);
return entity.getEyePos().add(velocity.multiply(1.5)).add(0, -1, 0);
}
return entity.getEyePos().add(entity.getVelocity());
}
}

View file

@ -0,0 +1,31 @@
package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import com.minelittlepony.unicopia.entity.ai.TargettingUtil;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.AbstractSkeletonEntity;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.PersistentProjectileEntity;
import net.minecraft.util.math.Vec3d;
@Mixin(AbstractSkeletonEntity.class)
abstract class MixinAbstractSkeletonEntity extends HostileEntity {
MixinAbstractSkeletonEntity() { super(null, null); }
@ModifyArg(method = "attack", at = @At(value = "INVOKE", target = "net/minecraft/world/World.spawnEntity(Lnet/minecraft/entity/Entity;)Z"))
private Entity modifyAccuracy(Entity entity) {
if (entity instanceof PersistentProjectileEntity projectile && getTarget() instanceof PlayerEntity player && Pony.of(player).getPhysics().isFlying()) {
Vec3d targetPos = TargettingUtil.getProjectedPos(player)
.add(0, player.getHeight() * 0.33333F, 0)
.subtract(projectile.getPos());
projectile.setVelocity(targetPos.x, targetPos.y + targetPos.horizontalLength() * 0.2, targetPos.z, 1.6F, (14 - getWorld().getDifficulty().getId() * 4) * 0.25F);
}
return entity;
}
}

View file

@ -7,6 +7,7 @@
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"mixins": [ "mixins": [
"MixinAbstractDecorationEntity", "MixinAbstractDecorationEntity",
"MixinAbstractSkeletonEntity",
"MixinBlazeEntity", "MixinBlazeEntity",
"MixinBlock", "MixinBlock",
"MixinBlockEntity", "MixinBlockEntity",