Fixed shields being offset and fixed shields applying to entities that they shouldn't

This commit is contained in:
Sollace 2021-01-29 18:37:41 +02:00
parent 543fd7aee0
commit b43ed1975b
13 changed files with 70 additions and 29 deletions

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.ability.magic; package com.minelittlepony.unicopia.ability.magic;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -107,7 +108,11 @@ public interface Caster<E extends LivingEntity> extends Owned<E>, Levelled, Affi
return CasterUtils.findInRange(this, radius); return CasterUtils.findInRange(this, radius);
} }
default Stream<Entity> findAllEntitiesInRange(double radius, @Nullable Predicate<Entity> test) {
return VecHelper.findInRange(getEntity(), getWorld(), getOriginVector(), radius, test).stream();
}
default Stream<Entity> findAllEntitiesInRange(double radius) { default Stream<Entity> findAllEntitiesInRange(double radius) {
return VecHelper.findInRange(getEntity(), getWorld(), getOrigin(), radius, null).stream(); return findAllEntitiesInRange(radius, null);
} }
} }

View file

@ -7,8 +7,6 @@ import javax.annotation.Nullable;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.entity.PonyContainer; import com.minelittlepony.unicopia.entity.PonyContainer;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@ -17,8 +15,7 @@ public class CasterUtils {
* Finds all surrounding spells within range from the given caster. * Finds all surrounding spells within range from the given caster.
*/ */
static Stream<Caster<?>> findInRange(Caster<?> source, double radius) { static Stream<Caster<?>> findInRange(Caster<?> source, double radius) {
return VecHelper.findInRange(source.getEntity(), source.getWorld(), source.getOrigin(), radius, EquinePredicates.IS_CASTER) return source.findAllEntitiesInRange(radius, EquinePredicates.IS_CASTER)
.stream()
.map(e -> toCaster(e).filter(o -> o != source)) .map(e -> toCaster(e).filter(o -> o != source))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get); .map(Optional::get);

View file

@ -60,7 +60,7 @@ public class AttractiveSpell extends ShieldSpell implements Thrown {
protected List<Entity> getTargets(Caster<?> source, double radius) { protected List<Entity> getTargets(Caster<?> source, double radius) {
if (homingPos != null) { if (homingPos != null) {
return VecHelper.findInRange(source.getEntity(), source.getWorld(), source.getOrigin(), radius, i -> i instanceof ItemEntity); return VecHelper.findInRange(source.getEntity(), source.getWorld(), source.getOriginVector(), radius, i -> i instanceof ItemEntity);
} }
return super.getTargets(source, radius); return super.getTargets(source, radius);

View file

@ -66,7 +66,7 @@ public class FireSpell extends AbstractRangedAreaSpell implements Thrown {
return PosHelper.getAllInRegionMutable(source.getOrigin(), EFFECT_RANGE).reduce(false, return PosHelper.getAllInRegionMutable(source.getOrigin(), EFFECT_RANGE).reduce(false,
(r, i) -> applyBlocks(source.getWorld(), i), (r, i) -> applyBlocks(source.getWorld(), i),
(a, b) -> a || b) (a, b) -> a || b)
|| applyEntities(null, source.getWorld(), source.getOrigin()); || applyEntities(null, source.getWorld(), source.getOriginVector());
} }
@Override @Override
@ -130,7 +130,7 @@ public class FireSpell extends AbstractRangedAreaSpell implements Thrown {
return false; return false;
} }
protected boolean applyEntities(Entity owner, World world, BlockPos pos) { protected boolean applyEntities(Entity owner, World world, Vec3d pos) {
return !VecHelper.findInRange(owner, world, pos, 3, i -> applyEntitySingle(owner, world, i)).isEmpty(); return !VecHelper.findInRange(owner, world, pos, 3, i -> applyEntitySingle(owner, world, i)).isEmpty();
} }

View file

@ -21,6 +21,7 @@ import net.minecraft.entity.TntEntity;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.tag.BlockTags; import net.minecraft.tag.BlockTags;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public class IceSpell extends AbstractRangedAreaSpell implements Thrown { public class IceSpell extends AbstractRangedAreaSpell implements Thrown {
@ -50,14 +51,14 @@ public class IceSpell extends AbstractRangedAreaSpell implements Thrown {
PosHelper.getAllInRegionMutable(source.getOrigin(), effect_range) PosHelper.getAllInRegionMutable(source.getOrigin(), effect_range)
.forEach(i -> applyBlockSingle(owner, source.getWorld(), i)); .forEach(i -> applyBlockSingle(owner, source.getWorld(), i));
return applyEntities(source.getMaster(), source.getWorld(), source.getOrigin()); return applyEntities(source.getMaster(), source.getWorld(), source.getOriginVector());
} }
@Override @Override
public void render(Caster<?> source) { public void render(Caster<?> source) {
} }
protected boolean applyEntities(LivingEntity owner, World world, BlockPos pos) { protected boolean applyEntities(LivingEntity owner, World world, Vec3d pos) {
return !VecHelper.findInRange(owner, world, pos, 3, i -> applyEntitySingle(owner, i)).isEmpty(); return !VecHelper.findInRange(owner, world, pos, 3, i -> applyEntitySingle(owner, i)).isEmpty();
} }

View file

@ -57,10 +57,10 @@ public class InfernoSpell extends FireSpell {
shape = new Sphere(false, radius - 1); shape = new Sphere(false, radius - 1);
for (int i = 0; i < radius * 2; i++) { for (int i = 0; i < radius * 2; i++) {
if (w.random.nextInt(12) == 0) { if (w.random.nextInt(12) == 0) {
BlockPos pos = new BlockPos(shape.computePoint(w.random).add(origin)); Vec3d vec = shape.computePoint(w.random).add(origin);
if (!applyBlocks(w, pos)) { if (!applyBlocks(w, new BlockPos(vec))) {
applyEntities(source.getMaster(), w, pos); applyEntities(source.getMaster(), w, vec);
} }
} }
} }

View file

@ -5,7 +5,6 @@ import java.util.List;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.minelittlepony.unicopia.Affinity; import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.util.VecHelper;
import com.minelittlepony.unicopia.util.WorldEvent; import com.minelittlepony.unicopia.util.WorldEvent;
import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Shape;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
@ -62,7 +61,7 @@ public class NecromancySpell extends AbstractRangedAreaSpell {
Vec3d origin = source.getOriginVector(); Vec3d origin = source.getOriginVector();
if (VecHelper.findInRange(source.getEntity(), source.getWorld(), source.getOrigin(), radius * 4, e -> e instanceof ZombieEntity).size() >= 10 * (1 + additional)) { if (source.findAllEntitiesInRange(radius * 4, e -> e instanceof ZombieEntity).count() >= 10 * (1 + additional)) {
return true; return true;
} }

View file

@ -16,9 +16,14 @@ import com.minelittlepony.unicopia.projectile.ProjectileUtil;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.EyeOfEnderEntity;
import net.minecraft.entity.FallingBlockEntity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.TntEntity;
import net.minecraft.entity.decoration.ArmorStandEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -100,7 +105,19 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached {
boolean ownerIsValid = source.getAffinity() != Affinity.BAD && EquinePredicates.PLAYER_UNICORN.test(owner); boolean ownerIsValid = source.getAffinity() != Affinity.BAD && EquinePredicates.PLAYER_UNICORN.test(owner);
return source.findAllEntitiesInRange(radius) return source.findAllEntitiesInRange(radius)
.filter(entity -> !(entity instanceof ItemEntity || (ownerIsValid && Pony.equal(entity, owner)))) .filter(entity -> {
return
(entity instanceof LivingEntity
|| entity instanceof TntEntity
|| entity instanceof FallingBlockEntity
|| entity instanceof EyeOfEnderEntity
|| entity instanceof BoatEntity
|| ProjectileUtil.isFlyingProjectile(entity)
|| entity instanceof AbstractMinecartEntity)
&& !(entity instanceof ArmorStandEntity)
&& !(owner.isConnectedThroughVehicle(entity))
&& !(ownerIsValid && Pony.equal(entity, owner));
})
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@ -126,7 +143,7 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached {
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) { protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
Vec3d pos = source.getOriginVector(); Vec3d pos = source.getOriginVector();
if (ProjectileUtil.isProjectile(target)) { if (ProjectileUtil.isFlyingProjectile(target)) {
if (!ProjectileUtil.isProjectileThrownBy(target, source.getMaster())) { if (!ProjectileUtil.isProjectileThrownBy(target, source.getMaster())) {
if (distance < 1) { if (distance < 1) {
target.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1F, 1); target.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1F, 1);

View file

@ -196,7 +196,7 @@ public class Disguise implements NbtSerialisable {
|| entity instanceof VexEntity || entity instanceof VexEntity
|| entity instanceof ShulkerBulletEntity || entity instanceof ShulkerBulletEntity
|| entity instanceof Flutterer || entity instanceof Flutterer
|| ProjectileUtil.isProjectile(entity)) { || ProjectileUtil.isFlyingProjectile(entity)) {
return FlightType.INSECTOID; return FlightType.INSECTOID;
} }

View file

@ -0,0 +1,12 @@
package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.entity.projectile.PersistentProjectileEntity;
@Mixin(PersistentProjectileEntity.class)
public interface MixinPersistentProjectileEntity {
@Accessor("inGround")
boolean isInGround();
}

View file

@ -2,23 +2,32 @@ package com.minelittlepony.unicopia.projectile;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.unicopia.mixin.MixinPersistentProjectileEntity;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
public class ProjectileUtil { public interface ProjectileUtil {
/** /**
* Checks if the given entity is a projectile. * Checks if the given entity is a projectile.
*/ */
public static boolean isProjectile(Entity e) { static boolean isProjectile(Entity e) {
return e instanceof ProjectileEntity; return e instanceof ProjectileEntity;
} }
/**
* Checks if the given entity is a projectile that is not stuck in the ground.
*/
static boolean isFlyingProjectile(Entity e) {
return isProjectile(e) && !(e instanceof MixinPersistentProjectileEntity && ((MixinPersistentProjectileEntity)e).isInGround());
}
/** /**
* Checks if the given projectile was thrown by the given entity * Checks if the given projectile was thrown by the given entity
*/ */
public static <T extends Entity> boolean isProjectileThrownBy(Entity throwable, @Nullable T e) { static <T extends Entity> boolean isProjectileThrownBy(Entity throwable, @Nullable T e) {
return e != null && isProjectile(throwable) && e.equals(((ProjectileEntity) throwable).getOwner()); return e != null && isProjectile(throwable) && e.equals(((ProjectileEntity) throwable).getOwner());
} }
@ -31,7 +40,7 @@ public class ProjectileUtil {
* @param inaccuracy Inaccuracy * @param inaccuracy Inaccuracy
* @return True the projectile's heading was set, false otherwise * @return True the projectile's heading was set, false otherwise
*/ */
public static void setThrowableHeading(Entity throwable, Vec3d heading, float velocity, float inaccuracy) { static void setThrowableHeading(Entity throwable, Vec3d heading, float velocity, float inaccuracy) {
if (throwable instanceof ProjectileEntity) { if (throwable instanceof ProjectileEntity) {
((ProjectileEntity)throwable).setVelocity(heading.x, heading.y, heading.z, velocity, inaccuracy); ((ProjectileEntity)throwable).setVelocity(heading.x, heading.y, heading.z, velocity, inaccuracy);

View file

@ -6,25 +6,25 @@ import javax.annotation.Nullable;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box; import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
public interface VecHelper { public interface VecHelper {
static Predicate<Entity> inRange(BlockPos center, double range) { static Predicate<Entity> inRange(Vec3d center, double range) {
double rad = Math.pow(range, 2); double rad = Math.pow(range, 2);
return e -> { return e -> {
return e.squaredDistanceTo(center.getX(), center.getY(), center.getZ()) <= rad return e.squaredDistanceTo(center) <= rad
|| e.squaredDistanceTo(center.getX(), center.getY() - e.getStandingEyeHeight(), center.getZ()) <= rad; || e.squaredDistanceTo(center.getX(), center.getY() - e.getStandingEyeHeight(), center.getZ()) <= rad;
}; };
} }
static List<Entity> findInRange(@Nullable Entity origin, World w, BlockPos pos, double radius, @Nullable Predicate<Entity> predicate) { static List<Entity> findInRange(@Nullable Entity origin, World w, Vec3d pos, double radius, @Nullable Predicate<Entity> predicate) {
return w.getOtherEntities(origin, new Box(pos).expand(radius), predicate == null ? inRange(pos, radius) : inRange(pos, radius).and(predicate)); return w.getOtherEntities(origin, Box.method_29968(pos).expand(radius), predicate == null ? inRange(pos, radius) : inRange(pos, radius).and(predicate));
} }
/** /**
* Gets all entities within a given range from the player. * Gets all entities within a given range from the player.
*/ */

View file

@ -13,6 +13,7 @@
"MixinItems", "MixinItems",
"MixinLivingEntity", "MixinLivingEntity",
"MixinMilkBucketItem", "MixinMilkBucketItem",
"MixinPersistentProjectileEntity",
"MixinPlayerEntity", "MixinPlayerEntity",
"MixinProjectileEntity", "MixinProjectileEntity",
"MixinServerPlayerEntity", "MixinServerPlayerEntity",