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.utils.SettingsUtil; 021import it.unimi.dsi.fastutil.doubles.DoubleIterator; 022import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet; 023import net.minecraft.core.BlockPos; 024 025import java.util.Arrays; 026import java.util.Objects; 027 028/** 029 * Useful for automated combat (retreating specifically) 030 * 031 * @author leijurv 032 */ 033public class GoalRunAway implements Goal { 034 035 private final BlockPos[] from; 036 037 private final int distanceSq; 038 039 private final Integer maintainY; 040 041 public GoalRunAway(double distance, BlockPos... from) { 042 this(distance, null, from); 043 } 044 045 public GoalRunAway(double distance, Integer maintainY, BlockPos... from) { 046 if (from.length == 0) { 047 throw new IllegalArgumentException("Positions to run away from must not be empty"); 048 } 049 this.from = from; 050 this.distanceSq = (int) (distance * distance); 051 this.maintainY = maintainY; 052 } 053 054 @Override 055 public boolean isInGoal(int x, int y, int z) { 056 if (maintainY != null && maintainY != y) { 057 return false; 058 } 059 for (BlockPos p : from) { 060 int diffX = x - p.getX(); 061 int diffZ = z - p.getZ(); 062 int distSq = diffX * diffX + diffZ * diffZ; 063 if (distSq < distanceSq) { 064 return false; 065 } 066 } 067 return true; 068 } 069 070 @Override 071 public double heuristic(int x, int y, int z) {// mostly copied from GoalBlock 072 double min = Double.MAX_VALUE; 073 for (BlockPos p : from) { 074 double h = GoalXZ.calculate(p.getX() - x, p.getZ() - z); 075 if (h < min) { 076 min = h; 077 } 078 } 079 min = -min; 080 if (maintainY != null) { 081 min = min * 0.6 + GoalYLevel.calculate(maintainY, y) * 1.5; 082 } 083 return min; 084 } 085 086 @Override 087 public double heuristic() {// TODO less hacky solution 088 int distance = (int) Math.ceil(Math.sqrt(distanceSq)); 089 int minX = Integer.MAX_VALUE; 090 int minY = Integer.MAX_VALUE; 091 int minZ = Integer.MAX_VALUE; 092 int maxX = Integer.MIN_VALUE; 093 int maxY = Integer.MIN_VALUE; 094 int maxZ = Integer.MIN_VALUE; 095 for (BlockPos p : from) { 096 minX = Math.min(minX, p.getX() - distance); 097 minY = Math.min(minY, p.getY() - distance); 098 minZ = Math.min(minZ, p.getZ() - distance); 099 maxX = Math.max(minX, p.getX() + distance); 100 maxY = Math.max(minY, p.getY() + distance); 101 maxZ = Math.max(minZ, p.getZ() + distance); 102 } 103 DoubleOpenHashSet maybeAlwaysInside = new DoubleOpenHashSet(); // see pull request #1978 104 double minOutside = Double.POSITIVE_INFINITY; 105 for (int x = minX; x <= maxX; x++) { 106 for (int y = minY; y <= maxY; y++) { 107 for (int z = minZ; z <= maxZ; z++) { 108 double h = heuristic(x, y, z); 109 if (h < minOutside && isInGoal(x, y, z)) { 110 maybeAlwaysInside.add(h); 111 } else { 112 minOutside = Math.min(minOutside, h); 113 } 114 } 115 } 116 } 117 double maxInside = Double.NEGATIVE_INFINITY; 118 DoubleIterator it = maybeAlwaysInside.iterator(); 119 while (it.hasNext()) { 120 double inside = it.nextDouble(); 121 if (inside < minOutside) { 122 maxInside = Math.max(maxInside, inside); 123 } 124 } 125 return maxInside; 126 } 127 128 @Override 129 public boolean equals(Object o) { 130 if (this == o) { 131 return true; 132 } 133 if (o == null || getClass() != o.getClass()) { 134 return false; 135 } 136 137 GoalRunAway goal = (GoalRunAway) o; 138 return distanceSq == goal.distanceSq 139 && Arrays.equals(from, goal.from) 140 && Objects.equals(maintainY, goal.maintainY); 141 } 142 143 @Override 144 public int hashCode() { 145 int hash = Arrays.hashCode(from); 146 hash = hash * 1196803141 + distanceSq; 147 hash = hash * -2053788840 + maintainY; 148 return hash; 149 } 150 151 @Override 152 public String toString() { 153 if (maintainY != null) { 154 return String.format( 155 "GoalRunAwayFromMaintainY y=%s, %s", 156 SettingsUtil.maybeCensor(maintainY), 157 Arrays.asList(from) 158 ); 159 } else { 160 return "GoalRunAwayFrom" + Arrays.asList(from); 161 } 162 } 163}