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.entity.h"
3#include "net.minecraft.world.entity.animal.h"
4#include "net.minecraft.world.entity.ai.attributes.h"
5#include "net.minecraft.world.entity.ai.goal.h"
6#include "net.minecraft.world.entity.ai.navigation.h"
7#include "net.minecraft.world.entity.monster.h"
8#include "net.minecraft.world.level.h"
9#include "net.minecraft.world.level.pathfinder.h"
10#include "net.minecraft.world.phys.h"
11#include "SharedConstants.h"
12#include "PathfinderMob.h"
13
14AttributeModifier *PathfinderMob::SPEED_MODIFIER_FLEEING = (new AttributeModifier(eModifierId_MOB_FLEEING, 2.0f, AttributeModifier::OPERATION_MULTIPLY_TOTAL))->setSerialize(false);
15
16PathfinderMob::PathfinderMob(Level *level) : Mob( level )
17{
18 path = NULL;
19 attackTarget = nullptr;
20 holdGround = false;
21 fleeTime = 0;
22
23 restrictRadius = -1;
24 restrictCenter = new Pos(0, 0, 0);
25 addedLeashRestrictionGoal = false;
26 leashRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0f);
27}
28
29bool PathfinderMob::shouldHoldGround()
30{
31 return false;
32}
33
34PathfinderMob::~PathfinderMob()
35{
36 delete path;
37 delete restrictCenter;
38 delete leashRestrictionGoal;
39}
40
41void PathfinderMob::serverAiStep()
42{
43 if (fleeTime > 0)
44 {
45 if (--fleeTime == 0)
46 {
47 AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED);
48 speed->removeModifier(SPEED_MODIFIER_FLEEING);
49 }
50 }
51 holdGround = shouldHoldGround();
52 float maxDist = 16;
53
54 if (attackTarget == NULL)
55 {
56 attackTarget = findAttackTarget();
57 if (attackTarget != NULL)
58 {
59 setPath(level->findPath(shared_from_this(), attackTarget, maxDist, true, false, false, true)); // 4J - changed to setPath from path =
60 }
61 }
62 else
63 {
64 if (attackTarget->isAlive())
65 {
66 float d = attackTarget->distanceTo(shared_from_this());
67 if (canSee(attackTarget))
68 {
69 checkHurtTarget(attackTarget, d);
70 }
71 }
72 else
73 {
74 attackTarget = nullptr;
75 }
76 }
77
78 /*
79 * if (holdGround) { xxa = 0; yya = 0; jumping = false; return; }
80 */
81
82 // 4J - a few changes here so that we can call findRandomStrollLocation for a sub-set of things that it normally wouldn't be in the java game.
83 // This is so that we can have entities wander around a little, in order that we can measure how far they wander and then determine (if they wander too far) that
84 // they aren't enclosed. We don't want the extra network overhead of just having Everything wandering round all the time, so have put a management system in place
85 // that selects a subset of entities which have had their flag set through the considerForExtraWandering method so that these can keep doing random strolling.
86
87 if (!holdGround && (attackTarget != NULL && (path == NULL || random->nextInt(20) == 0)))
88 {
89 setPath(level->findPath(shared_from_this(), attackTarget, maxDist, true, false, false, true));// 4J - changed to setPath from path =
90 }
91 else if (!holdGround && ((path == NULL && (random->nextInt(180) == 0) || fleeTime > 0) || (random->nextInt(120) == 0 || fleeTime > 0)))
92 {
93 if(noActionTime < SharedConstants::TICKS_PER_SECOND * 5)
94 {
95 findRandomStrollLocation();
96 }
97 }
98 else if (!holdGround && (path == NULL ) )
99 {
100 if( ( noActionTime >= SharedConstants::TICKS_PER_SECOND * 5 ) && isExtraWanderingEnabled() )
101 {
102 // This entity wouldn't normally be randomly strolling. However, if our management system says that it should do, then do. Don't
103 // bother waiting for random conditions to be met before picking a direction though as the point here is to see if it is possible to
104 // stroll out of a given area and so waiting around is just wasting time
105 findRandomStrollLocation(getWanderingQuadrant());
106 }
107 }
108
109 // Consider this for extra strolling if it is protected against despawning. We aren't interested in ones that aren't protected as the whole point of this
110 // extra wandering is to potentially transition from protected to not protected.
111 considerForExtraWandering( isDespawnProtected() );
112
113 int yFloor = Mth::floor(bb->y0 + 0.5f);
114
115 bool inWater = isInWater();
116 bool inLava = isInLava();
117 xRot = 0;
118 if (path == NULL || random->nextInt(100) == 0)
119 {
120 this->Mob::serverAiStep();
121 setPath(NULL);// 4J - changed to setPath from path =
122 return;
123 }
124
125 Vec3 *target = path->currentPos(shared_from_this());
126 double r = bbWidth * 2;
127 while (target != NULL && target->distanceToSqr(x, target->y, z) < r * r)
128 {
129 path->next();
130 if (path->isDone())
131 {
132 target = NULL;
133 setPath(NULL); // 4J - changed to setPath from path =
134 }
135 else target = path->currentPos(shared_from_this());
136 }
137
138 jumping = false;
139 if (target != NULL)
140 {
141 double xd = target->x - x;
142 double zd = target->z - z;
143 double yd = target->y - yFloor;
144 float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90;
145 float rotDiff = Mth::wrapDegrees(yRotD - yRot);
146 yya = (float) getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue();
147 if (rotDiff > MAX_TURN)
148 {
149 rotDiff = MAX_TURN;
150 }
151 if (rotDiff < -MAX_TURN)
152 {
153 rotDiff = -MAX_TURN;
154 }
155 yRot += rotDiff;
156
157 if (holdGround)
158 {
159 if (attackTarget != NULL)
160 {
161 double xd2 = attackTarget->x - x;
162 double zd2 = attackTarget->z - z;
163
164 float oldyRot = yRot;
165 yRot = (float) (atan2(zd2, xd2) * 180 / PI) - 90;
166
167 rotDiff = ((oldyRot - yRot) + 90) * PI / 180;
168 xxa = -Mth::sin(rotDiff) * yya * 1.0f;
169 yya = Mth::cos(rotDiff) * yya * 1.0f;
170 }
171 }
172 if (yd > 0)
173 {
174 jumping = true;
175 }
176 }
177
178 if (attackTarget != NULL)
179 {
180 lookAt(attackTarget, 30, 30);
181 }
182
183 if (horizontalCollision && !isPathFinding()) jumping = true;
184 if (random->nextFloat() < 0.8f && (inWater || inLava)) jumping = true;
185}
186
187void PathfinderMob::findRandomStrollLocation(int quadrant/*=-1*/) // 4J - added quadrant
188{
189 bool hasBest = false;
190 int xBest = -1;
191 int yBest = -1;
192 int zBest = -1;
193 float best = -99999;
194 for (int i = 0; i < 10; i++)
195 {
196 // 4J - added quadrant parameter to this method so that the caller can request that only stroll locations in one quadrant be found. If -1 is passed then
197 // behaviour is the same as the java game
198 int xt, zt;
199 int yt = Mth::floor(y + random->nextInt(7) - 3);
200 if( quadrant == -1 )
201 {
202 xt = Mth::floor(x + random->nextInt(13) - 6);
203 zt = Mth::floor(z + random->nextInt(13) - 6);
204 }
205 else
206 {
207 int sx = ( ( quadrant & 1 ) ? -1 : 1 );
208 int sz = ( ( quadrant & 2 ) ? -1 : 1 );
209 xt = Mth::floor(x + random->nextInt(7) * sx);
210 zt = Mth::floor(z + random->nextInt(7) * sz);
211 }
212 float value = getWalkTargetValue(xt, yt, zt);
213 if (value > best)
214 {
215 best = value;
216 xBest = xt;
217 yBest = yt;
218 zBest = zt;
219 hasBest = true;
220 }
221 }
222 if (hasBest)
223 {
224 setPath(level->findPath(shared_from_this(), xBest, yBest, zBest, 10, true, false, false, true)); // 4J - changed to setPath from path =
225 }
226}
227
228void PathfinderMob::checkHurtTarget(shared_ptr<Entity> target, float d)
229{
230}
231
232float PathfinderMob::getWalkTargetValue(int x, int y, int z)
233{
234 return 0;
235}
236
237shared_ptr<Entity> PathfinderMob::findAttackTarget()
238{
239 return shared_ptr<Entity>();
240}
241
242
243bool PathfinderMob::canSpawn()
244{
245 int xt = Mth::floor(x);
246 int yt = Mth::floor(bb->y0);
247 int zt = Mth::floor(z);
248 return this->Mob::canSpawn() && getWalkTargetValue(xt, yt, zt) >= 0;
249}
250
251bool PathfinderMob::isPathFinding()
252{
253 return path != NULL;
254}
255
256void PathfinderMob::setPath(Path *path)
257{
258 delete this->path;
259 this->path = path;
260}
261
262shared_ptr<Entity> PathfinderMob::getAttackTarget()
263{
264 return attackTarget;
265}
266
267void PathfinderMob::setAttackTarget(shared_ptr<Entity> attacker)
268{
269 attackTarget = attacker;
270}
271
272// might move to navigation, might make area
273bool PathfinderMob::isWithinRestriction()
274{
275 return isWithinRestriction(Mth::floor(x), Mth::floor(y), Mth::floor(z));
276}
277
278bool PathfinderMob::isWithinRestriction(int x, int y, int z)
279{
280 if (restrictRadius == -1) return true;
281 return restrictCenter->distSqr(x, y, z) < restrictRadius * restrictRadius;
282}
283
284void PathfinderMob::restrictTo(int x, int y, int z, int radius)
285{
286 restrictCenter->set(x, y, z);
287 restrictRadius = radius;
288}
289
290Pos *PathfinderMob::getRestrictCenter()
291{
292 return restrictCenter;
293}
294
295float PathfinderMob::getRestrictRadius()
296{
297 return restrictRadius;
298}
299
300void PathfinderMob::clearRestriction()
301{
302 restrictRadius = -1;
303}
304
305bool PathfinderMob::hasRestriction()
306{
307 return restrictRadius != -1;
308}
309
310void PathfinderMob::tickLeash()
311{
312 Mob::tickLeash();
313
314 if (isLeashed() && getLeashHolder() != NULL && getLeashHolder()->level == this->level)
315 {
316 // soft restriction
317 shared_ptr<Entity> leashHolder = getLeashHolder();
318 restrictTo((int) leashHolder->x, (int) leashHolder->y, (int) leashHolder->z, 5);
319
320 float _distanceTo = distanceTo(leashHolder);
321
322 shared_ptr<TamableAnimal> tamabaleAnimal = shared_from_this()->instanceof(eTYPE_TAMABLE_ANIMAL) ? dynamic_pointer_cast<TamableAnimal>(shared_from_this()) : nullptr;
323 if ( (tamabaleAnimal != NULL) && tamabaleAnimal->isSitting() )
324 {
325 if (_distanceTo > 10)
326 {
327 dropLeash(true, true);
328 }
329 return;
330 }
331
332 if (!addedLeashRestrictionGoal)
333 {
334 goalSelector.addGoal(2, leashRestrictionGoal, false);
335 getNavigation()->setAvoidWater(false);
336 addedLeashRestrictionGoal = true;
337 }
338
339 onLeashDistance(_distanceTo);
340
341 if (_distanceTo > 4)
342 {
343 // harder restriction
344 getNavigation()->moveTo(leashHolder, 1.0);
345 }
346 if (_distanceTo > 6)
347 {
348 // hardest restriction
349 double dx = (leashHolder->x - x) / _distanceTo;
350 double dy = (leashHolder->y - y) / _distanceTo;
351 double dz = (leashHolder->z - z) / _distanceTo;
352
353 xd += dx * abs(dx) * .4;
354 yd += dy * abs(dy) * .4;
355 zd += dz * abs(dz) * .4;
356 }
357 if (_distanceTo > 10)
358 {
359 dropLeash(true, true);
360 }
361
362 }
363 else if (!isLeashed() && addedLeashRestrictionGoal)
364 {
365 addedLeashRestrictionGoal = false;
366 goalSelector.removeGoal(leashRestrictionGoal);
367 getNavigation()->setAvoidWater(true);
368 clearRestriction();
369 }
370}
371
372void PathfinderMob::onLeashDistance(float distanceToLeashHolder)
373{
374}
375
376bool PathfinderMob::couldWander()
377{
378 return (noActionTime < SharedConstants::TICKS_PER_SECOND * 5) || ( isExtraWanderingEnabled() );
379}