001/*
002 * This file is part of Baritone.
003 *
004 * Baritone is free software: you can redistribute it and/or modify
005 * it under the terms of the GNU Lesser General Public License as published by
006 * the Free Software Foundation, either version 3 of the License, or
007 * (at your option) any later version.
008 *
009 * Baritone is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License
015 * along with Baritone.  If not, see <https://www.gnu.org/licenses/>.
016 */
017
018package baritone.api.pathing.goals;
019
020import baritone.api.BaritoneAPI;
021import baritone.api.utils.BetterBlockPos;
022import baritone.api.utils.SettingsUtil;
023import net.minecraft.util.math.MathHelper;
024import net.minecraft.util.math.Vec3d;
025
026/**
027 * Useful for long-range goals that don't have a specific Y level.
028 *
029 * @author leijurv
030 */
031public class GoalXZ implements Goal {
032
033    private static final double SQRT_2 = Math.sqrt(2);
034
035    /**
036     * The X block position of this goal
037     */
038    private final int x;
039
040    /**
041     * The Z block position of this goal
042     */
043    private final int z;
044
045    public GoalXZ(int x, int z) {
046        this.x = x;
047        this.z = z;
048    }
049
050    public GoalXZ(BetterBlockPos pos) {
051        this.x = pos.x;
052        this.z = pos.z;
053    }
054
055    @Override
056    public boolean isInGoal(int x, int y, int z) {
057        return x == this.x && z == this.z;
058    }
059
060    @Override
061    public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock
062        int xDiff = x - this.x;
063        int zDiff = z - this.z;
064        return calculate(xDiff, zDiff);
065    }
066
067    @Override
068    public String toString() {
069        return String.format(
070                "GoalXZ{x=%s,z=%s}",
071                SettingsUtil.maybeCensor(x),
072                SettingsUtil.maybeCensor(z)
073        );
074    }
075
076    public static double calculate(double xDiff, double zDiff) {
077        //This is a combination of pythagorean and manhattan distance
078        //It takes into account the fact that pathing can either walk diagonally or forwards
079
080        //It's not possible to walk forward 1 and right 2 in sqrt(5) time
081        //It's really 1+sqrt(2) because it'll walk forward 1 then diagonally 1
082        double x = Math.abs(xDiff);
083        double z = Math.abs(zDiff);
084        double straight;
085        double diagonal;
086        if (x < z) {
087            straight = z - x;
088            diagonal = x;
089        } else {
090            straight = x - z;
091            diagonal = z;
092        }
093        diagonal *= SQRT_2;
094        return (diagonal + straight) * BaritoneAPI.getSettings().costHeuristic.value; // big TODO tune
095    }
096
097    public static GoalXZ fromDirection(Vec3d origin, float yaw, double distance) {
098        float theta = (float) Math.toRadians(yaw);
099        double x = origin.x - MathHelper.sin(theta) * distance;
100        double z = origin.z + MathHelper.cos(theta) * distance;
101        return new GoalXZ(MathHelper.floor(x), MathHelper.floor(z));
102    }
103
104    public int getX() {
105        return x;
106    }
107
108    public int getZ() {
109        return z;
110    }
111}