Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
49 kB · 2143 lines
C++
at master
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143#include "stdafx.h"#include "com.mojang.nbt.h"#include "net.minecraft.world.item.h"#include "net.minecraft.world.item.enchantment.h"#include "net.minecraft.world.level.h"#include "net.minecraft.world.level.dimension.h"#include "net.minecraft.world.level.tile.h"#include "net.minecraft.world.phys.h"#include "net.minecraft.world.entity.item.h"#include "net.minecraft.world.level.material.h"#include "net.minecraft.world.damagesource.h"#include "SynchedEntityData.h"#include "EntityIO.h"#include "SharedConstants.h"
#include "ParticleTypes.h"
#include "EntityPos.h"#include "Entity.h"#include "SoundTypes.h"#include "..\minecraft.Client\HumanoidModel.h"#include "..\Minecraft.Client\MinecraftServer.h"#include "..\Minecraft.Client\MultiPlayerLevel.h"#include "..\Minecraft.Client\MultiplayerLocalPlayer.h"#include "..\Minecraft.Client\ServerLevel.h"#include "..\Minecraft.Client\PlayerList.h"
const wstring Entity::RIDING_TAG = L"Riding";
int 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 trackedDWORD Entity::tlsIdx = TlsAlloc();
// 4J - added getSmallId & freeSmallId methodsunsigned int Entity::entityIdUsedFlags[2048/32] = {0};unsigned int Entity::entityIdWanderFlags[2048/32] = {0};unsigned int Entity::entityIdRemovingFlags[2048/32] = {0};int Entity::extraWanderIds[EXTRA_WANDER_MAX] = {0};int Entity::extraWanderTicks = 0;int Entity::extraWanderCount = 0;
int Entity::getSmallId(){ unsigned int *puiUsedFlags = entityIdUsedFlags; unsigned int *puiRemovedFlags = NULL;
// 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 // 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 // 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 // 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. // This ends up with newly created client-side entities being removed by accident, causing invisible mobs. if( ((size_t)TlsGetValue(tlsIdx) != 0 ) ) { MinecraftServer *server = MinecraftServer::getInstance(); if( server ) { // In some attempt to optimise this, flagEntitiesToBeRemoved most of the time shouldn't do anything at all, and in this case it // doesn't even memset the entityIdRemovingFlags array, so we shouldn't use it if the return value is false. bool removedFound = server->flagEntitiesToBeRemoved(entityIdRemovingFlags); if( removedFound ) { // Has set up the entityIdRemovingFlags vector in this case, so we should check against this when allocating new ids // app.DebugPrintf("getSmallId: Removed entities found\n"); puiRemovedFlags = entityIdRemovingFlags; } } }
for( int i = 0; i < (2048 / 32 ); i++ ) { unsigned int uiFlags = *puiUsedFlags; if( uiFlags != 0xffffffff ) { unsigned int uiMask = 0x80000000; for( int j = 0; j < 32; j++ ) { // See comments above - now checking (if required) that these aren't newly removed entities that the clients still haven't been told about, // so we don't reuse those ids before we should. if( puiRemovedFlags ) { if( puiRemovedFlags[i] & uiMask ) { // app.DebugPrintf("Avoiding using ID %d (0x%x)\n", i * 32 + j,puiRemovedFlags[i]); uiMask >>= 1; continue; } } if( ( uiFlags & uiMask ) == 0 ) { uiFlags |= uiMask; *puiUsedFlags = uiFlags; return i * 32 + j; } uiMask >>= 1; } } puiUsedFlags++; }
app.DebugPrintf("Out of small entity Ids... possible leak?\n"); __debugbreak(); return -1;}
void Entity::countFlagsForPIX(){ int freecount = 0; unsigned int *puiUsedFlags = entityIdUsedFlags; for( int i = 0; i < (2048 / 32 ); i++ ) { unsigned int uiFlags = *puiUsedFlags; if( uiFlags != 0xffffffff ) { unsigned int uiMask = 0x80000000; for( int j = 0; j < 32; j++ ) { if( ( uiFlags & uiMask ) == 0 ) { freecount++; } uiMask >>= 1; } } puiUsedFlags++; } PIXAddNamedCounter(freecount,"Small Ids free"); PIXAddNamedCounter(2048 - freecount,"Small Ids used");}
void Entity::resetSmallId(){ freeSmallId(entityId); if( ((size_t)TlsGetValue(tlsIdx) != 0 ) ) { entityId = getSmallId(); }}
void Entity::freeSmallId(int index){ if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread if( index >= 2048 ) return; // Don't do anything if this isn't a short id
unsigned int i = index / 32; unsigned int j = index % 32; unsigned int uiMask = ~(0x80000000 >> j);
entityIdUsedFlags[i] &= uiMask; entityIdWanderFlags[i] &= uiMask;}
void Entity::useSmallIds(){ TlsSetValue(tlsIdx,(LPVOID)1);}
// 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// 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// 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.
// Let the management system here know whether or not to consider this particular entity for some extra wanderingvoid Entity::considerForExtraWandering(bool enable){ if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread if( entityId >= 2048 ) return; // Don't do anything if this isn't a short id
unsigned int i = entityId / 32; unsigned int j = entityId % 32; if( enable ) { unsigned int uiMask = 0x80000000 >> j; entityIdWanderFlags[i] |= uiMask; } else { unsigned int uiMask = ~(0x80000000 >> j); entityIdWanderFlags[i] &= uiMask; }}
// Should this entity do wandering in addition to what the java code would have done?bool Entity::isExtraWanderingEnabled(){ if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return false; // Don't do anything with small ids if this isn't the server thread if( entityId >= 2048 ) return false; // Don't do anything if this isn't a short id
for( int i = 0; i < extraWanderCount; i++ ) { if( extraWanderIds[i] == entityId ) return true; } return false;}
// 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// 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// 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.int Entity::getWanderingQuadrant(){ return ( entityId + ( extraWanderTicks / EXTRA_WANDER_TICKS ) ) & 3;}
// 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// extra wanderingvoid Entity::tickExtraWandering(){ extraWanderTicks++; // Time to move onto some new entities?
if( ( extraWanderTicks % EXTRA_WANDER_TICKS == 0 ) ) { // printf("Updating extras: "); // Start from the next Id after the one that we last found, or zero if we didn't find anything last time int entityId = 0; if( extraWanderCount ) { entityId = ( extraWanderIds[ extraWanderCount - 1 ] + 1 ) % 2048; }
extraWanderCount = 0;
for( int k = 0; ( k < 2048 ) && ( extraWanderCount < EXTRA_WANDER_MAX); k++ ) { unsigned int i = entityId / 32; unsigned int j = entityId % 32; unsigned int uiMask = 0x80000000 >> j;
if( entityIdWanderFlags[i] & uiMask ) { extraWanderIds[ extraWanderCount++ ] = entityId; // printf("%d, ", entityId); }
entityId = ( entityId + 1 ) % 2048; } // printf("\n"); }}
// 4J - added for common ctor code// Do all the default initialisations done in the java classvoid Entity::_init(bool useSmallId, Level *level){ // 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, // 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, // currently particles. We only ever want to allocate this type of id from the server thread, so using thread local storage to isolate this. if( useSmallId && ((size_t)TlsGetValue(tlsIdx) != 0 ) ) { entityId = getSmallId(); } else { entityId = Entity::entityCounter++; if(entityCounter == 0x7ffffff ) entityCounter = 2048; }
viewScale = 1.0;
blocksBuilding = false; rider = weak_ptr<Entity>(); riding = nullptr; forcedLoading = false;
//level = NULL; // Level is assigned to in the original c_tor code xo = yo = zo = 0.0; x = y = z = 0.0; xd = yd = zd = 0.0; yRot = xRot = 0.0f; yRotO = xRotO = 0.0f; bb = AABB::newPermanent(0, 0, 0, 0, 0, 0); // 4J Was final onGround = false; horizontalCollision = verticalCollision = false; collision = false; hurtMarked = false; isStuckInWeb = false;
slide = true; removed = false; heightOffset = 0 / 16.0f;
bbWidth = 0.6f; bbHeight = 1.8f;
walkDistO = 0; walkDist = 0; moveDist = 0.0f;
fallDistance = 0;
nextStep = 1;
xOld = yOld = zOld = 0.0; ySlideOffset = 0; footSize = 0.0f; noPhysics = false; pushthrough = 0.0f;
random = new Random();
tickCount = 0; flameTime = 1;
onFire = 0; wasInWater = false;
invulnerableTime = 0;
firstTick = true;
fireImmune = false;
// values that need to be sent to clients in SMP if( useSmallId ) { entityData = shared_ptr<SynchedEntityData>(new SynchedEntityData()); } else { entityData = nullptr; }
xRideRotA = yRideRotA = 0.0; inChunk = false; xChunk = yChunk = zChunk = 0; xp = yp = zp = 0; xRotp = yRotp = 0; noCulling = false;
hasImpulse = false;
changingDimensionDelay = 0; isInsidePortal = false; portalTime = 0; dimension = 0; portalEntranceDir = 0; invulnerable = false; if( useSmallId ) { uuid = L"ent" + Mth::createInsecureUUID(random); }
// 4J Added m_ignoreVerticalCollisions = false; m_uiAnimOverrideBitmask = 0L; m_ignorePortal = false;}
Entity::Entity(Level *level, bool useSmallId) // 4J - added useSmallId parameter{ MemSect(16); _init(useSmallId, level); MemSect(0);
this->level = level; // resetPos(); setPos(0, 0, 0);
if (level != NULL) { dimension = level->dimension->id; }
if( entityData ) { entityData->define(DATA_SHARED_FLAGS_ID, (byte) 0); 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. }
// 4J Stu - We cannot call virtual functions in ctors, as at this point the object // is of type Entity and not a derived class //this->defineSynchedData();}
Entity::~Entity(){ freeSmallId(entityId); delete random; delete bb;}
shared_ptr<SynchedEntityData> Entity::getEntityData(){ return entityData;}
/*public bool equals(Object obj) {if (obj instanceof Entity) {return ((Entity) obj).entityId == entityId;}return false;}
public int hashCode() {return entityId;}*/
void Entity::resetPos(){ if (level == NULL) return;
shared_ptr<Entity> sharedThis = shared_from_this(); while (true && y > 0) { setPos(x, y, z); if (level->getCubes(sharedThis, bb)->empty()) break; y += 1; }
xd = yd = zd = 0; xRot = 0;}
void Entity::remove(){ removed = true;}
void Entity::setSize(float w, float h){ if (w != bbWidth || h != bbHeight) { float oldW = bbWidth;
bbWidth = w; bbHeight = h;
bb->x1 = bb->x0 + bbWidth; bb->z1 = bb->z0 + bbWidth; bb->y1 = bb->y0 + bbHeight;
if (bbWidth > oldW && !firstTick && !level->isClientSide) { move(oldW - bbWidth, 0, oldW - bbWidth); } }}
void Entity::setPos(EntityPos *pos){ if (pos->move) setPos(pos->x, pos->y, pos->z); else setPos(x, y, z);
if (pos->rot) setRot(pos->yRot, pos->xRot); else setRot(yRot, xRot);}
void Entity::setRot(float yRot, float xRot){ /* JAVA: this->yRot = yRot % 360.0f; this->xRot = xRot % 360.0f;
C++ Cannot do mod of non-integral type */
while( yRot >= 360.0f ) yRot -= 360.0f; while( yRot < 0 ) yRot += 360.0f; while( xRot >= 360.0f ) xRot -= 360.0f;
this->yRot = yRot; this->xRot = xRot;}
void Entity::setPos(double x, double y, double z){ this->x = x; this->y = y; this->z = z; float w = bbWidth / 2; float h = bbHeight; bb->set(x - w, y - heightOffset + ySlideOffset, z - w, x + w, y - heightOffset + ySlideOffset + h, z + w);}
void Entity::turn(float xo, float yo){ float xRotOld = xRot; float yRotOld = yRot;
yRot += xo * 0.15f; xRot -= yo * 0.15f; if (xRot < -90) xRot = -90; if (xRot > 90) xRot = 90;
xRotO += xRot - xRotOld; yRotO += yRot - yRotOld;}
void Entity::interpolateTurn(float xo, float yo){ yRot += xo * 0.15f; xRot -= yo * 0.15f; if (xRot < -90) xRot = -90; if (xRot > 90) xRot = 90;}
void Entity::tick(){ baseTick();}
void Entity::baseTick(){ // 4J Stu - Not needed //util.Timer.push("entityBaseTick");
if (riding != NULL && riding->removed) { riding = nullptr; }
walkDistO = walkDist; xo = x; yo = y; zo = z; xRotO = xRot; yRotO = yRot;
if (!level->isClientSide) // 4J Stu - Don't need this && level instanceof ServerLevel) { if(!m_ignorePortal) // 4J Added { MinecraftServer *server = dynamic_cast<ServerLevel *>(level)->getServer(); int waitTime = getPortalWaitTime();
if (isInsidePortal) { if (server->isNetherEnabled()) { if (riding == NULL) { if (portalTime++ >= waitTime) { portalTime = waitTime; changingDimensionDelay = getDimensionChangingDelay();
int targetDimension;
if (level->dimension->id == -1) { targetDimension = 0; } else { targetDimension = -1; }
changeDimension(targetDimension); } } isInsidePortal = false; } } else { if (portalTime > 0) portalTime -= 4; if (portalTime < 0) portalTime = 0; } if (changingDimensionDelay > 0) changingDimensionDelay--; } }
if (isSprinting() && !isInWater() && canCreateParticles()) { int xt = Mth::floor(x); int yt = Mth::floor(y - 0.2f - heightOffset); int zt = Mth::floor(z); int t = level->getTile(xt, yt, zt); int d = level->getData(xt, yt, zt); if (t > 0) { 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); } }
updateInWaterState();
if (level->isClientSide) { onFire = 0; } else { if (onFire > 0) { if (fireImmune) { onFire -= 4; if (onFire < 0) onFire = 0; } else { if (onFire % 20 == 0) { hurt(DamageSource::onFire, 1); } onFire--; } } }
if (isInLava()) { lavaHurt(); fallDistance *= .5f; }
if (y < -64) { outOfWorld(); }
if (!level->isClientSide) { setSharedFlag(FLAG_ONFIRE, onFire > 0); }
firstTick = false;
// 4J Stu - Unused //util.Timer.pop();}
int Entity::getPortalWaitTime(){ return 0;}
void Entity::lavaHurt(){ if (fireImmune) { } else { hurt(DamageSource::lava, 4); setOnFire(15); }}
void Entity::setOnFire(int numberOfSeconds){ int newValue = numberOfSeconds * SharedConstants::TICKS_PER_SECOND; newValue = ProtectionEnchantment::getFireAfterDampener(shared_from_this(), newValue); if (onFire < newValue) { onFire = newValue; }}
void Entity::clearFire(){ onFire = 0;}
void Entity::outOfWorld(){ remove();}
bool Entity::isFree(float xa, float ya, float za, float grow){ AABB *box = bb->grow(grow, grow, grow)->cloneMove(xa, ya, za); AABBList *aABBs = level->getCubes(shared_from_this(), box); if (!aABBs->empty()) return false; if (level->containsAnyLiquid(box)) return false; return true;}
bool Entity::isFree(double xa, double ya, double za){ AABB *box = bb->cloneMove(xa, ya, za); AABBList *aABBs = level->getCubes(shared_from_this(), box); if (!aABBs->empty()) return false; if (level->containsAnyLiquid(box)) return false; return true;}
void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - added noEntityCubes parameter{ if (noPhysics) { bb->move(xa, ya, za); x = (bb->x0 + bb->x1) / 2.0f; y = bb->y0 + heightOffset - ySlideOffset; z = (bb->z0 + bb->z1) / 2.0f; return; }
ySlideOffset *= 0.4f;
double xo = x; double yo = y; double zo = z;
if (isStuckInWeb) { isStuckInWeb = false;
xa *= 0.25f; ya *= 0.05f; za *= 0.25f; xd = 0.0f; yd = 0.0f; zd = 0.0f; }
double xaOrg = xa; double yaOrg = ya; double zaOrg = za;
AABB *bbOrg = bb->copy();
bool isPlayerSneaking = onGround && isSneaking() && instanceof(eTYPE_PLAYER);
if (isPlayerSneaking) { double d = 0.05; while (xa != 0 && level->getCubes(shared_from_this(), bb->cloneMove(xa, -1.0, 0))->empty()) { if (xa < d && xa >= -d) xa = 0; else if (xa > 0) xa -= d; else xa += d; xaOrg = xa; } while (za != 0 && level->getCubes(shared_from_this(), bb->cloneMove(0, -1.0, za))->empty()) { if (za < d && za >= -d) za = 0; else if (za > 0) za -= d; else za += d; zaOrg = za; } while (xa != 0 && za != 0 && level->getCubes(shared_from_this(), bb->cloneMove(xa, -1.0, za))->empty()) { if (xa < d && xa >= -d) xa = 0; else if (xa > 0) xa -= d; else xa += d; if (za < d && za >= -d) za = 0; else if (za > 0) za -= d; else za += d; xaOrg = xa; zaOrg = za; } }
AABBList *aABBs = level->getCubes(shared_from_this(), bb->expand(xa, ya, za), noEntityCubes, true);
// LAND FIRST, then x and z AUTO_VAR(itEndAABB, aABBs->end());
// 4J Stu - Particles (and possibly other entities) don't have xChunk and zChunk set, so calculate the chunk instead int xc = Mth::floor(x / 16); int zc = Mth::floor(z / 16); if(!level->isClientSide || level->reallyHasChunk(xc, zc)) { // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk // data then all the collision info will be incorrect as well for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) ya = (*it)->clipYCollide(bb, ya); bb->move(0, ya, 0); }
if (!slide && yaOrg != ya) { xa = ya = za = 0; }
bool og = onGround || (yaOrg != ya && yaOrg < 0);
itEndAABB = aABBs->end(); for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) xa = (*it)->clipXCollide(bb, xa);
bb->move(xa, 0, 0);
if (!slide && xaOrg != xa) { xa = ya = za = 0; }
itEndAABB = aABBs->end(); for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) za = (*it)->clipZCollide(bb, za); bb->move(0, 0, za);
if (!slide && zaOrg != za) { xa = ya = za = 0; }
if (footSize > 0 && og && (isPlayerSneaking || ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za))) { double xaN = xa; double yaN = ya; double zaN = za;
xa = xaOrg; ya = footSize; za = zaOrg;
AABB *normal = bb->copy(); bb->set(bbOrg); // 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, // so we'd better include cubes under our feet in this list of things we might possibly collide with aABBs = level->getCubes(shared_from_this(), bb->expand(xa, ya, za)->expand(0,-ya,0),false,true);
// LAND FIRST, then x and z itEndAABB = aABBs->end();
if(!level->isClientSide || level->reallyHasChunk(xc, zc)) { // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk // data then all the collision info will be incorrect as well for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) ya = (*it)->clipYCollide(bb, ya); bb->move(0, ya, 0); }
if (!slide && yaOrg != ya) { xa = ya = za = 0; }
itEndAABB = aABBs->end(); for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) xa = (*it)->clipXCollide(bb, xa); bb->move(xa, 0, 0);
if (!slide && xaOrg != xa) { xa = ya = za = 0; }
itEndAABB = aABBs->end(); for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) za = (*it)->clipZCollide(bb, za); bb->move(0, 0, za);
if (!slide && zaOrg != za) { xa = ya = za = 0; }
if (!slide && yaOrg != ya) { xa = ya = za = 0; } else { ya = -footSize; // LAND FIRST, then x and z itEndAABB = aABBs->end(); for (AUTO_VAR(it, aABBs->begin()); it != itEndAABB; it++) ya = (*it)->clipYCollide(bb, ya); bb->move(0, ya, 0); }
if (xaN * xaN + zaN * zaN >= xa * xa + za * za) { xa = xaN; ya = yaN; za = zaN; bb->set(normal); } }
x = (bb->x0 + bb->x1) / 2.0f; y = bb->y0 + heightOffset - ySlideOffset; z = (bb->z0 + bb->z1) / 2.0f;
horizontalCollision = (xaOrg != xa) || (zaOrg != za); verticalCollision = !m_ignoreVerticalCollisions && (yaOrg != ya); onGround = !m_ignoreVerticalCollisions && yaOrg != ya && yaOrg < 0; collision = horizontalCollision || verticalCollision; checkFallDamage(ya, onGround);
if (xaOrg != xa) xd = 0; if (yaOrg != ya) yd = 0; if (zaOrg != za) zd = 0;
double xm = x - xo; double ym = y - yo; double zm = z - zo;
if (makeStepSound() && !isPlayerSneaking && riding == NULL) { int xt = Mth::floor(x); int yt = Mth::floor(y - 0.2f - heightOffset); int zt = Mth::floor(z); int t = level->getTile(xt, yt, zt); if (t == 0) { int renderShape = level->getTileRenderShape(xt, yt - 1, zt); if (renderShape == Tile::SHAPE_FENCE || renderShape == Tile::SHAPE_WALL || renderShape == Tile::SHAPE_FENCE_GATE) { t = level->getTile(xt, yt - 1, zt); } } if (t != Tile::ladder_Id) { ym = 0; }
walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6; moveDist += Mth::sqrt(xm * xm + ym * ym + zm * zm) * 0.6;
if (moveDist > nextStep && t > 0) { nextStep = (int) moveDist + 1; if (isInWater()) { float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.35f; if (speed > 1) speed = 1; playSound(eSoundType_LIQUID_SWIM, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); } playStepSound(xt, yt, zt, t); Tile::tiles[t]->stepOn(level, xt, yt, zt, shared_from_this()); } }
checkInsideTiles();
bool water = isInWaterOrRain(); if (level->containsFireTile(bb->shrink(0.001, 0.001, 0.001))) { burn(1); if (!water) { onFire++; if (onFire == 0) setOnFire(8); } } else { if (onFire <= 0) { onFire = -flameTime; } }
if (water && onFire > 0) { playSound(eSoundType_RANDOM_FIZZ, 0.7f, 1.6f + (random->nextFloat() - random->nextFloat()) * 0.4f); onFire = -flameTime; }}
void Entity::checkInsideTiles(){ int x0 = Mth::floor(bb->x0 + 0.001); int y0 = Mth::floor(bb->y0 + 0.001); int z0 = Mth::floor(bb->z0 + 0.001); int x1 = Mth::floor(bb->x1 - 0.001); int y1 = Mth::floor(bb->y1 - 0.001); int z1 = Mth::floor(bb->z1 - 0.001);
if (level->hasChunksAt(x0, y0, z0, x1, y1, z1)) { for (int x = x0; x <= x1; x++) for (int y = y0; y <= y1; y++) for (int z = z0; z <= z1; z++) { int t = level->getTile(x, y, z); if (t > 0) { Tile::tiles[t]->entityInside(level, x, y, z, shared_from_this()); } } }}
void Entity::playStepSound(int xt, int yt, int zt, int t){ const Tile::SoundType *soundType = Tile::tiles[t]->soundType; MemSect(31);
if (GetType() == eTYPE_PLAYER) { // should we turn off step sounds? unsigned int uiAnimOverrideBitmask=getAnimOverrideBitmask(); // this is masked for custom anim off, and force anim
if(( uiAnimOverrideBitmask& (1<<HumanoidModel::eAnim_NoLegAnim))!=0) { return; }
} if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) { soundType = Tile::topSnow->soundType; playSound(soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); } else if (!Tile::tiles[t]->material->isLiquid()) { playSound(soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); }
MemSect(0);}
void Entity::playSound(int iSound, float volume, float pitch){ level->playEntitySound(shared_from_this(), iSound, volume, pitch);}
bool Entity::makeStepSound(){ return true;}
void Entity::checkFallDamage(double ya, bool onGround){ if (onGround) { if (fallDistance > 0) { causeFallDamage(fallDistance); fallDistance = 0; } } else { if (ya < 0) fallDistance -= (float) ya; }}
AABB *Entity::getCollideBox(){ return NULL;}
void Entity::burn(int dmg){ if (!fireImmune) { hurt(DamageSource::inFire, dmg); }}
bool Entity::isFireImmune(){ return fireImmune;}
void Entity::causeFallDamage(float distance){ if (rider.lock() != NULL) rider.lock()->causeFallDamage(distance);}
bool Entity::isInWaterOrRain(){ 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)));}
bool Entity::isInWater(){ return wasInWater;}
bool Entity::updateInWaterState(){ if(level->checkAndHandleWater(bb->grow(0, -0.4f, 0)->shrink(0.001, 0.001, 0.001), Material::water, shared_from_this())) { if (!wasInWater && !firstTick && canCreateParticles()) { float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f; if (speed > 1) speed = 1; MemSect(31); playSound(eSoundType_RANDOM_SPLASH, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); MemSect(0); float yt = (float) Mth::floor(bb->y0); for (int i = 0; i < 1 + bbWidth * 20; i++) { float xo = (random->nextFloat() * 2 - 1) * bbWidth; float zo = (random->nextFloat() * 2 - 1) * bbWidth; level->addParticle(eParticleType_bubble, x + xo, yt + 1, z + zo, xd, yd - random->nextFloat() * 0.2f, zd); } for (int i = 0; i < 1 + bbWidth * 20; i++) { float xo = (random->nextFloat() * 2 - 1) * bbWidth; float zo = (random->nextFloat() * 2 - 1) * bbWidth; level->addParticle(eParticleType_splash, x + xo, yt + 1, z + zo, xd, yd, zd); } } fallDistance = 0; wasInWater = true; onFire = 0; } else { wasInWater = false; } return wasInWater;}
bool Entity::isUnderLiquid(Material *material){ double yp = y + getHeadHeight(); int xt = Mth::floor(x); int yt = Mth::floor(yp); // 4J - this used to be a nested pair of floors for some reason int zt = Mth::floor(z); int t = level->getTile(xt, yt, zt); if (t != 0 && Tile::tiles[t]->material == material) { float hh = LiquidTile::getHeight(level->getData(xt, yt, zt)) - 1 / 9.0f; float h = yt + 1 - hh; return yp < h; } return false;}
float Entity::getHeadHeight(){ return 0;}
bool Entity::isInLava(){ return level->containsMaterial(bb->grow(-0.1f, -0.4f, -0.1f), Material::lava);}
void Entity::moveRelative(float xa, float za, float speed){ float dist = xa * xa + za * za; if (dist < 0.01f * 0.01f) return;
dist = sqrt(dist); if (dist < 1) dist = 1; dist = speed / dist; xa *= dist; za *= dist;
float sinVar = Mth::sin(yRot * PI / 180); float cosVar = Mth::cos(yRot * PI / 180);
xd += xa * cosVar - za * sinVar; zd += za * cosVar + xa * sinVar;}
// 4J - change brought forward from 1.8.2int Entity::getLightColor(float a){ int xTile = Mth::floor(x); int zTile = Mth::floor(z);
if (level->hasChunkAt(xTile, 0, zTile)) { double hh = (bb->y1 - bb->y0) * 0.66; int yTile = Mth::floor(y - heightOffset + hh); return level->getLightColor(xTile, yTile, zTile, 0); } return 0;}
// 4J - changes brought forward from 1.8.2float Entity::getBrightness(float a){ int xTile = Mth::floor(x); int zTile = Mth::floor(z); if (level->hasChunkAt(xTile, 0, zTile)) { double hh = (bb->y1 - bb->y0) * 0.66; int yTile = Mth::floor(y - heightOffset + hh); return level->getBrightness(xTile, yTile, zTile); } return 0;}
void Entity::setLevel(Level *level){ this->level = level;}
void Entity::absMoveTo(double x, double y, double z, float yRot, float xRot){ xo = this->x = x; yo = this->y = y; zo = this->z = z; yRotO = this->yRot = yRot; xRotO = this->xRot = xRot; ySlideOffset = 0;
double yRotDiff = yRotO - yRot; if (yRotDiff < -180) yRotO += 360; if (yRotDiff >= 180) yRotO -= 360; setPos(this->x, this->y, this->z); setRot(yRot, xRot);}
void Entity::moveTo(double x, double y, double z, float yRot, float xRot){ xOld = xo = this->x = x; yOld = yo = this->y = y + heightOffset; zOld = zo = this->z = z; this->yRot = yRot; this->xRot = xRot; setPos(this->x, this->y, this->z);}
float Entity::distanceTo(shared_ptr<Entity> e){ float xd = (float) (x - e->x); float yd = (float) (y - e->y); float zd = (float) (z - e->z); return sqrt(xd * xd + yd * yd + zd * zd);}
double Entity::distanceToSqr(double x2, double y2, double z2){ double xd = (x - x2); double yd = (y - y2); double zd = (z - z2); return xd * xd + yd * yd + zd * zd;}
double Entity::distanceTo(double x2, double y2, double z2){ double xd = (x - x2); double yd = (y - y2); double zd = (z - z2); return sqrt(xd * xd + yd * yd + zd * zd);}
double Entity::distanceToSqr(shared_ptr<Entity> e){ double xd = x - e->x; double yd = y - e->y; double zd = z - e->z; return xd * xd + yd * yd + zd * zd;}
void Entity::playerTouch(shared_ptr<Player> player){}
void Entity::push(shared_ptr<Entity> e){ if (e->rider.lock().get() == this || e->riding.get() == this) return;
double xa = e->x - x; double za = e->z - z;
double dd = Mth::asbMax(xa, za);
if (dd >= 0.01f) { dd = sqrt(dd); xa /= dd; za /= dd;
double pow = 1 / dd; if (pow > 1) pow = 1; xa *= pow; za *= pow;
xa *= 0.05f; za *= 0.05f;
xa *= 1 - pushthrough; za *= 1 - pushthrough;
push(-xa, 0, -za); e->push(xa, 0, za); }}
void Entity::push(double xa, double ya, double za){ xd += xa; yd += ya; zd += za; hasImpulse = true;}
void Entity::markHurt(){ hurtMarked = true;}
bool Entity::hurt(DamageSource *source, float damage){ if(isInvulnerable()) return false; markHurt(); return false;}
bool Entity::intersects(double x0, double y0, double z0, double x1, double y1, double z1){ return bb->intersects(x0, y0, z0, x1, y1, z1);}
bool Entity::isPickable(){ return false;}
bool Entity::isPushable(){ return false;}
bool Entity::isShootable(){ return false;}
void Entity::awardKillScore(shared_ptr<Entity> victim, int score){}
bool Entity::shouldRender(Vec3 *c){ double xd = x - c->x; double yd = y - c->y; double zd = z - c->z; double distance = xd * xd + yd * yd + zd * zd; return shouldRenderAtSqrDistance(distance);}
bool Entity::shouldRenderAtSqrDistance(double distance){ double size = bb->getSize(); size *= 64.0f * viewScale; return distance < size * size;}
bool Entity::isCreativeModeAllowed(){ return false;}
bool Entity::saveAsMount(CompoundTag *entityTag){ wstring id = getEncodeId(); if (removed || id.empty() ) { return false; } // TODO Is this fine to be casting to a non-const char pointer? entityTag->putString(L"id", id ); saveWithoutId(entityTag); return true;}
bool Entity::save(CompoundTag *entityTag){ wstring id = getEncodeId(); if (removed || id.empty() || (rider.lock() != NULL) ) { return false; } // TODO Is this fine to be casting to a non-const char pointer? entityTag->putString(L"id", id ); saveWithoutId(entityTag); return true;}
void Entity::saveWithoutId(CompoundTag *entityTag){ entityTag->put(L"Pos", newDoubleList(3, x, y + ySlideOffset, z)); entityTag->put(L"Motion", newDoubleList(3, xd, yd, zd)); entityTag->put(L"Rotation", newFloatList(2, yRot, xRot));
entityTag->putFloat(L"FallDistance", fallDistance); entityTag->putShort(L"Fire", (short) onFire); entityTag->putShort(L"Air", (short) getAirSupply()); entityTag->putBoolean(L"OnGround", onGround); entityTag->putInt(L"Dimension", dimension); entityTag->putBoolean(L"Invulnerable", invulnerable); entityTag->putInt(L"PortalCooldown", changingDimensionDelay);
entityTag->putString(L"UUID", uuid);
addAdditonalSaveData(entityTag);
if (riding != NULL) { CompoundTag *ridingTag = new CompoundTag(RIDING_TAG); if (riding->saveAsMount(ridingTag)) { entityTag->put(L"Riding", ridingTag); } }}
void Entity::load(CompoundTag *tag){ ListTag<DoubleTag> *pos = (ListTag<DoubleTag> *) tag->getList(L"Pos"); ListTag<DoubleTag> *motion = (ListTag<DoubleTag> *) tag->getList(L"Motion"); ListTag<FloatTag> *rotation = (ListTag<FloatTag> *) tag->getList(L"Rotation");
xd = motion->get(0)->data; yd = motion->get(1)->data; zd = motion->get(2)->data;
if (abs(xd) > 10.0) { xd = 0; } if (abs(yd) > 10.0) { yd = 0; } if (abs(zd) > 10.0) { zd = 0; }
xo = xOld = x = pos->get(0)->data; yo = yOld = y = pos->get(1)->data; zo = zOld = z = pos->get(2)->data;
yRotO = yRot = rotation->get(0)->data; xRotO = xRot = rotation->get(1)->data;
fallDistance = tag->getFloat(L"FallDistance"); onFire = tag->getShort(L"Fire"); setAirSupply(tag->getShort(L"Air")); onGround = tag->getBoolean(L"OnGround"); dimension = tag->getInt(L"Dimension"); invulnerable = tag->getBoolean(L"Invulnerable"); changingDimensionDelay = tag->getInt(L"PortalCooldown");
if (tag->contains(L"UUID")) { uuid = tag->getString(L"UUID"); }
setPos(x, y, z); setRot(yRot, xRot);
readAdditionalSaveData(tag);
// set position again because bb size may have changed if (repositionEntityAfterLoad()) setPos(x, y, z);}
bool Entity::repositionEntityAfterLoad(){ return true;}
const wstring Entity::getEncodeId(){ return EntityIO::getEncodeId( shared_from_this() );}
/*** Called after load() has finished and the entity has been added to the* world*/void Entity::onLoadedFromSave(){
}
template<typename ...Args>ListTag<DoubleTag> *Entity::newDoubleList(unsigned int, double firstValue, Args... args){ ListTag<DoubleTag> *res = new ListTag<DoubleTag>();
// Add the first parameter to the ListTag res->add( new DoubleTag(L"", firstValue ) );
// use pre-C++17 fold trick (TODO: once we drop C++14 support, use C++14 fold expression) using expander = int[]; (void)expander{0, (res->add(new DoubleTag(L"", static_cast<double>(args))), 0)...};
return res;}
ListTag<FloatTag> *Entity::newFloatList(unsigned int number, float firstValue, float secondValue){ ListTag<FloatTag> *res = new ListTag<FloatTag>();
// Add the first parameter to the ListTag res->add( new FloatTag( L"", firstValue ) );
// TODO - 4J Stu For some reason the va_list wasn't working correctly here // We only make a list of two floats so just overriding and not using va_list res->add( new FloatTag( L"", secondValue ) );
/* va_list vl; va_start(vl,firstValue);
float val;
for (unsigned int i = 1; i < number; i++) { val = va_arg(vl,float); res->add(new FloatTag(val)); } va_end(vl); */ return res;}
float Entity::getShadowHeightOffs(){ return bbHeight / 2;}
shared_ptr<ItemEntity> Entity::spawnAtLocation(int resource, int count){ return spawnAtLocation(resource, count, 0);}
shared_ptr<ItemEntity> Entity::spawnAtLocation(int resource, int count, float yOffs){ return spawnAtLocation(shared_ptr<ItemInstance>( new ItemInstance(resource, count, 0) ), yOffs);}
shared_ptr<ItemEntity> Entity::spawnAtLocation(shared_ptr<ItemInstance> itemInstance, float yOffs){ if (itemInstance->count == 0) { return nullptr; } shared_ptr<ItemEntity> ie = shared_ptr<ItemEntity>( new ItemEntity(level, x, y + yOffs, z, itemInstance) ); ie->throwTime = 10; level->addEntity(ie); return ie;}
bool Entity::isAlive(){ return !removed;}
bool Entity::isInWall(){ for (int i = 0; i < 8; i++) { float xo = ((i >> 0) % 2 - 0.5f) * bbWidth * 0.8f; float yo = ((i >> 1) % 2 - 0.5f) * 0.1f; float zo = ((i >> 2) % 2 - 0.5f) * bbWidth * 0.8f; int xt = Mth::floor(x + xo); int yt = Mth::floor(y + getHeadHeight() + yo); int zt = Mth::floor(z + zo); if (level->isSolidBlockingTile(xt, yt, zt)) { return true; } } return false;}
bool Entity::interact(shared_ptr<Player> player){ return false;}
AABB *Entity::getCollideAgainstBox(shared_ptr<Entity> entity){ return NULL;}
void Entity::rideTick(){ if (riding->removed) { riding = nullptr; return; } xd = yd = zd = 0; tick();
if (riding == NULL) return;
// Sets riders old&new position to it's mount's old&new position (plus the ride y-seperatation). riding->positionRider();
yRideRotA += (riding->yRot - riding->yRotO); xRideRotA += (riding->xRot - riding->xRotO);
// Wrap rotation angles. while (yRideRotA >= 180) yRideRotA -= 360; while (yRideRotA < -180) yRideRotA += 360; while (xRideRotA >= 180) xRideRotA -= 360; while (xRideRotA < -180) xRideRotA += 360;
double yra = yRideRotA * 0.5; double xra = xRideRotA * 0.5;
// Cap rotation speed. float max = 10; if (yra > max) yra = max; if (yra < -max) yra = -max; if (xra > max) xra = max; if (xra < -max) xra = -max;
yRideRotA -= yra; xRideRotA -= xra;
// jeb: This caused the crosshair to "drift" while riding horses. For now I've just disabled it, // because I can't figure out what it's needed for. Riding boats and minecarts seem unaffected... // yRot += yra; // xRot += xra;}
void Entity::positionRider(){ shared_ptr<Entity> lockedRider = rider.lock(); if( lockedRider == NULL) { return; } lockedRider->setPos(x, y + getRideHeight() + lockedRider->getRidingHeight(), z);}
double Entity::getRidingHeight(){ return heightOffset;}
double Entity::getRideHeight(){ return bbHeight * .75;}
void Entity::ride(shared_ptr<Entity> e){ xRideRotA = 0; yRideRotA = 0;
if (e == NULL) { if (riding != NULL) { // 4J Stu - Position should already be updated before the SetEntityLinkPacket comes in if(!level->isClientSide) moveTo(riding->x, riding->bb->y0 + riding->bbHeight, riding->z, yRot, xRot); riding->rider = weak_ptr<Entity>(); } riding = nullptr; return; } if (riding != NULL) { riding->rider = weak_ptr<Entity>(); } riding = e; e->rider = shared_from_this();}
void Entity::lerpTo(double x, double y, double z, float yRot, float xRot, int steps){ setPos(x, y, z); setRot(yRot, xRot);
// 4J - don't know what this special y collision is specifically for, but its definitely bad news // for arrows as they are actually Meant to intersect the geometry they land in slightly. if( GetType() != eTYPE_ARROW ) { AABBList *collisions = level->getCubes(shared_from_this(), bb->shrink(1 / 32.0, 0, 1 / 32.0)); if (!collisions->empty()) { double yTop = 0; AUTO_VAR(itEnd, collisions->end()); for (AUTO_VAR(it, collisions->begin()); it != itEnd; it++) { AABB *ab = *it; //collisions->at(i); if (ab->y1 > yTop) yTop = ab->y1; }
y += yTop - bb->y0; setPos(x, y, z); } }}
float Entity::getPickRadius(){ return 0.1f;}
Vec3 *Entity::getLookAngle(){ return NULL;}
void Entity::handleInsidePortal(){ if (changingDimensionDelay > 0) { changingDimensionDelay = getDimensionChangingDelay(); return; }
double xd = xo - x; double zd = zo - z;
if (!level->isClientSide && !isInsidePortal) { portalEntranceDir = Direction::getDirection(xd, zd); }
isInsidePortal = true;}
int Entity::getDimensionChangingDelay(){ return SharedConstants::TICKS_PER_SECOND * 45;}
void Entity::lerpMotion(double xd, double yd, double zd){ this->xd = xd; this->yd = yd; this->zd = zd;}
void Entity::handleEntityEvent(byte eventId){}
void Entity::animateHurt(){}
ItemInstanceArray Entity::getEquipmentSlots() // ItemInstance[]{ return ItemInstanceArray(); // Default ctor creates NULL internal array}
// 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 gamevoid Entity::setEquippedSlot(int slot, shared_ptr<ItemInstance> item){}
bool Entity::isOnFire(){ return !fireImmune && (onFire > 0 || getSharedFlag(FLAG_ONFIRE));}
bool Entity::isRiding(){ return riding != NULL;}
bool Entity::isSneaking(){ return getSharedFlag(FLAG_SNEAKING);}
void Entity::setSneaking(bool value){ setSharedFlag(FLAG_SNEAKING, value);}
bool Entity::isIdle(){ return getSharedFlag(FLAG_IDLEANIM);}
void Entity::setIsIdle(bool value){ setSharedFlag(FLAG_IDLEANIM, value);}
bool Entity::isSprinting(){ return getSharedFlag(FLAG_SPRINTING);}
void Entity::setSprinting(bool value){ setSharedFlag(FLAG_SPRINTING, value);}
bool Entity::isInvisible(){ return getSharedFlag(FLAG_INVISIBLE);}
bool Entity::isInvisibleTo(shared_ptr<Player> plr){ return isInvisible();}
void Entity::setInvisible(bool value){ setSharedFlag(FLAG_INVISIBLE, value);}
bool Entity::isWeakened(){ return getSharedFlag(FLAG_EFFECT_WEAKENED);}
void Entity::setWeakened(bool value){ setSharedFlag(FLAG_EFFECT_WEAKENED, value);}
bool Entity::isUsingItemFlag(){ return getSharedFlag(FLAG_USING_ITEM);}
void Entity::setUsingItemFlag(bool value){ setSharedFlag(FLAG_USING_ITEM, value);}
bool Entity::getSharedFlag(int flag){ if( entityData ) { return (entityData->getByte(DATA_SHARED_FLAGS_ID) & (1 << flag)) != 0; } else { return false; }}
void Entity::setSharedFlag(int flag, bool value){ if( entityData ) { byte currentValue = entityData->getByte(DATA_SHARED_FLAGS_ID); if (value) { entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue | (1 << flag))); } else { entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue & ~(1 << flag))); } }}
// 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.int Entity::getAirSupply(){ return entityData->getShort(DATA_AIR_SUPPLY_ID);}
// 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.void Entity::setAirSupply(int supply){ entityData->set(DATA_AIR_SUPPLY_ID, (short) supply);}
void Entity::thunderHit(const LightningBolt *lightningBolt){ burn(5); onFire++; if (onFire == 0) setOnFire(8);}
void Entity::killed(shared_ptr<LivingEntity> mob){}
bool Entity::checkInTile(double x, double y, double z){ int xTile = Mth::floor(x); int yTile = Mth::floor(y); int zTile = Mth::floor(z);
double xd = x - (xTile); double yd = y - (yTile); double zd = z - (zTile);
vector<AABB *> *cubes = level->getTileCubes(bb); if ( (cubes && !cubes->empty()) || level->isFullAABBTile(xTile, yTile, zTile)) { bool west = !level->isFullAABBTile(xTile - 1, yTile, zTile); bool east = !level->isFullAABBTile(xTile + 1, yTile, zTile); bool down = !level->isFullAABBTile(xTile, yTile - 1, zTile); bool up = !level->isFullAABBTile(xTile, yTile + 1, zTile); bool north = !level->isFullAABBTile(xTile, yTile, zTile - 1); bool south = !level->isFullAABBTile(xTile, yTile, zTile + 1);
int dir = 3; double closest = 9999; if (west && xd < closest) { closest = xd; dir = 0; } if (east && 1 - xd < closest) { closest = 1 - xd; dir = 1; } if (up && 1 - yd < closest) { closest = 1 - yd; dir = 3; } if (north && zd < closest) { closest = zd; dir = 4; } if (south && 1 - zd < closest) { closest = 1 - zd; dir = 5; }
float speed = random->nextFloat() * 0.2f + 0.1f; if (dir == 0) this->xd = -speed; if (dir == 1) this->xd = +speed;
if (dir == 2) this->yd = -speed; if (dir == 3) this->yd = +speed;
if (dir == 4) this->zd = -speed; if (dir == 5) this->zd = +speed;
return true; } return false;}
void Entity::makeStuckInWeb(){ isStuckInWeb = true; fallDistance = 0;}
wstring Entity::getAName(){#ifdef _DEBUG wstring id = EntityIO::getEncodeId(shared_from_this()); if (id.empty()) id = L"generic"; return L"entity." + id + _toString(entityId);#else return L"";#endif}
vector<shared_ptr<Entity> > *Entity::getSubEntities(){ return NULL;}
bool Entity::is(shared_ptr<Entity> other){ return shared_from_this() == other;}
float Entity::getYHeadRot(){ return 0;}
void Entity::setYHeadRot(float yHeadRot){}
bool Entity::isAttackable(){ return true;}
bool Entity::skipAttackInteraction(shared_ptr<Entity> source){ return false;}
bool Entity::isInvulnerable(){ return invulnerable;}
void Entity::copyPosition(shared_ptr<Entity> target){ moveTo(target->x, target->y, target->z, target->yRot, target->xRot);}
void Entity::restoreFrom(shared_ptr<Entity> oldEntity, bool teleporting){ CompoundTag *tag = new CompoundTag(); oldEntity->saveWithoutId(tag); load(tag); delete tag; changingDimensionDelay = oldEntity->changingDimensionDelay; portalEntranceDir = oldEntity->portalEntranceDir;}
void Entity::changeDimension(int i){ if (level->isClientSide || removed) return;
MinecraftServer *server = MinecraftServer::getInstance(); int lastDimension = dimension; ServerLevel *oldLevel = server->getLevel(lastDimension); ServerLevel *newLevel = server->getLevel(i);
if (lastDimension == 1 && i == 1) { newLevel = server->getLevel(0); }
// 4J: Restrictions on what can go through { // 4J: Some things should just be destroyed when they hit a portal if (instanceof(eTYPE_FALLINGTILE)) { removed = true; return; }
// 4J: Check server level entity limit (arrows, item entities, experience orbs, etc) if (newLevel->atEntityLimit(shared_from_this())) return;
// 4J: Check level limit on living entities, minecarts and boats if (!instanceof(eTYPE_PLAYER) && !newLevel->canCreateMore(GetType(), Level::eSpawnType_Portal)) return; }
// 4J: Definitely sending, set dimension now dimension = newLevel->dimension->id;
level->removeEntity(shared_from_this()); removed = false;
server->getPlayers()->repositionAcrossDimension(shared_from_this(), lastDimension, oldLevel, newLevel); shared_ptr<Entity> newEntity = EntityIO::newEntity(EntityIO::getEncodeId(shared_from_this()), newLevel);
if (newEntity != NULL) { newEntity->restoreFrom(shared_from_this(), true);
if (lastDimension == 1 && i == 1) { Pos *spawnPos = newLevel->getSharedSpawnPos(); spawnPos->y = level->getTopSolidBlock(spawnPos->x, spawnPos->z); newEntity->moveTo(spawnPos->x, spawnPos->y, spawnPos->z, newEntity->yRot, newEntity->xRot); delete spawnPos; }
newLevel->addEntity(newEntity); }
removed = true;
oldLevel->resetEmptyTime(); newLevel->resetEmptyTime();}
float Entity::getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile){ return tile->getExplosionResistance(shared_from_this());}
bool Entity::shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power){ return true;}
int Entity::getMaxFallDistance(){ return 3;}
int Entity::getPortalEntranceDir(){ return portalEntranceDir;}
bool Entity::isIgnoringTileTriggers(){ return false;}
bool Entity::displayFireAnimation(){ return isOnFire();}
void Entity::setUUID(const wstring &UUID){ uuid = UUID;}
wstring Entity::getUUID(){ return uuid;}
bool Entity::isPushedByWater(){ return true;}
wstring Entity::getDisplayName(){ return getAName();}
// 4J: Added to retrieve name that should be sent in ChatPackets (important on Xbox One for players)wstring Entity::getNetworkName(){ return getDisplayName();}
void Entity::setAnimOverrideBitmask(unsigned int uiBitmask){ m_uiAnimOverrideBitmask=uiBitmask; app.DebugPrintf("!!! Setting anim override bitmask to %d\n",uiBitmask);}unsigned int Entity::getAnimOverrideBitmask(){ if(app.GetGameSettings(eGameSetting_CustomSkinAnim)==0 ) { // We have a force animation for some skins (claptrap) // 4J-PB - treat all the eAnim_Disable flags as a force anim unsigned int uiIgnoreUserCustomSkinAnimSettingMask=(1<<HumanoidModel::eAnim_ForceAnim) | (1<<HumanoidModel::eAnim_DisableRenderArm0) | (1<<HumanoidModel::eAnim_DisableRenderArm1) | (1<<HumanoidModel::eAnim_DisableRenderTorso) | (1<<HumanoidModel::eAnim_DisableRenderLeg0) | (1<<HumanoidModel::eAnim_DisableRenderLeg1) | (1<<HumanoidModel::eAnim_DisableRenderHair);
if((m_uiAnimOverrideBitmask & HumanoidModel::m_staticBitmaskIgnorePlayerCustomAnimSetting)!=0) { return m_uiAnimOverrideBitmask; } return 0; }
return m_uiAnimOverrideBitmask;}