the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 290 lines 8.1 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.entity.h" 3#include "net.minecraft.world.level.h" 4#include "net.minecraft.world.level.material.h" 5#include "net.minecraft.world.level.tile.h" 6#include "net.minecraft.world.phys.h" 7#include "BinaryHeap.h" 8#include "Node.h" 9#include "Path.h" 10#include "PathFinder.h" 11 12PathFinder::PathFinder(LevelSource *level, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat) 13{ 14 neighbors = new NodeArray(32); 15 16 this->canPassDoors = canPassDoors; 17 this->canOpenDoors = canOpenDoors; 18 this->avoidWater = avoidWater; 19 this->canFloat = canFloat; 20 this->level = level; 21} 22 23PathFinder::~PathFinder() 24{ 25 // All the nodes should be uniquely referenced in the nodes map, and everything else should just be duplicate 26 // references to the same things, so just need to destroy their containers 27 delete [] neighbors->data; 28 delete neighbors; 29 AUTO_VAR(itEnd, nodes.end()); 30 for( AUTO_VAR(it, nodes.begin()); it != itEnd; it++ ) 31 { 32 delete it->second; 33 } 34} 35 36Path *PathFinder::findPath(Entity *from, Entity *to, float maxDist) 37{ 38 return findPath(from, to->x, to->bb->y0, to->z, maxDist); 39} 40 41Path *PathFinder::findPath(Entity *from, int x, int y, int z, float maxDist) 42{ 43 return findPath(from, x + 0.5f, y + 0.5f, z + 0.5f, maxDist); 44} 45 46Path *PathFinder::findPath(Entity *e, double xt, double yt, double zt, float maxDist) 47{ 48 openSet.clear(); 49 nodes.clear(); 50 51 bool resetAvoidWater = avoidWater; 52 int startY = Mth::floor(e->bb->y0 + 0.5f); 53 if (canFloat && e->isInWater()) 54 { 55 startY = (int) (e->bb->y0); 56 int tileId = level->getTile((int) Mth::floor(e->x), startY, (int) Mth::floor(e->z)); 57 while (tileId == Tile::water_Id || tileId == Tile::calmWater_Id) 58 { 59 ++startY; 60 tileId = level->getTile((int) Mth::floor(e->x), startY, (int) Mth::floor(e->z)); 61 } 62 resetAvoidWater = avoidWater; 63 avoidWater = false; 64 } else startY = Mth::floor(e->bb->y0 + 0.5f); 65 66 Node *from = getNode((int) floor(e->bb->x0), startY, (int) floor(e->bb->z0)); 67 Node *to = getNode((int) floor(xt - e->bbWidth / 2), (int) floor(yt), (int) floor(zt - e->bbWidth / 2)); 68 69 Node *size = new Node((int) floor(e->bbWidth + 1), (int) floor(e->bbHeight + 1), (int) floor(e->bbWidth + 1)); 70 Path *path = findPath(e, from, to, size, maxDist); 71 delete size; 72 73 avoidWater = resetAvoidWater; 74 return path; 75} 76 77// function A*(start,goal) 78Path *PathFinder::findPath(Entity *e, Node *from, Node *to, Node *size, float maxDist) 79{ 80 from->g = 0; 81 from->h = from->distanceToSqr(to); 82 from->f = from->h; 83 84 openSet.clear(); 85 openSet.insert(from); 86 87 Node *closest = from; 88 89 while (!openSet.isEmpty()) 90 { 91 Node *x = openSet.pop(); 92 93 if (x->equals(to)) 94 { 95 return reconstruct_path(from, to); 96 } 97 98 if (x->distanceToSqr(to) < closest->distanceToSqr(to)) 99 { 100 closest = x; 101 } 102 x->closed = true; 103 104 int neighborCount = getNeighbors(e, x, size, to, maxDist); 105 for (int i = 0; i < neighborCount; i++) 106 { 107 Node *y = neighbors->data[i]; 108 109 float tentative_g_score = x->g + x->distanceToSqr(y); 110 if (!y->inOpenSet() || tentative_g_score < y->g) 111 { 112 y->cameFrom = x; 113 y->g = tentative_g_score; 114 y->h = y->distanceToSqr(to); 115 if (y->inOpenSet()) 116 { 117 openSet.changeCost(y, y->g + y->h); 118 } 119 else 120 { 121 y->f = y->g + y->h; 122 openSet.insert(y); 123 } 124 } 125 } 126 } 127 128 if (closest == from) return NULL; 129 return reconstruct_path(from, closest); 130} 131 132int PathFinder::getNeighbors(Entity *entity, Node *pos, Node *size, Node *target, float maxDist) 133{ 134 int p = 0; 135 136 int jumpSize = 0; 137 if (isFree(entity, pos->x, pos->y + 1, pos->z, size) == TYPE_OPEN) jumpSize = 1; 138 139 Node *n = getNode(entity, pos->x, pos->y, pos->z + 1, size, jumpSize); 140 Node *w = getNode(entity, pos->x - 1, pos->y, pos->z, size, jumpSize); 141 Node *e = getNode(entity, pos->x + 1, pos->y, pos->z, size, jumpSize); 142 Node *s = getNode(entity, pos->x, pos->y, pos->z - 1, size, jumpSize); 143 144 if (n != NULL && !n->closed && n->distanceTo(target) < maxDist) neighbors->data[p++] = n; 145 if (w != NULL && !w->closed && w->distanceTo(target) < maxDist) neighbors->data[p++] = w; 146 if (e != NULL && !e->closed && e->distanceTo(target) < maxDist) neighbors->data[p++] = e; 147 if (s != NULL && !s->closed && s->distanceTo(target) < maxDist) neighbors->data[p++] = s; 148 149 return p; 150} 151 152Node *PathFinder::getNode(Entity *entity, int x, int y, int z, Node *size, int jumpSize) 153{ 154 Node *best = NULL; 155 int pathType = isFree(entity, x, y, z, size); 156 if (pathType == TYPE_WALKABLE) return getNode(x, y, z); 157 if (pathType == TYPE_OPEN) best = getNode(x, y, z); 158 if (best == NULL && jumpSize > 0 && pathType != TYPE_FENCE && pathType != TYPE_TRAP && isFree(entity, x, y + jumpSize, z, size) == TYPE_OPEN) 159 { 160 best = getNode(x, y + jumpSize, z); 161 y += jumpSize; 162 } 163 164 if (best != NULL) 165 { 166 int drop = 0; 167 int cost = 0; 168 while (y > 0) 169 { 170 cost = isFree(entity, x, y - 1, z, size); 171 if (avoidWater && cost == TYPE_WATER) return NULL; 172 if (cost != TYPE_OPEN) break; 173 // fell too far? 174 if (++drop >= 4) return NULL; // 4J - rolling this back to pre-java 1.6.4 version as we're suspicious of the performance implications of this 175// if (drop++ >= entity->getMaxFallDistance()) return NULL; 176 y--; 177 178 if (y > 0) best = getNode(x, y, z); 179 } 180 // fell into lava? 181 if (cost == TYPE_LAVA) return NULL; 182 } 183 184 return best; 185} 186 187/*final*/ Node *PathFinder::getNode(int x, int y, int z) 188{ 189 int i = Node::createHash(x, y, z); 190 Node *node; 191 AUTO_VAR(it, nodes.find(i)); 192 if ( it == nodes.end() ) 193 { 194 MemSect(54); 195 node = new Node(x, y, z); 196 MemSect(0); 197 nodes.insert( unordered_map<int, Node *>::value_type(i, node) ); 198 } 199 else 200 { 201 node = (*it).second; 202 } 203 return node; 204} 205 206int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size) 207{ 208 return isFree(entity, x, y, z, size, avoidWater, canOpenDoors, canPassDoors); 209} 210 211int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size, bool avoidWater, bool canOpenDoors, bool canPassDoors) 212{ 213 bool walkable = false; 214 for (int xx = x; xx < x + size->x; xx++) 215 for (int yy = y; yy < y + size->y; yy++) 216 for (int zz = z; zz < z + size->z; zz++) 217 { 218 int tileId = entity->level->getTile(xx, yy, zz); 219 if(tileId <= 0) continue; 220 if (tileId == Tile::trapdoor_Id) walkable = true; 221 else if (tileId == Tile::water_Id || tileId == Tile::calmWater_Id) 222 { 223 if (avoidWater) return TYPE_WATER; 224 else walkable = true; 225 } 226 else if (!canPassDoors && tileId == Tile::door_wood_Id) 227 { 228 return TYPE_BLOCKED; 229 } 230 231 Tile *tile = Tile::tiles[tileId]; 232 233 // 4J Stu - Use new getTileRenderShape passing in the tileId we have already got 234 if (entity->level->getTileRenderShape(tileId) == Tile::SHAPE_RAIL) 235 { 236 int xt = Mth::floor(entity->x); 237 int yt = Mth::floor(entity->y); 238 int zt = Mth::floor(entity->z); 239 if (entity->level->getTileRenderShape(xt, yt, zt) == Tile::SHAPE_RAIL 240 || entity->level->getTileRenderShape(xt, yt - 1, zt) == Tile::SHAPE_RAIL) 241 { 242 continue; 243 } 244 else 245 { 246 return TYPE_FENCE; 247 } 248 } 249 250 if (tile->isPathfindable(entity->level, xx, yy, zz)) continue; 251 if (canOpenDoors && tileId == Tile::door_wood_Id) continue; 252 253 int renderShape = tile->getRenderShape(); 254 if (renderShape == Tile::SHAPE_FENCE || tileId == Tile::fenceGate_Id || renderShape == Tile::SHAPE_WALL) return TYPE_FENCE; 255 if (tileId == Tile::trapdoor_Id) return TYPE_TRAP; 256 Material *m = tile->material; 257 if (m == Material::lava) 258 { 259 if (entity->isInLava()) continue; 260 return TYPE_LAVA; 261 } 262 return TYPE_BLOCKED; 263 } 264 265 return walkable ? TYPE_WALKABLE : TYPE_OPEN; 266} 267 268// function reconstruct_path(came_from,current_node) 269Path *PathFinder::reconstruct_path(Node *from, Node *to) 270{ 271 int count = 1; 272 Node *n = to; 273 while (n->cameFrom != NULL) 274 { 275 count++; 276 n = n->cameFrom; 277 } 278 279 NodeArray nodes = NodeArray(count); 280 n = to; 281 nodes.data[--count] = n; 282 while (n->cameFrom != NULL) 283 { 284 n = n->cameFrom; 285 nodes.data[--count] = n; 286 } 287 Path *ret = new Path(nodes); 288 delete [] nodes.data; 289 return ret; 290}