From b4126b839b05bd539307fd2f96086acd250eeeeb Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 19 May 2024 20:21:46 +0100 Subject: [PATCH] Configure skeletons to target flying players over players on the ground, and fire at them with more accuracy --- .../unicopia/entity/Creature.java | 5 +++ .../unicopia/entity/Living.java | 1 - .../ai/PrioritizedActiveTargetGoal.java | 35 ++++++++++++++++ .../unicopia/entity/ai/TargettingUtil.java | 40 +++++++++++++++++++ .../mixin/MixinAbstractSkeletonEntity.java | 31 ++++++++++++++ src/main/resources/unicopia.mixin.json | 1 + 6 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java index cd0277dd..40d90e32 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Creature.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Creature.java @@ -17,6 +17,8 @@ import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.EatMuffinGoal; 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.mob.UEntityAttributes; @@ -152,6 +154,9 @@ public class Creature extends Living implements WeaklyOwned.Mutabl } if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) { 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) { eatMuffinGoal = new EatMuffinGoal(pig, targetter); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index 95631823..7a1807db 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -98,7 +98,6 @@ public abstract class Living implements Equine, Caste private final LandingEventHandler landEvent = addTicker(new LandingEventHandler(this)); private final Enchantments enchants = addTicker(new Enchantments(this)); private final ItemTracker armour = addTicker(new ItemTracker(this)); - //private final Transportation transportation = new Transportation<>(this); private final Transportation transportation = new Transportation<>(this); protected Living(T entity, TrackedData effect) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java new file mode 100644 index 00000000..67ea7796 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/PrioritizedActiveTargetGoal.java @@ -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 extends ActiveTargetGoal { + + private final Comparator prioritySorting; + + public PrioritizedActiveTargetGoal(MobEntity mob, Class targetClass, Comparator prioritySorting, boolean checkVisibility) { + super(mob, targetClass, checkVisibility); + this.prioritySorting = prioritySorting; + } + + public PrioritizedActiveTargetGoal(MobEntity mob, Class targetClass, Comparator prioritySorting, boolean checkVisibility, Predicate targetPredicate) { + super(mob, targetClass, 10, checkVisibility, false, targetPredicate); + this.prioritySorting = prioritySorting; + } + + public PrioritizedActiveTargetGoal(MobEntity mob, Class targetClass, Comparator 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); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java b/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java new file mode 100644 index 00000000..fe611c57 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/ai/TargettingUtil.java @@ -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 FLYING_PREFERRED = Comparator.comparing(e -> Pony.of(e).getPhysics().isFlying() ? 0 : 1); + + @SuppressWarnings("unchecked") + static Stream getTargets(Class type, TargetPredicate predicate, LivingEntity subject, Box searchArea) { + if (type == PlayerEntity.class || type == ServerPlayerEntity.class) { + return (Stream)subject.getWorld().getPlayers(predicate, subject, searchArea).stream(); + } + return subject.getWorld().getTargets(type, predicate, subject, searchArea).stream(); + } + + static Comparator 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()); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java new file mode 100644 index 00000000..62d7936d --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinAbstractSkeletonEntity.java @@ -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; + } +} diff --git a/src/main/resources/unicopia.mixin.json b/src/main/resources/unicopia.mixin.json index ba92c81c..f09a4e9c 100644 --- a/src/main/resources/unicopia.mixin.json +++ b/src/main/resources/unicopia.mixin.json @@ -7,6 +7,7 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "MixinAbstractDecorationEntity", + "MixinAbstractSkeletonEntity", "MixinBlazeEntity", "MixinBlock", "MixinBlockEntity",