the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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}