package mhfc.net.common.ai.general.provider.simple; import java.security.InvalidParameterException; import java.util.Objects; import mhfc.net.common.util.world.WorldHelper; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.Vec3; public interface IJumpParamterProvider<EntityT extends EntityLivingBase> { public default Vec3 getJumpVector(EntityT entity) { Vec3 lookVector = entity.getLookVec(); return Vec3.createVectorHelper(lookVector.xCoord, 0, lookVector.zCoord); } /** * Gets the speed upwards which the entity should have when jumping. */ public float getInitialUpVelocity(EntityT entity); /** * Gets the forward speed that the entity should have when jumping. */ public float getForwardVelocity(EntityT entity); /** * Tries to jump as exactly as possible onto the target coordinate * * @author Katora * * @param <EntityT> */ public static class ConstantAirTimeAdapter<EntityT extends EntityLiving> implements IJumpParamterProvider<EntityT> { public static interface ITargetResolver<EntityT extends EntityLiving> { Vec3 getJumpTarget(EntityT entity); } public static final float GRAVITATIONAL_C_LIVING = 0.08f; // blocks per // tick^2 protected float airTime; private float maxSpeed, minSpeed; private ITargetResolver<EntityT> targetResolver; public ConstantAirTimeAdapter(float jumpAirTimeInTicks, ITargetResolver<EntityT> targetResolver) { if (jumpAirTimeInTicks <= 0) throw new InvalidParameterException("Jump time must be bigger than zero"); this.airTime = jumpAirTimeInTicks; this.targetResolver = Objects.requireNonNull(targetResolver); this.maxSpeed = 100; this.minSpeed = 0; } @Override public float getInitialUpVelocity(EntityT entity) { Vec3 target = Objects.requireNonNull(targetResolver.getJumpTarget(entity)); float velocity = (float) (target.yCoord - entity.posY) / airTime + GRAVITATIONAL_C_LIVING * airTime / 2; return velocity; } @Override public float getForwardVelocity(EntityT entity) { Vec3 target = Objects.requireNonNull(targetResolver.getJumpTarget(entity)); Vec3 position = WorldHelper.getEntityPositionVector(entity); float distance = (float) position.distanceTo(target); // CLEANUP why does a multiplication with 3 work so well here?? // It should be v = s/t just straight up, not v = s/t*3..... float velocity = distance / airTime * 2.8f * // Correct minecraft slowdown (airTime * 0.02f) / (1 - (float) Math.pow(0.98, airTime)); return Math.min(Math.max(velocity, minSpeed), maxSpeed); } public void setSpeedInterval(float newMinSpeed, float newMaxSpeed) { if (newMaxSpeed < newMinSpeed) throw new InvalidParameterException("Min speed can not be bigger than max speed"); this.minSpeed = newMinSpeed; this.maxSpeed = newMaxSpeed; } } public static class AttackPointAdapter<EntityT extends EntityLiving> extends ConstantAirTimeAdapter<EntityT> { private static class ConstPointResolver<EntityT extends EntityLiving> implements ITargetResolver<EntityT> { private Vec3 targetPoint; public ConstPointResolver(Vec3 target) { this.targetPoint = target; } @Override public Vec3 getJumpTarget(EntityT entity) { return this.targetPoint; } } public AttackPointAdapter(float jumpTimeInTicks, Vec3 targetPoint) { super(jumpTimeInTicks, new ConstPointResolver<EntityT>(targetPoint)); } } /** * A class that implements the jump parameter aiming to provide a constant jump time when jumping towards the enemy * with enough speed to land directly at his position. */ public static class AttackTargetAdapter<EntityT extends EntityLiving> extends ConstantAirTimeAdapter<EntityT> { public AttackTargetAdapter(float jumpTimeInTicks) { super(jumpTimeInTicks, new ITargetResolver<EntityT>() { @Override public Vec3 getJumpTarget(EntityLiving entity) { EntityLivingBase attackTarget = entity.getAttackTarget(); Vec3 target; if (attackTarget != null) { target = WorldHelper.getEntityPositionVector(attackTarget); } else { target = WorldHelper.getEntityPositionVector(entity); } return target; } }); } } }