baritone/ui/LookManager.java
2018-08-01 11:34:35 -04:00

346 lines
15 KiB
Java

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package baritone.ui;
import java.util.ArrayList;
import java.util.Random;
import baritone.pathfinding.goals.GoalXZ;
import baritone.util.Manager;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFire;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
/**
*
* @author leijurv
*/
public class LookManager extends Manager {
public static boolean randomLooking = true;
static final float MAX_YAW_CHANGE_PER_TICK = 360 / 20;
static final float MAX_PITCH_CHANGE_PER_TICK = 360 / 20;
static float previousYaw = 0;
static float previousPitch = 0;
/**
* Something with smoothing between ticks
*/
static float desiredNextYaw = 0;
static float desiredNextPitch = 0;
/**
* The desired yaw, as set by whatever action is happening. Remember to also
* set lookingYaw to true if you really want the yaw to change
*
*/
static float desiredYaw;
/**
* The desired pitch, as set by whatever action is happening. Remember to
* also set lookingPitch to true if you really want the yaw to change
*
*/
static float desiredPitch;
/**
* Set to true if the action wants the player's yaw to be moved towards
* desiredYaw
*/
static boolean lookingYaw = false;
/**
* Set to true if the action wants the player's pitch to be moved towards
* desiredPitch
*/
static boolean lookingPitch = false;
public static void frame(float partialTicks) {
//Out.log("Part: " + partialTicks);
if (Minecraft.getMinecraft() == null || Minecraft.getMinecraft().player == null) {
return;
}
if (lookingPitch) {
Minecraft.getMinecraft().player.rotationPitch = (desiredNextPitch - previousPitch) * partialTicks + previousPitch;
}
if (lookingYaw) {
Minecraft.getMinecraft().player.rotationYaw = (desiredNextYaw - previousYaw) * partialTicks + previousYaw;
}
}
/**
* Because I had to do it the janky way
*/
private static final double[][] BLOCK_SIDE_MULTIPLIERS = {{0, 0.5, 0.5}, {1, 0.5, 0.5}, {0.5, 0, 0.5}, {0.5, 1, 0.5}, {0.5, 0.5, 0}, {0.5, 0.5, 1}};
/**
* Called by our code in order to look in the direction of the center of a
* block
*
* @param p the position to look at
* @param alsoDoPitch whether to set desired pitch or just yaw
* @return is the actual player yaw (and actual player pitch, if alsoDoPitch
* is true) within ANGLE_THRESHOLD (currently 7°) of looking straight at
* this block?
*/
public static boolean lookAtBlock(BlockPos p, boolean alsoDoPitch) {
if (couldIReachCenter(p)) {
return lookAtCenterOfBlock(p, alsoDoPitch);
}
Block b = Minecraft.getMinecraft().world.getBlockState(p).getBlock();
for (double[] mult : BLOCK_SIDE_MULTIPLIERS) {
double xDiff = b.getBlockBoundsMinX() * mult[0] + b.getBlockBoundsMaxX() * (1 - mult[0]);//lol
double yDiff = b.getBlockBoundsMinY() * mult[1] + b.getBlockBoundsMaxY() * (1 - mult[1]);
double zDiff = b.getBlockBoundsMinZ() * mult[2] + b.getBlockBoundsMaxZ() * (1 - mult[2]);
double x = p.getX() + xDiff;
double y = p.getY() + yDiff;
double z = p.getZ() + zDiff;
if (couldIReachByLookingAt(p, x, y, z)) {
return lookAtCoords(x, y, z, alsoDoPitch);
}
}
return lookAtCenterOfBlock(p, alsoDoPitch);
}
public static boolean lookAtCenterOfBlock(BlockPos p, boolean alsoDoPitch) {
Block b = Minecraft.getMinecraft().world.getBlockState(p).getBlock();
double xDiff = (b.getBlockBoundsMinX() + b.getBlockBoundsMaxX()) / 2;
double yDiff = (b.getBlockBoundsMinY() + b.getBlockBoundsMaxY()) / 2;
double zDiff = (b.getBlockBoundsMinZ() + b.getBlockBoundsMaxZ()) / 2;
if (b instanceof BlockFire) {//look at bottom of fire when putting it out
yDiff = 0;
}
double x = p.getX() + xDiff;
double y = p.getY() + yDiff;
double z = p.getZ() + zDiff;
return lookAtCoords(x, y, z, alsoDoPitch);
}
/**
* The threshold for how close it tries to get to looking straight at things
*/
public static final float ANGLE_THRESHOLD = 7;
public static boolean couldIReach(BlockPos pos) {
if (couldIReachCenter(pos)) {
return true;
}
Block b = Minecraft.getMinecraft().world.getBlockState(pos).getBlock();
for (double[] mult : BLOCK_SIDE_MULTIPLIERS) {
double xDiff = b.getBlockBoundsMinX() * mult[0] + b.getBlockBoundsMaxX() * (1 - mult[0]);
double yDiff = b.getBlockBoundsMinY() * mult[1] + b.getBlockBoundsMaxY() * (1 - mult[1]);
double zDiff = b.getBlockBoundsMinZ() * mult[2] + b.getBlockBoundsMaxZ() * (1 - mult[2]);
double x = pos.getX() + xDiff;
double y = pos.getY() + yDiff;
double z = pos.getZ() + zDiff;
if (couldIReachByLookingAt(pos, x, y, z)) {
return true;
}
}
return false;
}
public static boolean couldIReachCenter(BlockPos pos) {
float[] pitchAndYaw = pitchAndYawToCenter(pos);
MovingObjectPosition blah = raytraceTowards(pitchAndYaw);
return blah != null && blah.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK && blah.getBlockPos().equals(pos);
}
public static boolean couldIReach(BlockPos pos, EnumFacing dir) {
BlockPos side = pos.offset(dir);
double faceX = (pos.getX() + side.getX() + 1.0D) * 0.5D;
double faceY = (pos.getY() + side.getY()) * 0.5D;
double faceZ = (pos.getZ() + side.getZ() + 1.0D) * 0.5D;
MovingObjectPosition blah = raytraceTowards(faceX, faceY, faceZ);
return blah != null && blah.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK && blah.getBlockPos().equals(pos) && blah.sideHit == dir;
}
public static MovingObjectPosition raytraceTowards(double x, double y, double z) {
return raytraceTowards(pitchAndYaw(x, y, z));
}
public static MovingObjectPosition raytraceTowards(float[] pitchAndYaw) {
float yaw = pitchAndYaw[0];
float pitch = pitchAndYaw[1];
double blockReachDistance = (double) Minecraft.getMinecraft().playerController.getBlockReachDistance();
Vec3 vec3 = Minecraft.getMinecraft().player.getPositionEyes(1.0F);
Vec3 vec31 = getVectorForRotation(pitch, yaw);
Vec3 vec32 = vec3.addVector(vec31.xCoord * blockReachDistance, vec31.yCoord * blockReachDistance, vec31.zCoord * blockReachDistance);
MovingObjectPosition blah = Minecraft.getMinecraft().world.rayTraceBlocks(vec3, vec32, false, false, true);
return blah;
}
public static boolean couldIReachByLookingAt(BlockPos pos, double x, double y, double z) {
MovingObjectPosition blah = raytraceTowards(x, y, z);
return blah != null && blah.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK && blah.getBlockPos().equals(pos);
}
public static Vec3 getVectorForRotation(float pitch, float yaw) {//shamelessly copied from Entity.java
float f = MathHelper.cos(-yaw * 0.017453292F - (float) Math.PI);
float f1 = MathHelper.sin(-yaw * 0.017453292F - (float) Math.PI);
float f2 = -MathHelper.cos(-pitch * 0.017453292F);
float f3 = MathHelper.sin(-pitch * 0.017453292F);
return new Vec3((double) (f1 * f2), (double) f3, (double) (f * f2));
}
public static GoalXZ fromAngleAndDirection(double distance) {
double theta = ((double) Minecraft.getMinecraft().player.rotationYaw) * Math.PI / 180D;
double x = Minecraft.getMinecraft().player.posX - Math.sin(theta) * distance;
double z = Minecraft.getMinecraft().player.posZ + Math.cos(theta) * distance;
return new GoalXZ((int) x, (int) z);
}
public static boolean lookingYaw() {
return lookingYaw;
}
static double SPEED = 1000;
/**
* Smoothly moves between random pitches and yaws every second
*
* @return
*/
public static float[] getRandom() {
long now = (long) Math.ceil(((double) System.currentTimeMillis()) / SPEED);
now *= SPEED;
long prev = now - (long) SPEED;
float frac = (System.currentTimeMillis() - prev) / ((float) SPEED);//fraction between previous second and next
Random prevR = new Random(prev);//fite me
Random nowR = new Random(now);
float prevFirst = prevR.nextFloat() * 10 - 5;
float prevSecond = prevR.nextFloat() * 10 - 5;
float nowFirst = nowR.nextFloat() * 10 - 5;
float nowSecond = nowR.nextFloat() * 10 - 5;
float first = prevFirst + frac * (nowFirst - prevFirst);//smooth between previous and next second
float second = prevSecond + frac * (nowSecond - prevSecond);
return new float[]{first, second};
}
public static float[] pitchAndYawToCenter(BlockPos p) {
Block b = Minecraft.getMinecraft().world.getBlockState(p).getBlock();
double xDiff = (b.getBlockBoundsMinX() + b.getBlockBoundsMaxX()) / 2;
double yolo = (b.getBlockBoundsMinY() + b.getBlockBoundsMaxY()) / 2;
double zDiff = (b.getBlockBoundsMinZ() + b.getBlockBoundsMaxZ()) / 2;
if (b instanceof BlockFire) {//look at bottom of fire when putting it out
yolo = 0;
}
double x = p.getX() + xDiff;
double y = p.getY() + yolo;
double z = p.getZ() + zDiff;
return pitchAndYaw(x, y, z);
}
public static float[] pitchAndYaw(double x, double y, double z) {
EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
double yDiff = (thePlayer.posY + 1.62) - y;//lol
double yaw = Math.atan2(thePlayer.posX - x, -thePlayer.posZ + z);
double dist = Math.sqrt((thePlayer.posX - x) * (thePlayer.posX - x) + (-thePlayer.posZ + z) * (-thePlayer.posZ + z));
double pitch = Math.atan2(yDiff, dist);
return new float[]{(float) (yaw * 180 / Math.PI), (float) (pitch * 180 / Math.PI)};
}
static ArrayList<Exception> sketchiness = new ArrayList<>();
public static void setDesiredYaw(float y) {
sketchiness.add(new Exception("Desired yaw already set!"));
if (lookingYaw) {
/*for (Exception ex : sketchiness) {
Logger.getLogger(LookManager.class.getName()).log(Level.SEVERE, null, ex);//print out everyone who has tried to set the desired yaw this tick to show the conflict
}*/
sketchiness.clear();
return;
}
desiredYaw = y;
lookingYaw = true;
}
/**
* Look at coordinates
*
* @param x
* @param y
* @param z
* @param alsoDoPitch also adjust the pitch? if false, y is ignored
* @return is the actual player yaw (and actual player pitch, if alsoDoPitch
* is true) within ANGLE_THRESHOLD (currently 7°) of looking straight at
* these coordinates?
*/
public static boolean lookAtCoords(double x, double y, double z, boolean alsoDoPitch) {
EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
double yDiff = (thePlayer.posY + 1.62) - y;
double yaw = Math.atan2(thePlayer.posX - x, -thePlayer.posZ + z);
double dist = Math.sqrt((thePlayer.posX - x) * (thePlayer.posX - x) + (-thePlayer.posZ + z) * (-thePlayer.posZ + z));
double pitch = Math.atan2(yDiff, dist);
setDesiredYaw((float) (yaw * 180 / Math.PI));
float yawDist = Math.abs(desiredYaw - thePlayer.rotationYaw);
boolean withinRange = yawDist < ANGLE_THRESHOLD || yawDist > 360 - ANGLE_THRESHOLD;
if (alsoDoPitch) {
lookingPitch = true;
desiredPitch = (float) (pitch * 180 / Math.PI);
float pitchDist = Math.abs(desiredPitch - thePlayer.rotationPitch);
withinRange = withinRange && (pitchDist < ANGLE_THRESHOLD || pitchDist > 360 - ANGLE_THRESHOLD);
}
return withinRange;
}
@Override
public void onTickPre() {
if (lookingYaw) {
Minecraft.getMinecraft().player.rotationYaw = desiredNextYaw;
}
if (lookingPitch) {
Minecraft.getMinecraft().player.rotationPitch = desiredNextPitch;
}
lookingYaw = false;
sketchiness.clear();
lookingPitch = false;
}
public static void nudgeToLevel() {
EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
if (!lookingPitch) {
if (thePlayer.rotationPitch < -20) {
thePlayer.rotationPitch++;
} else if (thePlayer.rotationPitch > 20) {
thePlayer.rotationPitch--;
}
}
}
@Override
public void onTickPost() {
if (randomLooking) {
desiredYaw += getRandom()[0];
desiredPitch += getRandom()[1];
}
if (desiredPitch > 90) {
desiredPitch = 90;
}
if (desiredPitch < -90) {
desiredPitch = -90;
}
if (lookingYaw) {
previousYaw = Minecraft.getMinecraft().player.rotationYaw;
desiredYaw += 360;
desiredYaw %= 360;
float yawDistance = Minecraft.getMinecraft().player.rotationYaw - desiredYaw;
if (yawDistance > 180) {
yawDistance -= 360;
} else if (yawDistance < -180) {
yawDistance += 360;
}
if (Math.abs(yawDistance) > MAX_YAW_CHANGE_PER_TICK) {
yawDistance = Math.signum(yawDistance) * MAX_YAW_CHANGE_PER_TICK;
}
desiredNextYaw = Minecraft.getMinecraft().player.rotationYaw - yawDistance;
}
if (lookingPitch) {
previousPitch = Minecraft.getMinecraft().player.rotationPitch;
desiredPitch += 360;
desiredPitch %= 360;
float pitchDistance = Minecraft.getMinecraft().player.rotationPitch - desiredPitch;
if (pitchDistance > 180) {
pitchDistance -= 360;
} else if (pitchDistance < -180) {
pitchDistance += 360;
}
if (Math.abs(pitchDistance) > MAX_PITCH_CHANGE_PER_TICK) {
pitchDistance = Math.signum(pitchDistance) * MAX_PITCH_CHANGE_PER_TICK;
}
desiredNextPitch = Minecraft.getMinecraft().player.rotationPitch - pitchDistance;
}
}
@Override
protected void onTick() {
}
@Override
protected void onCancel() {
}
@Override
protected void onStart() {
}
@Override
protected boolean onEnabled(boolean enabled) {
return true;
}
}