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 "com.mojang.nbt.h"
3#include "net.minecraft.world.item.h"
4#include "net.minecraft.world.item.enchantment.h"
5#include "net.minecraft.world.level.h"
6#include "net.minecraft.world.level.dimension.h"
7#include "net.minecraft.world.level.tile.h"
8#include "net.minecraft.world.phys.h"
9#include "net.minecraft.world.entity.item.h"
10#include "net.minecraft.world.level.material.h"
11#include "net.minecraft.world.damagesource.h"
12#include "SynchedEntityData.h"
13#include "EntityIO.h"
14#include "SharedConstants.h"
15
16#include "ParticleTypes.h"
17
18#include "EntityPos.h"
19#include "Entity.h"
20#include "SoundTypes.h"
21#include "..\minecraft.Client\HumanoidModel.h"
22#include "..\Minecraft.Client\MinecraftServer.h"
23#include "..\Minecraft.Client\MultiPlayerLevel.h"
24#include "..\Minecraft.Client\MultiplayerLocalPlayer.h"
25#include "..\Minecraft.Client\ServerLevel.h"
26#include "..\Minecraft.Client\PlayerList.h"
27
28const wstring Entity::RIDING_TAG = L"Riding";
29
30int Entity::entityCounter = 2048; // 4J - changed initialiser to 2048, as we are using range 0 - 2047 as special unique smaller ids for things that need network tracked
31DWORD Entity::tlsIdx = TlsAlloc();
32
33// 4J - added getSmallId & freeSmallId methods
34unsigned int Entity::entityIdUsedFlags[2048/32] = {0};
35unsigned int Entity::entityIdWanderFlags[2048/32] = {0};
36unsigned int Entity::entityIdRemovingFlags[2048/32] = {0};
37int Entity::extraWanderIds[EXTRA_WANDER_MAX] = {0};
38int Entity::extraWanderTicks = 0;
39int Entity::extraWanderCount = 0;
40
41int Entity::getSmallId()
42{
43 unsigned int *puiUsedFlags = entityIdUsedFlags;
44 unsigned int *puiRemovedFlags = NULL;
45
46 // If we are the server (we should be, if we are allocating small Ids), then check with the server if there are any small Ids which are
47 // still in the ServerPlayer's vectors of entities to be removed - these are used to gather up a set of entities into one network packet
48 // for final notification to the client that the entities are removed. We can't go re-using these small Ids yet, as otherwise we will
49 // potentially end up telling the client that the entity has been removed After we have already re-used its Id and created a new entity.
50 // This ends up with newly created client-side entities being removed by accident, causing invisible mobs.
51 if( ((size_t)TlsGetValue(tlsIdx) != 0 ) )
52 {
53 MinecraftServer *server = MinecraftServer::getInstance();
54 if( server )
55 {
56 // In some attempt to optimise this, flagEntitiesToBeRemoved most of the time shouldn't do anything at all, and in this case it
57 // doesn't even memset the entityIdRemovingFlags array, so we shouldn't use it if the return value is false.
58 bool removedFound = server->flagEntitiesToBeRemoved(entityIdRemovingFlags);
59 if( removedFound )
60 {
61 // Has set up the entityIdRemovingFlags vector in this case, so we should check against this when allocating new ids
62 // app.DebugPrintf("getSmallId: Removed entities found\n");
63 puiRemovedFlags = entityIdRemovingFlags;
64 }
65 }
66 }
67
68 for( int i = 0; i < (2048 / 32 ); i++ )
69 {
70 unsigned int uiFlags = *puiUsedFlags;
71 if( uiFlags != 0xffffffff )
72 {
73 unsigned int uiMask = 0x80000000;
74 for( int j = 0; j < 32; j++ )
75 {
76 // See comments above - now checking (if required) that these aren't newly removed entities that the clients still haven't been told about,
77 // so we don't reuse those ids before we should.
78 if( puiRemovedFlags )
79 {
80 if( puiRemovedFlags[i] & uiMask )
81 {
82 // app.DebugPrintf("Avoiding using ID %d (0x%x)\n", i * 32 + j,puiRemovedFlags[i]);
83 uiMask >>= 1;
84 continue;
85 }
86 }
87 if( ( uiFlags & uiMask ) == 0 )
88 {
89 uiFlags |= uiMask;
90 *puiUsedFlags = uiFlags;
91 return i * 32 + j;
92 }
93 uiMask >>= 1;
94 }
95 }
96 puiUsedFlags++;
97 }
98
99 app.DebugPrintf("Out of small entity Ids... possible leak?\n");
100 __debugbreak();
101 return -1;
102}
103
104void Entity::countFlagsForPIX()
105{
106 int freecount = 0;
107 unsigned int *puiUsedFlags = entityIdUsedFlags;
108 for( int i = 0; i < (2048 / 32 ); i++ )
109 {
110 unsigned int uiFlags = *puiUsedFlags;
111 if( uiFlags != 0xffffffff )
112 {
113 unsigned int uiMask = 0x80000000;
114 for( int j = 0; j < 32; j++ )
115 {
116 if( ( uiFlags & uiMask ) == 0 )
117 {
118 freecount++;
119 }
120 uiMask >>= 1;
121 }
122 }
123 puiUsedFlags++;
124 }
125 PIXAddNamedCounter(freecount,"Small Ids free");
126 PIXAddNamedCounter(2048 - freecount,"Small Ids used");
127}
128
129void Entity::resetSmallId()
130{
131 freeSmallId(entityId);
132 if( ((size_t)TlsGetValue(tlsIdx) != 0 ) )
133 {
134 entityId = getSmallId();
135 }
136}
137
138void Entity::freeSmallId(int index)
139{
140 if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread
141 if( index >= 2048 ) return; // Don't do anything if this isn't a short id
142
143 unsigned int i = index / 32;
144 unsigned int j = index % 32;
145 unsigned int uiMask = ~(0x80000000 >> j);
146
147 entityIdUsedFlags[i] &= uiMask;
148 entityIdWanderFlags[i] &= uiMask;
149}
150
151void Entity::useSmallIds()
152{
153 TlsSetValue(tlsIdx,(LPVOID)1);
154}
155
156// Things also added here to be able to manage the concept of a number of extra "wandering" entities - normally path finding entities aren't allowed to
157// randomly wander about once they are a certain distance away from any player, but we want to be able to (in a controlled fashion) allow some to be able
158// to move so that we can determine whether they have been enclosed in some kind of farm, and so be able to better determine what shouldn't or shouldn't be despawned.
159
160// Let the management system here know whether or not to consider this particular entity for some extra wandering
161void Entity::considerForExtraWandering(bool enable)
162{
163 if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread
164 if( entityId >= 2048 ) return; // Don't do anything if this isn't a short id
165
166 unsigned int i = entityId / 32;
167 unsigned int j = entityId % 32;
168 if( enable )
169 {
170 unsigned int uiMask = 0x80000000 >> j;
171 entityIdWanderFlags[i] |= uiMask;
172 }
173 else
174 {
175 unsigned int uiMask = ~(0x80000000 >> j);
176 entityIdWanderFlags[i] &= uiMask;
177 }
178}
179
180// Should this entity do wandering in addition to what the java code would have done?
181bool Entity::isExtraWanderingEnabled()
182{
183 if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return false; // Don't do anything with small ids if this isn't the server thread
184 if( entityId >= 2048 ) return false; // Don't do anything if this isn't a short id
185
186 for( int i = 0; i < extraWanderCount; i++ )
187 {
188 if( extraWanderIds[i] == entityId ) return true;
189 }
190 return false;
191}
192
193
194// Returns a quadrant of direction that a given entity should be moved in - this is to stop the randomness of the wandering/strolling from just making the entity double back
195// on itself and thus making the determination of whether the entity has been enclosed take longer than it needs to. This function returns a quadrant from 0 to 3
196// that should be consistent within one period of an entity being considered for extra wandering, but should potentially vary between tries and between different entities.
197int Entity::getWanderingQuadrant()
198{
199 return ( entityId + ( extraWanderTicks / EXTRA_WANDER_TICKS ) ) & 3;
200}
201
202// Every EXTRA_WANDER_TICKS ticks, attempt to find EXTRA_WANDER_MAX entity Ids from those that have been flagged as ones that should be considered for
203// extra wandering
204void Entity::tickExtraWandering()
205{
206 extraWanderTicks++;
207 // Time to move onto some new entities?
208
209 if( ( extraWanderTicks % EXTRA_WANDER_TICKS == 0 ) )
210 {
211 // printf("Updating extras: ");
212 // Start from the next Id after the one that we last found, or zero if we didn't find anything last time
213 int entityId = 0;
214 if( extraWanderCount )
215 {
216 entityId = ( extraWanderIds[ extraWanderCount - 1 ] + 1 ) % 2048;
217 }
218
219 extraWanderCount = 0;
220
221 for( int k = 0; ( k < 2048 ) && ( extraWanderCount < EXTRA_WANDER_MAX); k++ )
222 {
223 unsigned int i = entityId / 32;
224 unsigned int j = entityId % 32;
225 unsigned int uiMask = 0x80000000 >> j;
226
227 if( entityIdWanderFlags[i] & uiMask )
228 {
229 extraWanderIds[ extraWanderCount++ ] = entityId;
230 // printf("%d, ", entityId);
231 }
232
233 entityId = ( entityId + 1 ) % 2048;
234 }
235 // printf("\n");
236 }
237}
238
239// 4J - added for common ctor code
240// Do all the default initialisations done in the java class
241void Entity::_init(bool useSmallId, Level *level)
242{
243 // 4J - changed to assign two different types of ids. A range from 0-2047 is used for things that we'll be wanting to identify over the network,
244 // so we should only need 11 bits rather than 32 to uniquely identify them. The rest of the range is used for anything we don't need to track like this,
245 // currently particles. We only ever want to allocate this type of id from the server thread, so using thread local storage to isolate this.
246 if( useSmallId && ((size_t)TlsGetValue(tlsIdx) != 0 ) )
247 {
248 entityId = getSmallId();
249 }
250 else
251 {
252 entityId = Entity::entityCounter++;
253 if(entityCounter == 0x7ffffff ) entityCounter = 2048;
254 }
255
256 viewScale = 1.0;
257
258 blocksBuilding = false;
259 rider = weak_ptr<Entity>();
260 riding = nullptr;
261 forcedLoading = false;
262
263 //level = NULL; // Level is assigned to in the original c_tor code
264 xo = yo = zo = 0.0;
265 x = y = z = 0.0;
266 xd = yd = zd = 0.0;
267 yRot = xRot = 0.0f;
268 yRotO = xRotO = 0.0f;
269 bb = AABB::newPermanent(0, 0, 0, 0, 0, 0); // 4J Was final
270 onGround = false;
271 horizontalCollision = verticalCollision = false;
272 collision = false;
273 hurtMarked = false;
274 isStuckInWeb = false;
275
276 slide = true;
277 removed = false;
278 heightOffset = 0 / 16.0f;
279
280 bbWidth = 0.6f;
281 bbHeight = 1.8f;
282
283 walkDistO = 0;
284 walkDist = 0;
285 moveDist = 0.0f;
286
287 fallDistance = 0;
288
289 nextStep = 1;
290
291 xOld = yOld = zOld = 0.0;
292 ySlideOffset = 0;
293 footSize = 0.0f;
294 noPhysics = false;
295 pushthrough = 0.0f;
296
297 random = new Random();
298
299 tickCount = 0;
300 flameTime = 1;
301
302 onFire = 0;
303 wasInWater = false;
304
305
306 invulnerableTime = 0;
307
308 firstTick = true;
309
310 fireImmune = false;
311
312 // values that need to be sent to clients in SMP
313 if( useSmallId )
314 {
315 entityData = shared_ptr<SynchedEntityData>(new SynchedEntityData());
316 }
317 else
318 {
319 entityData = nullptr;
320 }
321
322 xRideRotA = yRideRotA = 0.0;
323 inChunk = false;
324 xChunk = yChunk = zChunk = 0;
325 xp = yp = zp = 0;
326 xRotp = yRotp = 0;
327 noCulling = false;
328
329 hasImpulse = false;
330
331 changingDimensionDelay = 0;
332 isInsidePortal = false;
333 portalTime = 0;
334 dimension = 0;
335 portalEntranceDir = 0;
336 invulnerable = false;
337 if( useSmallId )
338 {
339 uuid = L"ent" + Mth::createInsecureUUID(random);
340 }
341
342 // 4J Added
343 m_ignoreVerticalCollisions = false;
344 m_uiAnimOverrideBitmask = 0L;
345 m_ignorePortal = false;
346}
347
348Entity::Entity(Level *level, bool useSmallId) // 4J - added useSmallId parameter
349{
350 MemSect(16);
351 _init(useSmallId, level);
352 MemSect(0);
353
354 this->level = level;
355 // resetPos();
356 setPos(0, 0, 0);
357
358 if (level != NULL)
359 {
360 dimension = level->dimension->id;
361 }
362
363 if( entityData )
364 {
365 entityData->define(DATA_SHARED_FLAGS_ID, (byte) 0);
366 entityData->define(DATA_AIR_SUPPLY_ID, TOTAL_AIR_SUPPLY); // 4J Stu - Brought forward from 1.2.3 to fix 38654 - Gameplay: Player will take damage when air bubbles are present if resuming game from load/autosave underwater.
367 }
368
369 // 4J Stu - We cannot call virtual functions in ctors, as at this point the object
370 // is of type Entity and not a derived class
371 //this->defineSynchedData();
372}
373
374Entity::~Entity()
375{
376 freeSmallId(entityId);
377 delete random;
378 delete bb;
379}
380
381shared_ptr<SynchedEntityData> Entity::getEntityData()
382{
383 return entityData;
384}
385
386/*
387public bool equals(Object obj) {
388if (obj instanceof Entity) {
389return ((Entity) obj).entityId == entityId;
390}
391return false;
392}
393
394public int hashCode() {
395return entityId;
396}
397*/
398
399void Entity::resetPos()
400{
401 if (level == NULL) return;
402
403 shared_ptr<Entity> sharedThis = shared_from_this();
404 while (true && y > 0)
405 {
406 setPos(x, y, z);
407 if (level->getCubes(sharedThis, bb)->empty()) break;
408 y += 1;
409 }
410
411 xd = yd = zd = 0;
412 xRot = 0;
413}
414
415void Entity::remove()
416{
417 removed = true;
418}
419
420
421void Entity::setSize(float w, float h)
422{
423 if (w != bbWidth || h != bbHeight)
424 {
425 float oldW = bbWidth;
426
427 bbWidth = w;
428 bbHeight = h;
429
430 bb->x1 = bb->x0 + bbWidth;
431 bb->z1 = bb->z0 + bbWidth;
432 bb->y1 = bb->y0 + bbHeight;
433
434 if (bbWidth > oldW && !firstTick && !level->isClientSide)
435 {
436 move(oldW - bbWidth, 0, oldW - bbWidth);
437 }
438 }
439}
440
441void Entity::setPos(EntityPos *pos)
442{
443 if (pos->move) setPos(pos->x, pos->y, pos->z);
444 else setPos(x, y, z);
445
446 if (pos->rot) setRot(pos->yRot, pos->xRot);
447 else setRot(yRot, xRot);
448}
449
450void Entity::setRot(float yRot, float xRot)
451{
452 /* JAVA:
453 this->yRot = yRot % 360.0f;
454 this->xRot = xRot % 360.0f;
455
456 C++ Cannot do mod of non-integral type
457 */
458
459 while( yRot >= 360.0f )
460 yRot -= 360.0f;
461 while( yRot < 0 )
462 yRot += 360.0f;
463 while( xRot >= 360.0f )
464 xRot -= 360.0f;
465
466 this->yRot = yRot;
467 this->xRot = xRot;
468}
469
470
471void Entity::setPos(double x, double y, double z)
472{
473 this->x = x;
474 this->y = y;
475 this->z = z;
476 float w = bbWidth / 2;
477 float h = bbHeight;
478 bb->set(x - w, y - heightOffset + ySlideOffset, z - w, x + w, y - heightOffset + ySlideOffset + h, z + w);
479}
480
481void Entity::turn(float xo, float yo)
482{
483 float xRotOld = xRot;
484 float yRotOld = yRot;
485
486 yRot += xo * 0.15f;
487 xRot -= yo * 0.15f;
488 if (xRot < -90) xRot = -90;
489 if (xRot > 90) xRot = 90;
490
491 xRotO += xRot - xRotOld;
492 yRotO += yRot - yRotOld;
493}
494
495void Entity::interpolateTurn(float xo, float yo)
496{
497 yRot += xo * 0.15f;
498 xRot -= yo * 0.15f;
499 if (xRot < -90) xRot = -90;
500 if (xRot > 90) xRot = 90;
501}
502
503void Entity::tick()
504{
505 baseTick();
506}
507
508void Entity::baseTick()
509{
510 // 4J Stu - Not needed
511 //util.Timer.push("entityBaseTick");
512
513 if (riding != NULL && riding->removed)
514 {
515 riding = nullptr;
516 }
517
518 walkDistO = walkDist;
519 xo = x;
520 yo = y;
521 zo = z;
522 xRotO = xRot;
523 yRotO = yRot;
524
525 if (!level->isClientSide) // 4J Stu - Don't need this && level instanceof ServerLevel)
526 {
527 if(!m_ignorePortal) // 4J Added
528 {
529 MinecraftServer *server = dynamic_cast<ServerLevel *>(level)->getServer();
530 int waitTime = getPortalWaitTime();
531
532 if (isInsidePortal)
533 {
534 if (server->isNetherEnabled())
535 {
536 if (riding == NULL)
537 {
538 if (portalTime++ >= waitTime)
539 {
540 portalTime = waitTime;
541 changingDimensionDelay = getDimensionChangingDelay();
542
543 int targetDimension;
544
545 if (level->dimension->id == -1)
546 {
547 targetDimension = 0;
548 }
549 else
550 {
551 targetDimension = -1;
552 }
553
554 changeDimension(targetDimension);
555 }
556 }
557 isInsidePortal = false;
558 }
559 }
560 else
561 {
562 if (portalTime > 0) portalTime -= 4;
563 if (portalTime < 0) portalTime = 0;
564 }
565 if (changingDimensionDelay > 0) changingDimensionDelay--;
566 }
567 }
568
569 if (isSprinting() && !isInWater() && canCreateParticles())
570 {
571 int xt = Mth::floor(x);
572 int yt = Mth::floor(y - 0.2f - heightOffset);
573 int zt = Mth::floor(z);
574 int t = level->getTile(xt, yt, zt);
575 int d = level->getData(xt, yt, zt);
576 if (t > 0)
577 {
578 level->addParticle(PARTICLE_TILECRACK(t,d), x + (random->nextFloat() - 0.5) * bbWidth, bb->y0 + 0.1, z + (random->nextFloat() - 0.5) * bbWidth, -xd * 4, 1.5, -zd * 4);
579 }
580 }
581
582 updateInWaterState();
583
584 if (level->isClientSide)
585 {
586 onFire = 0;
587 }
588 else
589 {
590 if (onFire > 0)
591 {
592 if (fireImmune)
593 {
594 onFire -= 4;
595 if (onFire < 0) onFire = 0;
596 }
597 else
598 {
599 if (onFire % 20 == 0)
600 {
601 hurt(DamageSource::onFire, 1);
602 }
603 onFire--;
604 }
605 }
606 }
607
608 if (isInLava())
609 {
610 lavaHurt();
611 fallDistance *= .5f;
612 }
613
614 if (y < -64)
615 {
616 outOfWorld();
617 }
618
619 if (!level->isClientSide)
620 {
621 setSharedFlag(FLAG_ONFIRE, onFire > 0);
622 }
623
624 firstTick = false;
625
626 // 4J Stu - Unused
627 //util.Timer.pop();
628}
629
630int Entity::getPortalWaitTime()
631{
632 return 0;
633}
634
635void Entity::lavaHurt()
636{
637 if (fireImmune)
638 {
639 }
640 else
641 {
642 hurt(DamageSource::lava, 4);
643 setOnFire(15);
644 }
645}
646
647void Entity::setOnFire(int numberOfSeconds)
648{
649 int newValue = numberOfSeconds * SharedConstants::TICKS_PER_SECOND;
650 newValue = ProtectionEnchantment::getFireAfterDampener(shared_from_this(), newValue);
651 if (onFire < newValue)
652 {
653 onFire = newValue;
654 }
655}
656
657void Entity::clearFire()
658{
659 onFire = 0;
660}
661
662void Entity::outOfWorld()
663{
664 remove();
665}
666
667
668bool Entity::isFree(float xa, float ya, float za, float grow)
669{
670 AABB *box = bb->grow(grow, grow, grow)->cloneMove(xa, ya, za);
671 AABBList *aABBs = level->getCubes(shared_from_this(), box);
672 if (!aABBs->empty()) return false;
673 if (level->containsAnyLiquid(box)) return false;
674 return true;
675}
676
677bool Entity::isFree(double xa, double ya, double za)
678{
679 AABB *box = bb->cloneMove(xa, ya, za);
680 AABBList *aABBs = level->getCubes(shared_from_this(), box);
681 if (!aABBs->empty()) return false;
682 if (level->containsAnyLiquid(box)) return false;
683 return true;
684}
685
686void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - added noEntityCubes parameter
687{
688 if (noPhysics)
689 {
690 bb->move(xa, ya, za);
691 x = (bb->x0 + bb->x1) / 2.0f;
692 y = bb->y0 + heightOffset - ySlideOffset;
693 z = (bb->z0 + bb->z1) / 2.0f;
694 return;
695 }
696
697 ySlideOffset *= 0.4f;
698
699 double xo = x;
700 double yo = y;
701 double zo = z;
702
703 if (isStuckInWeb)
704 {
705 isStuckInWeb = false;
706
707 xa *= 0.25f;
708 ya *= 0.05f;
709 za *= 0.25f;
710 xd = 0.0f;
711 yd = 0.0f;
712 zd = 0.0f;
713 }
714
715 double xaOrg = xa;
716 double yaOrg = ya;
717 double zaOrg = za;
718
719 AABB *bbOrg = bb->copy();
720
721 bool isPlayerSneaking = onGround && isSneaking() && instanceof(eTYPE_PLAYER);
722
723 if (isPlayerSneaking)
724 {
725 double d = 0.05;
726 while (xa != 0 && level->getCubes(shared_from_this(), bb->cloneMove(xa, -1.0, 0))->empty())
727 {
728 if (xa < d && xa >= -d) xa = 0;
729 else if (xa > 0) xa -= d;
730 else xa += d;
731 xaOrg = xa;
732 }
733 while (za != 0 && level->getCubes(shared_from_this(), bb->cloneMove(0, -1.0, za))->empty())
734 {
735 if (za < d && za >= -d) za = 0;
736 else if (za > 0) za -= d;
737 else za += d;
738 zaOrg = za;
739 }
740 while (xa != 0 && za != 0 && level->getCubes(shared_from_this(), bb->cloneMove(xa, -1.0, za))->empty())
741 {
742 if (xa < d && xa >= -d) xa = 0;
743 else if (xa > 0) xa -= d;
744 else xa += d;
745 if (za < d && za >= -d) za = 0;
746 else if (za > 0) za -= d;
747 else za += d;
748 xaOrg = xa;
749 zaOrg = za;
750 }
751 }
752
753 AABBList *aABBs = level->getCubes(shared_from_this(), bb->expand(xa, ya, za), noEntityCubes, true);
754
755
756 // LAND FIRST, then x and z
757 AUTO_VAR(itEndAABB, aABBs->end());
758
759 // 4J Stu - Particles (and possibly other entities) don't have xChunk and zChunk set, so calculate the chunk instead
760 int xc = Mth::floor(x / 16);
761 int zc = Mth::floor(z / 16);
762 if(!level->isClientSide || level->reallyHasChunk(xc, zc))
763 {
764 // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk
765 // data then all the collision info will be incorrect as well
766 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
767 ya = (*it)->clipYCollide(bb, ya);
768 bb->move(0, ya, 0);
769 }
770
771 if (!slide && yaOrg != ya)
772 {
773 xa = ya = za = 0;
774 }
775
776 bool og = onGround || (yaOrg != ya && yaOrg < 0);
777
778 itEndAABB = aABBs->end();
779 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
780 xa = (*it)->clipXCollide(bb, xa);
781
782 bb->move(xa, 0, 0);
783
784 if (!slide && xaOrg != xa)
785 {
786 xa = ya = za = 0;
787 }
788
789 itEndAABB = aABBs->end();
790 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
791 za = (*it)->clipZCollide(bb, za);
792 bb->move(0, 0, za);
793
794 if (!slide && zaOrg != za)
795 {
796 xa = ya = za = 0;
797 }
798
799 if (footSize > 0 && og && (isPlayerSneaking || ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za)))
800 {
801 double xaN = xa;
802 double yaN = ya;
803 double zaN = za;
804
805 xa = xaOrg;
806 ya = footSize;
807 za = zaOrg;
808
809 AABB *normal = bb->copy();
810 bb->set(bbOrg);
811 // 4J - added extra expand, as if we don't move up by footSize by hitting a block above us, then overall we could be trying to move as much as footSize downwards,
812 // so we'd better include cubes under our feet in this list of things we might possibly collide with
813 aABBs = level->getCubes(shared_from_this(), bb->expand(xa, ya, za)->expand(0,-ya,0),false,true);
814
815 // LAND FIRST, then x and z
816 itEndAABB = aABBs->end();
817
818 if(!level->isClientSide || level->reallyHasChunk(xc, zc))
819 {
820 // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk
821 // data then all the collision info will be incorrect as well
822 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
823 ya = (*it)->clipYCollide(bb, ya);
824 bb->move(0, ya, 0);
825 }
826
827 if (!slide && yaOrg != ya)
828 {
829 xa = ya = za = 0;
830 }
831
832
833 itEndAABB = aABBs->end();
834 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
835 xa = (*it)->clipXCollide(bb, xa);
836 bb->move(xa, 0, 0);
837
838 if (!slide && xaOrg != xa)
839 {
840 xa = ya = za = 0;
841 }
842
843 itEndAABB = aABBs->end();
844 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
845 za = (*it)->clipZCollide(bb, za);
846 bb->move(0, 0, za);
847
848 if (!slide && zaOrg != za)
849 {
850 xa = ya = za = 0;
851 }
852
853
854 if (!slide && yaOrg != ya)
855 {
856 xa = ya = za = 0;
857 }
858 else
859 {
860 ya = -footSize;
861 // LAND FIRST, then x and z
862 itEndAABB = aABBs->end();
863 for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++)
864 ya = (*it)->clipYCollide(bb, ya);
865 bb->move(0, ya, 0);
866 }
867
868 if (xaN * xaN + zaN * zaN >= xa * xa + za * za)
869 {
870 xa = xaN;
871 ya = yaN;
872 za = zaN;
873 bb->set(normal);
874 }
875 }
876
877
878 x = (bb->x0 + bb->x1) / 2.0f;
879 y = bb->y0 + heightOffset - ySlideOffset;
880 z = (bb->z0 + bb->z1) / 2.0f;
881
882 horizontalCollision = (xaOrg != xa) || (zaOrg != za);
883 verticalCollision = !m_ignoreVerticalCollisions && (yaOrg != ya);
884 onGround = !m_ignoreVerticalCollisions && yaOrg != ya && yaOrg < 0;
885 collision = horizontalCollision || verticalCollision;
886 checkFallDamage(ya, onGround);
887
888 if (xaOrg != xa) xd = 0;
889 if (yaOrg != ya) yd = 0;
890 if (zaOrg != za) zd = 0;
891
892 double xm = x - xo;
893 double ym = y - yo;
894 double zm = z - zo;
895
896
897 if (makeStepSound() && !isPlayerSneaking && riding == NULL)
898 {
899 int xt = Mth::floor(x);
900 int yt = Mth::floor(y - 0.2f - heightOffset);
901 int zt = Mth::floor(z);
902 int t = level->getTile(xt, yt, zt);
903 if (t == 0)
904 {
905 int renderShape = level->getTileRenderShape(xt, yt - 1, zt);
906 if (renderShape == Tile::SHAPE_FENCE || renderShape == Tile::SHAPE_WALL || renderShape == Tile::SHAPE_FENCE_GATE)
907 {
908 t = level->getTile(xt, yt - 1, zt);
909 }
910 }
911 if (t != Tile::ladder_Id)
912 {
913 ym = 0;
914 }
915
916 walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6;
917 moveDist += Mth::sqrt(xm * xm + ym * ym + zm * zm) * 0.6;
918
919 if (moveDist > nextStep && t > 0)
920 {
921 nextStep = (int) moveDist + 1;
922 if (isInWater())
923 {
924 float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.35f;
925 if (speed > 1) speed = 1;
926 playSound(eSoundType_LIQUID_SWIM, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f);
927 }
928 playStepSound(xt, yt, zt, t);
929 Tile::tiles[t]->stepOn(level, xt, yt, zt, shared_from_this());
930 }
931 }
932
933 checkInsideTiles();
934
935
936 bool water = isInWaterOrRain();
937 if (level->containsFireTile(bb->shrink(0.001, 0.001, 0.001)))
938 {
939 burn(1);
940 if (!water)
941 {
942 onFire++;
943 if (onFire == 0) setOnFire(8);
944 }
945 }
946 else
947 {
948 if (onFire <= 0)
949 {
950 onFire = -flameTime;
951 }
952 }
953
954 if (water && onFire > 0)
955 {
956 playSound(eSoundType_RANDOM_FIZZ, 0.7f, 1.6f + (random->nextFloat() - random->nextFloat()) * 0.4f);
957 onFire = -flameTime;
958 }
959}
960
961void Entity::checkInsideTiles()
962{
963 int x0 = Mth::floor(bb->x0 + 0.001);
964 int y0 = Mth::floor(bb->y0 + 0.001);
965 int z0 = Mth::floor(bb->z0 + 0.001);
966 int x1 = Mth::floor(bb->x1 - 0.001);
967 int y1 = Mth::floor(bb->y1 - 0.001);
968 int z1 = Mth::floor(bb->z1 - 0.001);
969
970 if (level->hasChunksAt(x0, y0, z0, x1, y1, z1))
971 {
972 for (int x = x0; x <= x1; x++)
973 for (int y = y0; y <= y1; y++)
974 for (int z = z0; z <= z1; z++)
975 {
976 int t = level->getTile(x, y, z);
977 if (t > 0)
978 {
979 Tile::tiles[t]->entityInside(level, x, y, z, shared_from_this());
980 }
981 }
982 }
983}
984
985
986void Entity::playStepSound(int xt, int yt, int zt, int t)
987{
988 const Tile::SoundType *soundType = Tile::tiles[t]->soundType;
989 MemSect(31);
990
991 if (GetType() == eTYPE_PLAYER)
992 {
993 // should we turn off step sounds?
994 unsigned int uiAnimOverrideBitmask=getAnimOverrideBitmask(); // this is masked for custom anim off, and force anim
995
996 if(( uiAnimOverrideBitmask& (1<<HumanoidModel::eAnim_NoLegAnim))!=0)
997 {
998 return;
999 }
1000
1001 }
1002 if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id)
1003 {
1004 soundType = Tile::topSnow->soundType;
1005 playSound(soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch());
1006 }
1007 else if (!Tile::tiles[t]->material->isLiquid())
1008 {
1009 playSound(soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch());
1010 }
1011
1012 MemSect(0);
1013}
1014
1015void Entity::playSound(int iSound, float volume, float pitch)
1016{
1017 level->playEntitySound(shared_from_this(), iSound, volume, pitch);
1018}
1019
1020bool Entity::makeStepSound()
1021{
1022 return true;
1023}
1024
1025void Entity::checkFallDamage(double ya, bool onGround)
1026{
1027 if (onGround)
1028 {
1029 if (fallDistance > 0)
1030 {
1031 causeFallDamage(fallDistance);
1032 fallDistance = 0;
1033 }
1034 }
1035 else
1036 {
1037 if (ya < 0) fallDistance -= (float) ya;
1038 }
1039}
1040
1041AABB *Entity::getCollideBox()
1042{
1043 return NULL;
1044}
1045
1046void Entity::burn(int dmg)
1047{
1048 if (!fireImmune)
1049 {
1050 hurt(DamageSource::inFire, dmg);
1051 }
1052}
1053
1054bool Entity::isFireImmune()
1055{
1056 return fireImmune;
1057}
1058
1059void Entity::causeFallDamage(float distance)
1060{
1061 if (rider.lock() != NULL) rider.lock()->causeFallDamage(distance);
1062}
1063
1064
1065bool Entity::isInWaterOrRain()
1066{
1067 return wasInWater || (level->isRainingAt( Mth::floor(x), Mth::floor(y), Mth::floor(z)) || level->isRainingAt(Mth::floor(x), Mth::floor(y + bbHeight), Mth::floor(z)));
1068}
1069
1070bool Entity::isInWater()
1071{
1072 return wasInWater;
1073}
1074
1075bool Entity::updateInWaterState()
1076{
1077 if(level->checkAndHandleWater(bb->grow(0, -0.4f, 0)->shrink(0.001, 0.001, 0.001), Material::water, shared_from_this()))
1078 {
1079 if (!wasInWater && !firstTick && canCreateParticles())
1080 {
1081 float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f;
1082 if (speed > 1) speed = 1;
1083 MemSect(31);
1084 playSound(eSoundType_RANDOM_SPLASH, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f);
1085 MemSect(0);
1086 float yt = (float) Mth::floor(bb->y0);
1087 for (int i = 0; i < 1 + bbWidth * 20; i++)
1088 {
1089 float xo = (random->nextFloat() * 2 - 1) * bbWidth;
1090 float zo = (random->nextFloat() * 2 - 1) * bbWidth;
1091 level->addParticle(eParticleType_bubble, x + xo, yt + 1, z + zo, xd, yd - random->nextFloat() * 0.2f, zd);
1092 }
1093 for (int i = 0; i < 1 + bbWidth * 20; i++)
1094 {
1095 float xo = (random->nextFloat() * 2 - 1) * bbWidth;
1096 float zo = (random->nextFloat() * 2 - 1) * bbWidth;
1097 level->addParticle(eParticleType_splash, x + xo, yt + 1, z + zo, xd, yd, zd);
1098 }
1099 }
1100 fallDistance = 0;
1101 wasInWater = true;
1102 onFire = 0;
1103 }
1104 else
1105 {
1106 wasInWater = false;
1107 }
1108 return wasInWater;
1109}
1110
1111bool Entity::isUnderLiquid(Material *material)
1112{
1113 double yp = y + getHeadHeight();
1114 int xt = Mth::floor(x);
1115 int yt = Mth::floor(yp); // 4J - this used to be a nested pair of floors for some reason
1116 int zt = Mth::floor(z);
1117 int t = level->getTile(xt, yt, zt);
1118 if (t != 0 && Tile::tiles[t]->material == material) {
1119 float hh = LiquidTile::getHeight(level->getData(xt, yt, zt)) - 1 / 9.0f;
1120 float h = yt + 1 - hh;
1121 return yp < h;
1122 }
1123 return false;
1124}
1125
1126float Entity::getHeadHeight()
1127{
1128 return 0;
1129}
1130
1131bool Entity::isInLava()
1132{
1133 return level->containsMaterial(bb->grow(-0.1f, -0.4f, -0.1f), Material::lava);
1134}
1135
1136void Entity::moveRelative(float xa, float za, float speed)
1137{
1138 float dist = xa * xa + za * za;
1139 if (dist < 0.01f * 0.01f) return;
1140
1141 dist = sqrt(dist);
1142 if (dist < 1) dist = 1;
1143 dist = speed / dist;
1144 xa *= dist;
1145 za *= dist;
1146
1147 float sinVar = Mth::sin(yRot * PI / 180);
1148 float cosVar = Mth::cos(yRot * PI / 180);
1149
1150 xd += xa * cosVar - za * sinVar;
1151 zd += za * cosVar + xa * sinVar;
1152}
1153
1154// 4J - change brought forward from 1.8.2
1155int Entity::getLightColor(float a)
1156{
1157 int xTile = Mth::floor(x);
1158 int zTile = Mth::floor(z);
1159
1160 if (level->hasChunkAt(xTile, 0, zTile))
1161 {
1162 double hh = (bb->y1 - bb->y0) * 0.66;
1163 int yTile = Mth::floor(y - heightOffset + hh);
1164 return level->getLightColor(xTile, yTile, zTile, 0);
1165 }
1166 return 0;
1167}
1168
1169// 4J - changes brought forward from 1.8.2
1170float Entity::getBrightness(float a)
1171{
1172 int xTile = Mth::floor(x);
1173 int zTile = Mth::floor(z);
1174 if (level->hasChunkAt(xTile, 0, zTile))
1175 {
1176 double hh = (bb->y1 - bb->y0) * 0.66;
1177 int yTile = Mth::floor(y - heightOffset + hh);
1178 return level->getBrightness(xTile, yTile, zTile);
1179 }
1180 return 0;
1181}
1182
1183void Entity::setLevel(Level *level)
1184{
1185 this->level = level;
1186}
1187
1188void Entity::absMoveTo(double x, double y, double z, float yRot, float xRot)
1189{
1190 xo = this->x = x;
1191 yo = this->y = y;
1192 zo = this->z = z;
1193 yRotO = this->yRot = yRot;
1194 xRotO = this->xRot = xRot;
1195 ySlideOffset = 0;
1196
1197 double yRotDiff = yRotO - yRot;
1198 if (yRotDiff < -180) yRotO += 360;
1199 if (yRotDiff >= 180) yRotO -= 360;
1200 setPos(this->x, this->y, this->z);
1201 setRot(yRot, xRot);
1202}
1203
1204void Entity::moveTo(double x, double y, double z, float yRot, float xRot)
1205{
1206 xOld = xo = this->x = x;
1207 yOld = yo = this->y = y + heightOffset;
1208 zOld = zo = this->z = z;
1209 this->yRot = yRot;
1210 this->xRot = xRot;
1211 setPos(this->x, this->y, this->z);
1212}
1213
1214float Entity::distanceTo(shared_ptr<Entity> e)
1215{
1216 float xd = (float) (x - e->x);
1217 float yd = (float) (y - e->y);
1218 float zd = (float) (z - e->z);
1219 return sqrt(xd * xd + yd * yd + zd * zd);
1220}
1221
1222double Entity::distanceToSqr(double x2, double y2, double z2)
1223{
1224 double xd = (x - x2);
1225 double yd = (y - y2);
1226 double zd = (z - z2);
1227 return xd * xd + yd * yd + zd * zd;
1228}
1229
1230double Entity::distanceTo(double x2, double y2, double z2)
1231{
1232 double xd = (x - x2);
1233 double yd = (y - y2);
1234 double zd = (z - z2);
1235 return sqrt(xd * xd + yd * yd + zd * zd);
1236}
1237
1238double Entity::distanceToSqr(shared_ptr<Entity> e)
1239{
1240 double xd = x - e->x;
1241 double yd = y - e->y;
1242 double zd = z - e->z;
1243 return xd * xd + yd * yd + zd * zd;
1244}
1245
1246void Entity::playerTouch(shared_ptr<Player> player)
1247{
1248}
1249
1250void Entity::push(shared_ptr<Entity> e)
1251{
1252 if (e->rider.lock().get() == this || e->riding.get() == this) return;
1253
1254 double xa = e->x - x;
1255 double za = e->z - z;
1256
1257 double dd = Mth::asbMax(xa, za);
1258
1259 if (dd >= 0.01f)
1260 {
1261 dd = sqrt(dd);
1262 xa /= dd;
1263 za /= dd;
1264
1265 double pow = 1 / dd;
1266 if (pow > 1) pow = 1;
1267 xa *= pow;
1268 za *= pow;
1269
1270 xa *= 0.05f;
1271 za *= 0.05f;
1272
1273 xa *= 1 - pushthrough;
1274 za *= 1 - pushthrough;
1275
1276 push(-xa, 0, -za);
1277 e->push(xa, 0, za);
1278 }
1279}
1280
1281void Entity::push(double xa, double ya, double za)
1282{
1283 xd += xa;
1284 yd += ya;
1285 zd += za;
1286 hasImpulse = true;
1287}
1288
1289void Entity::markHurt()
1290{
1291 hurtMarked = true;
1292}
1293
1294bool Entity::hurt(DamageSource *source, float damage)
1295{
1296 if(isInvulnerable()) return false;
1297 markHurt();
1298 return false;
1299}
1300
1301bool Entity::intersects(double x0, double y0, double z0, double x1, double y1, double z1)
1302{
1303 return bb->intersects(x0, y0, z0, x1, y1, z1);
1304}
1305
1306bool Entity::isPickable()
1307{
1308 return false;
1309}
1310
1311bool Entity::isPushable()
1312{
1313 return false;
1314}
1315
1316bool Entity::isShootable()
1317{
1318 return false;
1319}
1320
1321void Entity::awardKillScore(shared_ptr<Entity> victim, int score)
1322{
1323}
1324
1325bool Entity::shouldRender(Vec3 *c)
1326{
1327 double xd = x - c->x;
1328 double yd = y - c->y;
1329 double zd = z - c->z;
1330 double distance = xd * xd + yd * yd + zd * zd;
1331 return shouldRenderAtSqrDistance(distance);
1332}
1333
1334bool Entity::shouldRenderAtSqrDistance(double distance)
1335{
1336 double size = bb->getSize();
1337 size *= 64.0f * viewScale;
1338 return distance < size * size;
1339}
1340
1341bool Entity::isCreativeModeAllowed()
1342{
1343 return false;
1344}
1345
1346bool Entity::saveAsMount(CompoundTag *entityTag)
1347{
1348 wstring id = getEncodeId();
1349 if (removed || id.empty() )
1350 {
1351 return false;
1352 }
1353 // TODO Is this fine to be casting to a non-const char pointer?
1354 entityTag->putString(L"id", id );
1355 saveWithoutId(entityTag);
1356 return true;
1357}
1358
1359bool Entity::save(CompoundTag *entityTag)
1360{
1361 wstring id = getEncodeId();
1362 if (removed || id.empty() || (rider.lock() != NULL) )
1363 {
1364 return false;
1365 }
1366 // TODO Is this fine to be casting to a non-const char pointer?
1367 entityTag->putString(L"id", id );
1368 saveWithoutId(entityTag);
1369 return true;
1370}
1371
1372void Entity::saveWithoutId(CompoundTag *entityTag)
1373{
1374 entityTag->put(L"Pos", newDoubleList(3, x, y + ySlideOffset, z));
1375 entityTag->put(L"Motion", newDoubleList(3, xd, yd, zd));
1376 entityTag->put(L"Rotation", newFloatList(2, yRot, xRot));
1377
1378 entityTag->putFloat(L"FallDistance", fallDistance);
1379 entityTag->putShort(L"Fire", (short) onFire);
1380 entityTag->putShort(L"Air", (short) getAirSupply());
1381 entityTag->putBoolean(L"OnGround", onGround);
1382 entityTag->putInt(L"Dimension", dimension);
1383 entityTag->putBoolean(L"Invulnerable", invulnerable);
1384 entityTag->putInt(L"PortalCooldown", changingDimensionDelay);
1385
1386 entityTag->putString(L"UUID", uuid);
1387
1388 addAdditonalSaveData(entityTag);
1389
1390 if (riding != NULL)
1391 {
1392 CompoundTag *ridingTag = new CompoundTag(RIDING_TAG);
1393 if (riding->saveAsMount(ridingTag))
1394 {
1395 entityTag->put(L"Riding", ridingTag);
1396 }
1397 }
1398}
1399
1400void Entity::load(CompoundTag *tag)
1401{
1402 ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) tag->getList(L"Pos");
1403 ListTag<DoubleTag> *motion = (ListTag<DoubleTag> *) tag->getList(L"Motion");
1404 ListTag<FloatTag> *rotation = (ListTag<FloatTag> *) tag->getList(L"Rotation");
1405
1406 xd = motion->get(0)->data;
1407 yd = motion->get(1)->data;
1408 zd = motion->get(2)->data;
1409
1410 if (abs(xd) > 10.0)
1411 {
1412 xd = 0;
1413 }
1414 if (abs(yd) > 10.0)
1415 {
1416 yd = 0;
1417 }
1418 if (abs(zd) > 10.0)
1419 {
1420 zd = 0;
1421 }
1422
1423 xo = xOld = x = pos->get(0)->data;
1424 yo = yOld = y = pos->get(1)->data;
1425 zo = zOld = z = pos->get(2)->data;
1426
1427 yRotO = yRot = rotation->get(0)->data;
1428 xRotO = xRot = rotation->get(1)->data;
1429
1430 fallDistance = tag->getFloat(L"FallDistance");
1431 onFire = tag->getShort(L"Fire");
1432 setAirSupply(tag->getShort(L"Air"));
1433 onGround = tag->getBoolean(L"OnGround");
1434 dimension = tag->getInt(L"Dimension");
1435 invulnerable = tag->getBoolean(L"Invulnerable");
1436 changingDimensionDelay = tag->getInt(L"PortalCooldown");
1437
1438 if (tag->contains(L"UUID"))
1439 {
1440 uuid = tag->getString(L"UUID");
1441 }
1442
1443 setPos(x, y, z);
1444 setRot(yRot, xRot);
1445
1446 readAdditionalSaveData(tag);
1447
1448 // set position again because bb size may have changed
1449 if (repositionEntityAfterLoad()) setPos(x, y, z);
1450}
1451
1452bool Entity::repositionEntityAfterLoad()
1453{
1454 return true;
1455}
1456
1457const wstring Entity::getEncodeId()
1458{
1459 return EntityIO::getEncodeId( shared_from_this() );
1460}
1461
1462/**
1463* Called after load() has finished and the entity has been added to the
1464* world
1465*/
1466void Entity::onLoadedFromSave()
1467{
1468
1469}
1470
1471template<typename ...Args>
1472ListTag<DoubleTag> *Entity::newDoubleList(unsigned int, double firstValue, Args... args)
1473{
1474 ListTag<DoubleTag> *res = new ListTag<DoubleTag>();
1475
1476 // Add the first parameter to the ListTag
1477 res->add( new DoubleTag(L"", firstValue ) );
1478
1479 // use pre-C++17 fold trick (TODO: once we drop C++14 support, use C++14 fold expression)
1480 using expander = int[];
1481 (void)expander{0, (res->add(new DoubleTag(L"", static_cast<double>(args))), 0)...};
1482
1483 return res;
1484}
1485
1486ListTag<FloatTag> *Entity::newFloatList(unsigned int number, float firstValue, float secondValue)
1487{
1488 ListTag<FloatTag> *res = new ListTag<FloatTag>();
1489
1490 // Add the first parameter to the ListTag
1491 res->add( new FloatTag( L"", firstValue ) );
1492
1493 // TODO - 4J Stu For some reason the va_list wasn't working correctly here
1494 // We only make a list of two floats so just overriding and not using va_list
1495 res->add( new FloatTag( L"", secondValue ) );
1496
1497 /*
1498 va_list vl;
1499 va_start(vl,firstValue);
1500
1501 float val;
1502
1503 for (unsigned int i = 1; i < number; i++)
1504 {
1505 val = va_arg(vl,float);
1506 res->add(new FloatTag(val));
1507 }
1508 va_end(vl);
1509 */
1510 return res;
1511}
1512
1513float Entity::getShadowHeightOffs()
1514{
1515 return bbHeight / 2;
1516}
1517
1518shared_ptr<ItemEntity> Entity::spawnAtLocation(int resource, int count)
1519{
1520 return spawnAtLocation(resource, count, 0);
1521}
1522
1523shared_ptr<ItemEntity> Entity::spawnAtLocation(int resource, int count, float yOffs)
1524{
1525 return spawnAtLocation(shared_ptr<ItemInstance>( new ItemInstance(resource, count, 0) ), yOffs);
1526}
1527
1528shared_ptr<ItemEntity> Entity::spawnAtLocation(shared_ptr<ItemInstance> itemInstance, float yOffs)
1529{
1530 if (itemInstance->count == 0)
1531 {
1532 return nullptr;
1533 }
1534 shared_ptr<ItemEntity> ie = shared_ptr<ItemEntity>( new ItemEntity(level, x, y + yOffs, z, itemInstance) );
1535 ie->throwTime = 10;
1536 level->addEntity(ie);
1537 return ie;
1538}
1539
1540bool Entity::isAlive()
1541{
1542 return !removed;
1543}
1544
1545bool Entity::isInWall()
1546{
1547 for (int i = 0; i < 8; i++)
1548 {
1549 float xo = ((i >> 0) % 2 - 0.5f) * bbWidth * 0.8f;
1550 float yo = ((i >> 1) % 2 - 0.5f) * 0.1f;
1551 float zo = ((i >> 2) % 2 - 0.5f) * bbWidth * 0.8f;
1552 int xt = Mth::floor(x + xo);
1553 int yt = Mth::floor(y + getHeadHeight() + yo);
1554 int zt = Mth::floor(z + zo);
1555 if (level->isSolidBlockingTile(xt, yt, zt))
1556 {
1557 return true;
1558 }
1559 }
1560 return false;
1561}
1562
1563bool Entity::interact(shared_ptr<Player> player)
1564{
1565 return false;
1566}
1567
1568AABB *Entity::getCollideAgainstBox(shared_ptr<Entity> entity)
1569{
1570 return NULL;
1571}
1572
1573void Entity::rideTick()
1574{
1575 if (riding->removed)
1576 {
1577 riding = nullptr;
1578 return;
1579 }
1580 xd = yd = zd = 0;
1581 tick();
1582
1583 if (riding == NULL) return;
1584
1585 // Sets riders old&new position to it's mount's old&new position (plus the ride y-seperatation).
1586 riding->positionRider();
1587
1588 yRideRotA += (riding->yRot - riding->yRotO);
1589 xRideRotA += (riding->xRot - riding->xRotO);
1590
1591 // Wrap rotation angles.
1592 while (yRideRotA >= 180) yRideRotA -= 360;
1593 while (yRideRotA < -180) yRideRotA += 360;
1594 while (xRideRotA >= 180) xRideRotA -= 360;
1595 while (xRideRotA < -180) xRideRotA += 360;
1596
1597 double yra = yRideRotA * 0.5;
1598 double xra = xRideRotA * 0.5;
1599
1600 // Cap rotation speed.
1601 float max = 10;
1602 if (yra > max) yra = max;
1603 if (yra < -max) yra = -max;
1604 if (xra > max) xra = max;
1605 if (xra < -max) xra = -max;
1606
1607 yRideRotA -= yra;
1608 xRideRotA -= xra;
1609
1610 // jeb: This caused the crosshair to "drift" while riding horses. For now I've just disabled it,
1611 // because I can't figure out what it's needed for. Riding boats and minecarts seem unaffected...
1612 // yRot += yra;
1613 // xRot += xra;
1614}
1615
1616void Entity::positionRider()
1617{
1618 shared_ptr<Entity> lockedRider = rider.lock();
1619 if( lockedRider == NULL)
1620 {
1621 return;
1622 }
1623 lockedRider->setPos(x, y + getRideHeight() + lockedRider->getRidingHeight(), z);
1624}
1625
1626double Entity::getRidingHeight()
1627{
1628 return heightOffset;
1629}
1630
1631double Entity::getRideHeight()
1632{
1633 return bbHeight * .75;
1634}
1635
1636void Entity::ride(shared_ptr<Entity> e)
1637{
1638 xRideRotA = 0;
1639 yRideRotA = 0;
1640
1641 if (e == NULL)
1642 {
1643 if (riding != NULL)
1644 {
1645 // 4J Stu - Position should already be updated before the SetEntityLinkPacket comes in
1646 if(!level->isClientSide) moveTo(riding->x, riding->bb->y0 + riding->bbHeight, riding->z, yRot, xRot);
1647 riding->rider = weak_ptr<Entity>();
1648 }
1649 riding = nullptr;
1650 return;
1651 }
1652 if (riding != NULL)
1653 {
1654 riding->rider = weak_ptr<Entity>();
1655 }
1656 riding = e;
1657 e->rider = shared_from_this();
1658}
1659
1660void Entity::lerpTo(double x, double y, double z, float yRot, float xRot, int steps)
1661{
1662 setPos(x, y, z);
1663 setRot(yRot, xRot);
1664
1665 // 4J - don't know what this special y collision is specifically for, but its definitely bad news
1666 // for arrows as they are actually Meant to intersect the geometry they land in slightly.
1667 if( GetType() != eTYPE_ARROW )
1668 {
1669 AABBList *collisions = level->getCubes(shared_from_this(), bb->shrink(1 / 32.0, 0, 1 / 32.0));
1670 if (!collisions->empty())
1671 {
1672 double yTop = 0;
1673 AUTO_VAR(itEnd, collisions->end());
1674 for (AUTO_VAR(it, collisions->begin()); it != itEnd; it++)
1675 {
1676 AABB *ab = *it; //collisions->at(i);
1677 if (ab->y1 > yTop) yTop = ab->y1;
1678 }
1679
1680 y += yTop - bb->y0;
1681 setPos(x, y, z);
1682 }
1683 }
1684}
1685
1686float Entity::getPickRadius()
1687{
1688 return 0.1f;
1689}
1690
1691Vec3 *Entity::getLookAngle()
1692{
1693 return NULL;
1694}
1695
1696void Entity::handleInsidePortal()
1697{
1698 if (changingDimensionDelay > 0)
1699 {
1700 changingDimensionDelay = getDimensionChangingDelay();
1701 return;
1702 }
1703
1704 double xd = xo - x;
1705 double zd = zo - z;
1706
1707 if (!level->isClientSide && !isInsidePortal)
1708 {
1709 portalEntranceDir = Direction::getDirection(xd, zd);
1710 }
1711
1712 isInsidePortal = true;
1713}
1714
1715int Entity::getDimensionChangingDelay()
1716{
1717 return SharedConstants::TICKS_PER_SECOND * 45;
1718}
1719
1720void Entity::lerpMotion(double xd, double yd, double zd)
1721{
1722 this->xd = xd;
1723 this->yd = yd;
1724 this->zd = zd;
1725}
1726
1727void Entity::handleEntityEvent(byte eventId)
1728{
1729}
1730
1731void Entity::animateHurt()
1732{
1733}
1734
1735ItemInstanceArray Entity::getEquipmentSlots() // ItemInstance[]
1736{
1737 return ItemInstanceArray(); // Default ctor creates NULL internal array
1738}
1739
1740// 4J Stu - Brought forward change from 1.3 to fix #64688 - Customer Encountered: TU7: Content: Art: Aura of enchanted item is not displayed for other players in online game
1741void Entity::setEquippedSlot(int slot, shared_ptr<ItemInstance> item)
1742{
1743}
1744
1745bool Entity::isOnFire()
1746{
1747 return !fireImmune && (onFire > 0 || getSharedFlag(FLAG_ONFIRE));
1748}
1749
1750bool Entity::isRiding()
1751{
1752 return riding != NULL;
1753}
1754
1755bool Entity::isSneaking()
1756{
1757 return getSharedFlag(FLAG_SNEAKING);
1758}
1759
1760void Entity::setSneaking(bool value)
1761{
1762 setSharedFlag(FLAG_SNEAKING, value);
1763}
1764
1765bool Entity::isIdle()
1766{
1767 return getSharedFlag(FLAG_IDLEANIM);
1768}
1769
1770void Entity::setIsIdle(bool value)
1771{
1772 setSharedFlag(FLAG_IDLEANIM, value);
1773}
1774
1775bool Entity::isSprinting()
1776{
1777 return getSharedFlag(FLAG_SPRINTING);
1778}
1779
1780void Entity::setSprinting(bool value)
1781{
1782 setSharedFlag(FLAG_SPRINTING, value);
1783}
1784
1785bool Entity::isInvisible()
1786{
1787 return getSharedFlag(FLAG_INVISIBLE);
1788}
1789
1790bool Entity::isInvisibleTo(shared_ptr<Player> plr)
1791{
1792 return isInvisible();
1793}
1794
1795void Entity::setInvisible(bool value)
1796{
1797 setSharedFlag(FLAG_INVISIBLE, value);
1798}
1799
1800bool Entity::isWeakened()
1801{
1802 return getSharedFlag(FLAG_EFFECT_WEAKENED);
1803}
1804
1805void Entity::setWeakened(bool value)
1806{
1807 setSharedFlag(FLAG_EFFECT_WEAKENED, value);
1808}
1809
1810bool Entity::isUsingItemFlag()
1811{
1812 return getSharedFlag(FLAG_USING_ITEM);
1813}
1814
1815void Entity::setUsingItemFlag(bool value)
1816{
1817 setSharedFlag(FLAG_USING_ITEM, value);
1818}
1819
1820bool Entity::getSharedFlag(int flag)
1821{
1822 if( entityData )
1823 {
1824 return (entityData->getByte(DATA_SHARED_FLAGS_ID) & (1 << flag)) != 0;
1825 }
1826 else
1827 {
1828 return false;
1829 }
1830}
1831
1832void Entity::setSharedFlag(int flag, bool value)
1833{
1834 if( entityData )
1835 {
1836 byte currentValue = entityData->getByte(DATA_SHARED_FLAGS_ID);
1837 if (value)
1838 {
1839 entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue | (1 << flag)));
1840 }
1841 else
1842 {
1843 entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue & ~(1 << flag)));
1844 }
1845 }
1846}
1847
1848// 4J Stu - Brought forward from 1.2.3 to fix 38654 - Gameplay: Player will take damage when air bubbles are present if resuming game from load/autosave underwater.
1849int Entity::getAirSupply()
1850{
1851 return entityData->getShort(DATA_AIR_SUPPLY_ID);
1852}
1853
1854// 4J Stu - Brought forward from 1.2.3 to fix 38654 - Gameplay: Player will take damage when air bubbles are present if resuming game from load/autosave underwater.
1855void Entity::setAirSupply(int supply)
1856{
1857 entityData->set(DATA_AIR_SUPPLY_ID, (short) supply);
1858}
1859
1860void Entity::thunderHit(const LightningBolt *lightningBolt)
1861{
1862 burn(5);
1863 onFire++;
1864 if (onFire == 0) setOnFire(8);
1865}
1866
1867void Entity::killed(shared_ptr<LivingEntity> mob)
1868{
1869}
1870
1871bool Entity::checkInTile(double x, double y, double z)
1872{
1873 int xTile = Mth::floor(x);
1874 int yTile = Mth::floor(y);
1875 int zTile = Mth::floor(z);
1876
1877 double xd = x - (xTile);
1878 double yd = y - (yTile);
1879 double zd = z - (zTile);
1880
1881 vector<AABB *> *cubes = level->getTileCubes(bb);
1882 if ( (cubes && !cubes->empty()) || level->isFullAABBTile(xTile, yTile, zTile))
1883 {
1884 bool west = !level->isFullAABBTile(xTile - 1, yTile, zTile);
1885 bool east = !level->isFullAABBTile(xTile + 1, yTile, zTile);
1886 bool down = !level->isFullAABBTile(xTile, yTile - 1, zTile);
1887 bool up = !level->isFullAABBTile(xTile, yTile + 1, zTile);
1888 bool north = !level->isFullAABBTile(xTile, yTile, zTile - 1);
1889 bool south = !level->isFullAABBTile(xTile, yTile, zTile + 1);
1890
1891 int dir = 3;
1892 double closest = 9999;
1893 if (west && xd < closest)
1894 {
1895 closest = xd;
1896 dir = 0;
1897 }
1898 if (east && 1 - xd < closest)
1899 {
1900 closest = 1 - xd;
1901 dir = 1;
1902 }
1903 if (up && 1 - yd < closest)
1904 {
1905 closest = 1 - yd;
1906 dir = 3;
1907 }
1908 if (north && zd < closest)
1909 {
1910 closest = zd;
1911 dir = 4;
1912 }
1913 if (south && 1 - zd < closest)
1914 {
1915 closest = 1 - zd;
1916 dir = 5;
1917 }
1918
1919 float speed = random->nextFloat() * 0.2f + 0.1f;
1920 if (dir == 0) this->xd = -speed;
1921 if (dir == 1) this->xd = +speed;
1922
1923 if (dir == 2) this->yd = -speed;
1924 if (dir == 3) this->yd = +speed;
1925
1926 if (dir == 4) this->zd = -speed;
1927 if (dir == 5) this->zd = +speed;
1928
1929 return true;
1930 }
1931 return false;
1932}
1933
1934void Entity::makeStuckInWeb()
1935{
1936 isStuckInWeb = true;
1937 fallDistance = 0;
1938}
1939
1940wstring Entity::getAName()
1941{
1942#ifdef _DEBUG
1943 wstring id = EntityIO::getEncodeId(shared_from_this());
1944 if (id.empty()) id = L"generic";
1945 return L"entity." + id + _toString(entityId);
1946#else
1947 return L"";
1948#endif
1949}
1950
1951vector<shared_ptr<Entity> > *Entity::getSubEntities()
1952{
1953 return NULL;
1954}
1955
1956bool Entity::is(shared_ptr<Entity> other)
1957{
1958 return shared_from_this() == other;
1959}
1960
1961float Entity::getYHeadRot()
1962{
1963 return 0;
1964}
1965
1966void Entity::setYHeadRot(float yHeadRot)
1967{
1968}
1969
1970bool Entity::isAttackable()
1971{
1972 return true;
1973}
1974
1975bool Entity::skipAttackInteraction(shared_ptr<Entity> source)
1976{
1977 return false;
1978}
1979
1980bool Entity::isInvulnerable()
1981{
1982 return invulnerable;
1983}
1984
1985void Entity::copyPosition(shared_ptr<Entity> target)
1986{
1987 moveTo(target->x, target->y, target->z, target->yRot, target->xRot);
1988}
1989
1990void Entity::restoreFrom(shared_ptr<Entity> oldEntity, bool teleporting)
1991{
1992 CompoundTag *tag = new CompoundTag();
1993 oldEntity->saveWithoutId(tag);
1994 load(tag);
1995 delete tag;
1996 changingDimensionDelay = oldEntity->changingDimensionDelay;
1997 portalEntranceDir = oldEntity->portalEntranceDir;
1998}
1999
2000void Entity::changeDimension(int i)
2001{
2002 if (level->isClientSide || removed) return;
2003
2004 MinecraftServer *server = MinecraftServer::getInstance();
2005 int lastDimension = dimension;
2006 ServerLevel *oldLevel = server->getLevel(lastDimension);
2007 ServerLevel *newLevel = server->getLevel(i);
2008
2009 if (lastDimension == 1 && i == 1)
2010 {
2011 newLevel = server->getLevel(0);
2012 }
2013
2014 // 4J: Restrictions on what can go through
2015 {
2016 // 4J: Some things should just be destroyed when they hit a portal
2017 if (instanceof(eTYPE_FALLINGTILE))
2018 {
2019 removed = true;
2020 return;
2021 }
2022
2023 // 4J: Check server level entity limit (arrows, item entities, experience orbs, etc)
2024 if (newLevel->atEntityLimit(shared_from_this())) return;
2025
2026 // 4J: Check level limit on living entities, minecarts and boats
2027 if (!instanceof(eTYPE_PLAYER) && !newLevel->canCreateMore(GetType(), Level::eSpawnType_Portal)) return;
2028 }
2029
2030 // 4J: Definitely sending, set dimension now
2031 dimension = newLevel->dimension->id;
2032
2033 level->removeEntity(shared_from_this());
2034 removed = false;
2035
2036 server->getPlayers()->repositionAcrossDimension(shared_from_this(), lastDimension, oldLevel, newLevel);
2037 shared_ptr<Entity> newEntity = EntityIO::newEntity(EntityIO::getEncodeId(shared_from_this()), newLevel);
2038
2039 if (newEntity != NULL)
2040 {
2041 newEntity->restoreFrom(shared_from_this(), true);
2042
2043 if (lastDimension == 1 && i == 1)
2044 {
2045 Pos *spawnPos = newLevel->getSharedSpawnPos();
2046 spawnPos->y = level->getTopSolidBlock(spawnPos->x, spawnPos->z);
2047 newEntity->moveTo(spawnPos->x, spawnPos->y, spawnPos->z, newEntity->yRot, newEntity->xRot);
2048 delete spawnPos;
2049 }
2050
2051 newLevel->addEntity(newEntity);
2052 }
2053
2054 removed = true;
2055
2056 oldLevel->resetEmptyTime();
2057 newLevel->resetEmptyTime();
2058}
2059
2060float Entity::getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile)
2061{
2062 return tile->getExplosionResistance(shared_from_this());
2063}
2064
2065bool Entity::shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power)
2066{
2067 return true;
2068}
2069
2070int Entity::getMaxFallDistance()
2071{
2072 return 3;
2073}
2074
2075int Entity::getPortalEntranceDir()
2076{
2077 return portalEntranceDir;
2078}
2079
2080bool Entity::isIgnoringTileTriggers()
2081{
2082 return false;
2083}
2084
2085bool Entity::displayFireAnimation()
2086{
2087 return isOnFire();
2088}
2089
2090void Entity::setUUID(const wstring &UUID)
2091{
2092 uuid = UUID;
2093}
2094
2095wstring Entity::getUUID()
2096{
2097 return uuid;
2098}
2099
2100bool Entity::isPushedByWater()
2101{
2102 return true;
2103}
2104
2105wstring Entity::getDisplayName()
2106{
2107 return getAName();
2108}
2109
2110// 4J: Added to retrieve name that should be sent in ChatPackets (important on Xbox One for players)
2111wstring Entity::getNetworkName()
2112{
2113 return getDisplayName();
2114}
2115
2116void Entity::setAnimOverrideBitmask(unsigned int uiBitmask)
2117{
2118 m_uiAnimOverrideBitmask=uiBitmask;
2119 app.DebugPrintf("!!! Setting anim override bitmask to %d\n",uiBitmask);
2120}
2121unsigned int Entity::getAnimOverrideBitmask()
2122{
2123 if(app.GetGameSettings(eGameSetting_CustomSkinAnim)==0 )
2124 {
2125 // We have a force animation for some skins (claptrap)
2126 // 4J-PB - treat all the eAnim_Disable flags as a force anim
2127 unsigned int uiIgnoreUserCustomSkinAnimSettingMask=(1<<HumanoidModel::eAnim_ForceAnim) |
2128 (1<<HumanoidModel::eAnim_DisableRenderArm0) |
2129 (1<<HumanoidModel::eAnim_DisableRenderArm1) |
2130 (1<<HumanoidModel::eAnim_DisableRenderTorso) |
2131 (1<<HumanoidModel::eAnim_DisableRenderLeg0) |
2132 (1<<HumanoidModel::eAnim_DisableRenderLeg1) |
2133 (1<<HumanoidModel::eAnim_DisableRenderHair);
2134
2135 if((m_uiAnimOverrideBitmask & HumanoidModel::m_staticBitmaskIgnorePlayerCustomAnimSetting)!=0)
2136 {
2137 return m_uiAnimOverrideBitmask;
2138 }
2139 return 0;
2140 }
2141
2142 return m_uiAnimOverrideBitmask;
2143}