the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 383 lines 9.3 kB view raw
1#include "stdafx.h" 2#include "net.minecraft.world.level.h" 3#include "net.minecraft.world.level.pathfinder.h" 4#include "net.minecraft.world.entity.h" 5#include "net.minecraft.world.entity.ai.attributes.h" 6#include "net.minecraft.world.entity.ai.control.h" 7#include "net.minecraft.world.entity.monster.h" 8#include "net.minecraft.world.level.h" 9#include "net.minecraft.world.level.tile.h" 10#include "net.minecraft.world.phys.h" 11#include "PathNavigation.h" 12 13PathNavigation::PathNavigation(Mob *mob, Level *level) 14{ 15 this->mob = mob; 16 this->level = level; 17 dist = mob->getAttribute(SharedMonsterAttributes::FOLLOW_RANGE); 18 19 path = NULL; 20 speedModifier = 0.0; 21 avoidSun = false; 22 _tick = 0; 23 lastStuckCheck = 0; 24 lastStuckCheckPos = Vec3::newPermanent(0, 0, 0); 25 _canPassDoors = true; 26 _canOpenDoors = false; 27 avoidWater = false; 28 canFloat = false; 29} 30 31PathNavigation::~PathNavigation() 32{ 33 if(path != NULL) delete path; 34 delete lastStuckCheckPos; 35} 36 37void PathNavigation::setAvoidWater(bool avoidWater) 38{ 39 this->avoidWater = avoidWater; 40} 41 42bool PathNavigation::getAvoidWater() 43{ 44 return avoidWater; 45} 46 47void PathNavigation::setCanOpenDoors(bool canOpenDoors) 48{ 49 this->_canOpenDoors = canOpenDoors; 50} 51 52bool PathNavigation::canPassDoors() 53{ 54 return _canPassDoors; 55} 56 57void PathNavigation::setCanPassDoors(bool canPass) 58{ 59 _canPassDoors = canPass; 60} 61 62bool PathNavigation::canOpenDoors() 63{ 64 return _canOpenDoors; 65} 66 67void PathNavigation::setAvoidSun(bool avoidSun) 68{ 69 this->avoidSun = avoidSun; 70} 71 72void PathNavigation::setSpeedModifier(double speedModifier) 73{ 74 this->speedModifier = speedModifier; 75} 76 77void PathNavigation::setCanFloat(bool canFloat) 78{ 79 this->canFloat = canFloat; 80} 81 82float PathNavigation::getMaxDist() 83{ 84 return (float) dist->getValue(); 85} 86 87Path *PathNavigation::createPath(double x, double y, double z) 88{ 89 if (!canUpdatePath()) return NULL; 90 return level->findPath(mob->shared_from_this(), Mth::floor(x), (int) y, Mth::floor(z), getMaxDist(), _canPassDoors, _canOpenDoors, avoidWater, canFloat); 91} 92 93bool PathNavigation::moveTo(double x, double y, double z, double speedModifier) 94{ 95 MemSect(52); 96 Path *newPath = createPath(Mth::floor(x), (int) y, Mth::floor(z)); 97 MemSect(0); 98 // No need to delete newPath here as this will be copied into the member variable path and the class can assume responsibility for it 99 return moveTo(newPath, speedModifier); 100} 101 102Path *PathNavigation::createPath(shared_ptr<Entity> target) 103{ 104 if (!canUpdatePath()) return NULL; 105 return level->findPath(mob->shared_from_this(), target, getMaxDist(), _canPassDoors, _canOpenDoors, avoidWater, canFloat); 106} 107 108bool PathNavigation::moveTo(shared_ptr<Entity> target, double speedModifier) 109{ 110 MemSect(53); 111 Path *newPath = createPath(target); 112 MemSect(0); 113 // No need to delete newPath here as this will be copied into the member variable path and the class can assume responsibility for it 114 if (newPath != NULL) return moveTo(newPath, speedModifier); 115 else return false; 116} 117 118bool PathNavigation::moveTo(Path *newPath, double speedModifier) 119{ 120 if(newPath == NULL) 121 { 122 if(path != NULL) delete path; 123 path = NULL; 124 return false; 125 } 126 if(!newPath->sameAs(path)) 127 { 128 if(path != NULL) delete path; 129 path = newPath; 130 } 131 else 132 { 133 delete newPath; 134 } 135 if (avoidSun) trimPathFromSun(); 136 if (path->getSize() == 0) return false; 137 138 this->speedModifier = speedModifier; 139 Vec3 *mobPos = getTempMobPos(); 140 lastStuckCheck = _tick; 141 lastStuckCheckPos->x = mobPos->x; 142 lastStuckCheckPos->y = mobPos->y; 143 lastStuckCheckPos->z = mobPos->z; 144 return true; 145} 146 147Path *PathNavigation::getPath() 148{ 149 return path; 150} 151 152void PathNavigation::tick() 153{ 154 ++_tick; 155 if (isDone()) return; 156 157 if (canUpdatePath()) updatePath(); 158 159 if (isDone()) return; 160 Vec3 *target = path->currentPos(mob->shared_from_this()); 161 if (target == NULL) return; 162 163 mob->getMoveControl()->setWantedPosition(target->x, target->y, target->z, speedModifier); 164} 165 166void PathNavigation::updatePath() 167{ 168 Vec3 *mobPos = getTempMobPos(); 169 170 // find first elevations in path 171 int firstElevation = path->getSize(); 172 for (int i = path->getIndex(); path != NULL && i < path->getSize(); ++i) 173 { 174 if ((int) path->get(i)->y != (int) mobPos->y) 175 { 176 firstElevation = i; 177 break; 178 } 179 } 180 181 // remove those within way point radius (this is not optimal, should 182 // check canWalkDirectly also) possibly only check next as well 183 float waypointRadiusSqr = mob->bbWidth * mob->bbWidth; 184 for (int i = path->getIndex(); i < firstElevation; ++i) 185 { 186 Vec3 *pathPos = path->getPos(mob->shared_from_this(), i); 187 if (mobPos->distanceToSqr(pathPos) < waypointRadiusSqr) 188 { 189 path->setIndex(i + 1); 190 } 191 } 192 193 // smooth remaining on same elevation 194 int sx = (int) ceil(mob->bbWidth); 195 int sy = (int) mob->bbHeight + 1; 196 int sz = sx; 197 for (int i = firstElevation - 1; i >= path->getIndex(); --i) 198 { 199 if (canMoveDirectly(mobPos, path->getPos(mob->shared_from_this(), i), sx, sy, sz)) 200 { 201 path->setIndex(i); 202 break; 203 } 204 } 205 206 // stuck detection (probably pushed off path) 207 if (_tick - lastStuckCheck > 100) 208 { 209 if (mobPos->distanceToSqr(lastStuckCheckPos) < 1.5 * 1.5) stop(); 210 lastStuckCheck = _tick; 211 lastStuckCheckPos->x = mobPos->x; 212 lastStuckCheckPos->y = mobPos->y; 213 lastStuckCheckPos->z = mobPos->z; 214 } 215} 216 217bool PathNavigation::isDone() 218{ 219 return path == NULL || path->isDone(); 220} 221 222void PathNavigation::stop() 223{ 224 if(path != NULL) delete path; 225 path = NULL; 226} 227 228Vec3 *PathNavigation::getTempMobPos() 229{ 230 return Vec3::newTemp(mob->x, getSurfaceY(), mob->z); 231} 232 233int PathNavigation::getSurfaceY() 234{ 235 if (!mob->isInWater() || !canFloat) return (int) (mob->bb->y0 + 0.5); 236 237 int surface = (int) (mob->bb->y0); 238 int tileId = level->getTile(Mth::floor(mob->x), surface, Mth::floor(mob->z)); 239 int steps = 0; 240 while (tileId == Tile::water_Id || tileId == Tile::calmWater_Id) 241 { 242 ++surface; 243 tileId = level->getTile(Mth::floor(mob->x), surface, Mth::floor(mob->z)); 244 if (++steps > 16) return (int) (mob->bb->y0); 245 } 246 return surface; 247} 248 249bool PathNavigation::canUpdatePath() 250{ 251 return mob->onGround || (canFloat && isInLiquid()); 252} 253 254bool PathNavigation::isInLiquid() 255{ 256 return mob->isInWater() || mob->isInLava(); 257} 258 259void PathNavigation::trimPathFromSun() 260{ 261 if (level->canSeeSky(Mth::floor(mob->x), (int) (mob->bb->y0 + 0.5), Mth::floor(mob->z))) return; 262 263 for (int i = 0; i < path->getSize(); ++i) 264 { 265 Node *n = path->get(i); 266 if (level->canSeeSky((int) n->x, (int) n->y, (int) n->z)) 267 { 268 path->setSize(i - 1); 269 return; 270 } 271 } 272} 273 274bool PathNavigation::canMoveDirectly(Vec3 *startPos, Vec3 *stopPos, int sx, int sy, int sz) 275{ 276 277 int gridPosX = Mth::floor(startPos->x); 278 int gridPosZ = Mth::floor(startPos->z); 279 280 double dirX = stopPos->x - startPos->x; 281 double dirZ = stopPos->z - startPos->z; 282 double distSqr = dirX * dirX + dirZ * dirZ; 283 if (distSqr < 0.00000001) return false; 284 285 double nf = 1 / sqrt(distSqr); 286 dirX *= nf; 287 dirZ *= nf; 288 289 sx += 2; 290 sz += 2; 291 if (!canWalkOn(gridPosX, (int) startPos->y, gridPosZ, sx, sy, sz, startPos, dirX, dirZ)) return false; 292 sx -= 2; 293 sz -= 2; 294 295 double deltaX = 1 / abs(dirX); 296 double deltaZ = 1 / abs(dirZ); 297 298 double maxX = gridPosX * 1 - startPos->x; 299 double maxZ = gridPosZ * 1 - startPos->z; 300 if (dirX >= 0) maxX += 1; 301 if (dirZ >= 0) maxZ += 1; 302 maxX /= dirX; 303 maxZ /= dirZ; 304 305 int stepX = dirX < 0 ? -1 : 1; 306 int stepZ = dirZ < 0 ? -1 : 1; 307 int gridGoalX = Mth::floor(stopPos->x); 308 int gridGoalZ = Mth::floor(stopPos->z); 309 int currentDirX = gridGoalX - gridPosX; 310 int currentDirZ = gridGoalZ - gridPosZ; 311 while (currentDirX * stepX > 0 || currentDirZ * stepZ > 0) 312 { 313 if (maxX < maxZ) 314 { 315 maxX += deltaX; 316 gridPosX += stepX; 317 currentDirX = gridGoalX - gridPosX; 318 } 319 else 320 { 321 maxZ += deltaZ; 322 gridPosZ += stepZ; 323 currentDirZ = gridGoalZ - gridPosZ; 324 } 325 326 if (!canWalkOn(gridPosX, (int) startPos->y, gridPosZ, sx, sy, sz, startPos, dirX, dirZ)) return false; 327 } 328 return true; 329} 330 331bool PathNavigation::canWalkOn(int x, int y, int z, int sx, int sy, int sz, Vec3 *startPos, double goalDirX, double goalDirZ) 332{ 333 334 int startX = x - sx / 2; 335 int startZ = z - sz / 2; 336 337 if (!canWalkAbove(startX, y, startZ, sx, sy, sz, startPos, goalDirX, goalDirZ)) return false; 338 339 // lava or water or air under 340 for (int xx = startX; xx < startX + sx; xx++) 341 { 342 for (int zz = startZ; zz < startZ + sz; zz++) 343 { 344 double dirX = xx + 0.5 - startPos->x; 345 double dirZ = zz + 0.5 - startPos->z; 346 if (dirX * goalDirX + dirZ * goalDirZ < 0) continue; 347 int tile = level->getTile(xx, y - 1, zz); 348 if (tile <= 0) return false; 349 Material *m = Tile::tiles[tile]->material; 350 if (m == Material::water && !mob->isInWater()) return false; 351 if (m == Material::lava) return false; 352 } 353 } 354 355 return true; 356} 357 358bool PathNavigation::canWalkAbove(int startX, int startY, int startZ, int sx, int sy, int sz, Vec3 *startPos, double goalDirX, double goalDirZ) 359{ 360 361 for (int xx = startX; xx < startX + sx; xx++) 362 { 363 for (int yy = startY; yy < startY + sy; yy++) 364 { 365 for (int zz = startZ; zz < startZ + sz; zz++) 366 { 367 368 double dirX = xx + 0.5 - startPos->x; 369 double dirZ = zz + 0.5 - startPos->z; 370 if (dirX * goalDirX + dirZ * goalDirZ < 0) continue; 371 int tile = level->getTile(xx, yy, zz); 372 if (tile <= 0) continue; 373 if (!Tile::tiles[tile]->isPathfindable(level, xx, yy, zz)) return false; 374 } 375 } 376 } 377 return true; 378} 379 380void PathNavigation::setLevel(Level *level) 381{ 382 this->level = level; 383}