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.calc; 019 020import baritone.api.Settings; 021import baritone.api.pathing.goals.Goal; 022import baritone.api.pathing.movement.IMovement; 023import baritone.api.utils.BetterBlockPos; 024 025import java.util.HashSet; 026import java.util.List; 027 028/** 029 * @author leijurv, Brady 030 */ 031public interface IPath { 032 033 /** 034 * Ordered list of movements to carry out. 035 * movements.get(i).getSrc() should equal positions.get(i) 036 * movements.get(i).getDest() should equal positions.get(i+1) 037 * movements.size() should equal positions.size()-1 038 * 039 * @return All of the movements to carry out 040 */ 041 List<IMovement> movements(); 042 043 /** 044 * All positions along the way. 045 * Should begin with the same as getSrc and end with the same as getDest 046 * 047 * @return All of the positions along this path 048 */ 049 List<BetterBlockPos> positions(); 050 051 /** 052 * This path is actually going to be executed in the world. Do whatever additional processing is required. 053 * (as opposed to Path objects that are just constructed every frame for rendering) 054 * 055 * @return The result of path post processing 056 */ 057 default IPath postProcess() { 058 throw new UnsupportedOperationException(); 059 } 060 061 /** 062 * Returns the number of positions in this path. Equivalent to {@code positions().size()}. 063 * 064 * @return Number of positions in this path 065 */ 066 default int length() { 067 return positions().size(); 068 } 069 070 /** 071 * @return The goal that this path was calculated towards 072 */ 073 Goal getGoal(); 074 075 /** 076 * Returns the number of nodes that were considered during calculation before 077 * this path was found. 078 * 079 * @return The number of nodes that were considered before finding this path 080 */ 081 int getNumNodesConsidered(); 082 083 /** 084 * Returns the start position of this path. This is the first element in the 085 * {@link List} that is returned by {@link IPath#positions()}. 086 * 087 * @return The start position of this path 088 */ 089 default BetterBlockPos getSrc() { 090 return positions().get(0); 091 } 092 093 /** 094 * Returns the end position of this path. This is the last element in the 095 * {@link List} that is returned by {@link IPath#positions()}. 096 * 097 * @return The end position of this path. 098 */ 099 default BetterBlockPos getDest() { 100 List<BetterBlockPos> pos = positions(); 101 return pos.get(pos.size() - 1); 102 } 103 104 /** 105 * Returns the estimated number of ticks to complete the path from the given node index. 106 * 107 * @param pathPosition The index of the node we're calculating from 108 * @return The estimated number of ticks remaining frm the given position 109 */ 110 default double ticksRemainingFrom(int pathPosition) { 111 double sum = 0; 112 //this is fast because we aren't requesting recalculation, it's just cached 113 List<IMovement> movements = movements(); 114 for (int i = pathPosition; i < movements.size(); i++) { 115 sum += movements.get(i).getCost(); 116 } 117 return sum; 118 } 119 120 /** 121 * Cuts off this path at the loaded chunk border, and returns the resulting path. Default 122 * implementation just returns this path, without the intended functionality. 123 * <p> 124 * The argument is supposed to be a BlockStateInterface LOL LOL LOL LOL LOL 125 * 126 * @param bsi The block state lookup, highly cursed 127 * @return The result of this cut-off operation 128 */ 129 default IPath cutoffAtLoadedChunks(Object bsi) { 130 throw new UnsupportedOperationException(); 131 } 132 133 /** 134 * Cuts off this path using the min length and cutoff factor settings, and returns the resulting path. 135 * Default implementation just returns this path, without the intended functionality. 136 * 137 * @param destination The end goal of this path 138 * @return The result of this cut-off operation 139 * @see Settings#pathCutoffMinimumLength 140 * @see Settings#pathCutoffFactor 141 */ 142 default IPath staticCutoff(Goal destination) { 143 throw new UnsupportedOperationException(); 144 } 145 146 147 /** 148 * Performs a series of checks to ensure that the assembly of the path went as expected. 149 */ 150 default void sanityCheck() { 151 List<BetterBlockPos> path = positions(); 152 List<IMovement> movements = movements(); 153 if (!getSrc().equals(path.get(0))) { 154 throw new IllegalStateException("Start node does not equal first path element"); 155 } 156 if (!getDest().equals(path.get(path.size() - 1))) { 157 throw new IllegalStateException("End node does not equal last path element"); 158 } 159 if (path.size() != movements.size() + 1) { 160 throw new IllegalStateException("Size of path array is unexpected"); 161 } 162 HashSet<BetterBlockPos> seenSoFar = new HashSet<>(); 163 for (int i = 0; i < path.size() - 1; i++) { 164 BetterBlockPos src = path.get(i); 165 BetterBlockPos dest = path.get(i + 1); 166 IMovement movement = movements.get(i); 167 if (!src.equals(movement.getSrc())) { 168 throw new IllegalStateException("Path source is not equal to the movement source"); 169 } 170 if (!dest.equals(movement.getDest())) { 171 throw new IllegalStateException("Path destination is not equal to the movement destination"); 172 } 173 if (seenSoFar.contains(src)) { 174 throw new IllegalStateException("Path doubles back on itself, making a loop"); 175 } 176 seenSoFar.add(src); 177 } 178 } 179}