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