diff options
| author | daoge <3523206925@qq.com> | 2026-03-03 03:04:10 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-03 03:04:10 +0800 |
| commit | b3feddfef372618c8a9d7a0abcaf18cfad866c18 (patch) | |
| tree | 267761c3bb39241ba5c347bfbe2254d06686e287 /Minecraft.World/Minecart.cpp | |
| parent | 84c31a2331f7a0ec85b9d438992e244f60e5020f (diff) | |
feat: TU19 (Dec 2014) Features & Content (#155)
* try to resolve merge conflict
* feat: TU19 (Dec 2014) Features & Content (#32)
* December 2014 files
* Working release build
* Fix compilation issues
* Add sound to Windows64Media
* Add DLC content and force Tutorial DLC
* Revert "Add DLC content and force Tutorial DLC"
This reverts commit 97a43994725008e35fceb984d5549df9c8cea470.
* Disable broken light packing
* Disable breakpoint during DLC texture map load
Allows DLC loading but the DLC textures are still broken
* Fix post build not working
* ...
* fix vs2022 build
* fix cmake build
---------
Co-authored-by: Loki <lokirautio@gmail.com>
Diffstat (limited to 'Minecraft.World/Minecart.cpp')
| -rw-r--r-- | Minecraft.World/Minecart.cpp | 1127 |
1 files changed, 479 insertions, 648 deletions
diff --git a/Minecraft.World/Minecart.cpp b/Minecraft.World/Minecart.cpp index 2b8fbb95..48787f55 100644 --- a/Minecraft.World/Minecart.cpp +++ b/Minecraft.World/Minecart.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" @@ -8,6 +9,8 @@ #include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.damagesource.h" +#include "..\Minecraft.Client\MinecraftServer.h" +#include "..\Minecraft.Client\ServerLevel.h" #include "com.mojang.nbt.h" #include "Minecart.h" #include "SharedConstants.h" @@ -16,89 +19,23 @@ const int Minecart::EXITS[][2][3] = { // // - { - { - +0, +0, -1 - }, { - +0, +0, +1 - } - }, // 0 - { - { - -1, +0, +0 - }, { - +1, +0, +0 - } - }, // 1 - { - { - -1, -1, +0 - }, { - +1, +0, +0 - } - }, // 2 - { - { - -1, +0, +0 - }, { - +1, -1, +0 - } - }, // 3 - { - { - +0, +0, -1 - }, { - +0, -1, +1 - } - }, // 4 - { - { - +0, -1, -1 - }, { - +0, +0, +1 - } - }, // 5 - - { - { - +0, +0, +1 - }, { - +1, +0, +0 - } - }, // 6 - { - { - +0, +0, +1 - }, { - -1, +0, +0 - } - }, // 7 - { - { - +0, +0, -1 - }, { - -1, +0, +0 - } - }, // 8 - { - { - +0, +0, -1 - }, { - +1, +0, +0 - } - }, // 9 + {{+0, +0, -1}, {+0, +0, +1}}, // 0 + {{-1, +0, +0}, {+1, +0, +0}}, // 1 + {{-1, -1, +0}, {+1, +0, +0}}, // 2 + {{-1, +0, +0}, {+1, -1, +0}}, // 3 + {{+0, +0, -1}, {+0, -1, +1}}, // 4 + {{+0, -1, -1}, {+0, +0, +1}}, // 5 + + {{+0, +0, +1}, {+1, +0, +0}}, // 6 + {{+0, +0, +1}, {-1, +0, +0}}, // 7 + {{+0, +0, -1}, {-1, +0, +0}}, // 8 + {{+0, +0, -1}, {+1, +0, +0}}, // 9 }; void Minecart::_init() { - // 4J TODO This gets replaced again later so should maybe be inited as NULL? - items = new ItemInstanceArray(9 * 4); - flipped = false; - type = fuel = 0; - xPush = zPush = 0.0; - lSteps = 0; lx = ly = lz = lyr = lxr = 0.0; lxd = lyd = lzd = 0.0; @@ -107,6 +44,8 @@ void Minecart::_init() blocksBuilding = true; setSize(0.98f, 0.7f); heightOffset = bbHeight / 2.0f; + soundUpdater = NULL; + name = L""; // // 4J Added @@ -115,13 +54,34 @@ void Minecart::_init() Minecart::Minecart(Level *level) : Entity( level ) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that - // the derived version of the function is called - this->defineSynchedData(); - _init(); + + //soundUpdater = level != NULL ? level->makeSoundUpdater(this) : NULL; } +Minecart::~Minecart() +{ + delete soundUpdater; +} + +shared_ptr<Minecart> Minecart::createMinecart(Level *level, double x, double y, double z, int type) +{ + switch (type) + { + case TYPE_CHEST: + return shared_ptr<MinecartChest>( new MinecartChest(level, x, y, z) ); + case TYPE_FURNACE: + return shared_ptr<MinecartFurnace>( new MinecartFurnace(level, x, y, z) ); + case TYPE_TNT: + return shared_ptr<MinecartTNT>( new MinecartTNT(level, x, y, z) ); + case TYPE_SPAWNER: + return shared_ptr<MinecartSpawner>( new MinecartSpawner(level, x, y, z) ); + case TYPE_HOPPER: + return shared_ptr<MinecartHopper>( new MinecartHopper(level, x, y, z) ); + default: + return shared_ptr<MinecartRideable>( new MinecartRideable(level, x, y, z) ); + } +} bool Minecart::makeStepSound() { @@ -130,21 +90,26 @@ bool Minecart::makeStepSound() void Minecart::defineSynchedData() { - entityData->define(DATA_ID_FUEL, (byte) 0); entityData->define(DATA_ID_HURT, 0); entityData->define(DATA_ID_HURTDIR, 1); - entityData->define(DATA_ID_DAMAGE, 0); + entityData->define(DATA_ID_DAMAGE, 0.0f); + entityData->define(DATA_ID_DISPLAY_TILE, 0); + entityData->define(DATA_ID_DISPLAY_OFFSET, 6); + entityData->define(DATA_ID_CUSTOM_DISPLAY, (byte) 0); } AABB *Minecart::getCollideAgainstBox(shared_ptr<Entity> entity) { - return entity->bb; + if (entity->isPushable()) + { + return entity->bb; + } + return NULL; } AABB *Minecart::getCollideBox() { - // if (level->isClientSide) return NULL; return NULL; } @@ -153,14 +118,11 @@ bool Minecart::isPushable() return true; } -Minecart::Minecart(Level *level, double x, double y, double z, int type) : Entity( level ) +Minecart::Minecart(Level *level, double x, double y, double z) : Entity( level ) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that - // the derived version of the function is called - this->defineSynchedData(); _init(); - setPos(x, y + heightOffset, z); + setPos(x, y, z); xd = 0; yd = 0; @@ -169,7 +131,6 @@ Minecart::Minecart(Level *level, double x, double y, double z, int type) : Entit xo = x; yo = y; zo = z; - this->type = type; } double Minecart::getRideHeight() @@ -177,88 +138,65 @@ double Minecart::getRideHeight() return bbHeight * 0.0 - 0.3f; } -bool Minecart::hurt(DamageSource *source, int hurtDamage) +bool Minecart::hurt(DamageSource *source, float hurtDamage) { if (level->isClientSide || removed) return true; - + if (isInvulnerable()) return false; + // 4J-JEV: Fix for #88212, // Untrusted players shouldn't be able to damage minecarts or boats. if (dynamic_cast<EntityDamageSource *>(source) != NULL) { shared_ptr<Entity> attacker = source->getDirectEntity(); - if (dynamic_pointer_cast<Player>(attacker) != NULL && - !dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity( shared_from_this() )) + if ( attacker->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast<Player>(attacker)->isAllowedToHurtEntity( shared_from_this() )) + { return false; + } } setHurtDir(-getHurtDir()); setHurtTime(10); markHurt(); + setDamage(getDamage() + (hurtDamage * 10)); // 4J Stu - If someone is riding in this, then it can tick multiple times which causes the damage to // decrease too quickly. So just make the damage a bit higher to start with for similar behaviour // to an unridden one. Only do this change if the riding player is attacking it. if( rider.lock() != NULL && rider.lock() == source->getEntity() ) hurtDamage += 1; - // 4J Stu - Brought froward from 12w36 to fix #46611 - TU5: Gameplay: Minecarts and boat requires more hits than one to be destroyed in creative mode - shared_ptr<Player> player = dynamic_pointer_cast<Player>(source->getEntity()); - if (player != NULL && player->abilities.instabuild) this->setDamage(100); + bool creativePlayer = source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) && dynamic_pointer_cast<Player>(source->getEntity())->abilities.instabuild; - this->setDamage(getDamage() + (hurtDamage * 10)); - if (this->getDamage() > 20 * 2) + if (creativePlayer || getDamage() > 20 * 2) { // 4J HEG - Fixed issue with player falling through the ground on destroying a minecart while riding (issue #160607) if (rider.lock() != NULL) rider.lock()->ride(nullptr); - remove(); - spawnAtLocation(Item::minecart->id, 1, 0); - if (type == Minecart::CHEST) + if (!creativePlayer || hasCustomName()) { - shared_ptr<Container> container = dynamic_pointer_cast<Container>( shared_from_this() ); - for (unsigned int i = 0; i < container->getContainerSize(); i++) - { - shared_ptr<ItemInstance> item = container->getItem(i); - if (item != NULL) - { - float xo = random->nextFloat() * 0.8f + 0.1f; - float yo = random->nextFloat() * 0.8f + 0.1f; - float zo = random->nextFloat() * 0.8f + 0.1f; - - while (item->count > 0) - { - int count = random->nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - - shared_ptr<ItemEntity> itemEntity = shared_ptr<ItemEntity>( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr<ItemInstance>( new ItemInstance(item->id, count, item->getAuxValue()) ) ) ); - float pow = 0.05f; - itemEntity->xd = (float) random->nextGaussian() * pow; - itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; - itemEntity->zd = (float) random->nextGaussian() * pow; - if (item->hasTag()) - { - itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); - } - level->addEntity(itemEntity); - } - } - } - spawnAtLocation(Tile::chest_Id, 1, 0); + destroy(source); } - else if (type == Minecart::FURNACE) + else { - spawnAtLocation(Tile::furnace_Id, 1, 0); + remove(); } } return true; } +void Minecart::destroy(DamageSource *source) +{ + remove(); + shared_ptr<ItemInstance> item = shared_ptr<ItemInstance>( new ItemInstance(Item::minecart, 1) ); + if (!name.empty()) item->setHoverName(name); + spawnAtLocation(item, 0); +} + void Minecart::animateHurt() { setHurtDir(-getHurtDir()); setHurtTime(10); - this->setDamage(this->getDamage() + (getDamage() * 10)); + setDamage(getDamage() + (getDamage() * 10)); } bool Minecart::isPickable() @@ -268,40 +206,13 @@ bool Minecart::isPickable() void Minecart::remove() { - for (unsigned int i = 0; i < getContainerSize(); i++) - { - shared_ptr<ItemInstance> item = getItem(i); - if (item != NULL) - { - float xo = random->nextFloat() * 0.8f + 0.1f; - float yo = random->nextFloat() * 0.8f + 0.1f; - float zo = random->nextFloat() * 0.8f + 0.1f; - - while (item->count > 0) - { - int count = random->nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - - shared_ptr<ItemEntity> itemEntity = shared_ptr<ItemEntity>( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr<ItemInstance>( new ItemInstance(item->id, count, item->getAuxValue()) ) ) ); - float pow = 0.05f; - itemEntity->xd = (float) random->nextGaussian() * pow; - itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; - itemEntity->zd = (float) random->nextGaussian() * pow; - if (item->hasTag()) - { - itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); - } - level->addEntity(itemEntity); - } - } - } Entity::remove(); + //if (soundUpdater != NULL) soundUpdater->tick(); } - void Minecart::tick() { + //if (soundUpdater != NULL) soundUpdater->tick(); // 4J - make minecarts (server-side) tick twice, to put things back to how they were when we were accidently ticking them twice for( int i = 0; i < 2; i++ ) { @@ -312,9 +223,45 @@ void Minecart::tick() outOfWorld(); } - if (hasFuel() && random->nextInt(4) == 0) + if (!level->isClientSide && dynamic_cast<ServerLevel *>(level) != NULL) { - level->addParticle(eParticleType_largesmoke, x, y + 0.8, z, 0, 0, 0); + MinecraftServer *server = ((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--; } // 4J Stu - Fix for #8284 - Gameplay: Collision: Minecart clips into/ through blocks at the end of the track, prevents player from riding @@ -332,13 +279,13 @@ void Minecart::tick() xRot += (float) ( (lxr - xRot) / lSteps ); lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); + setPos(xt, yt, zt); + setRot(yRot, xRot); } else { - this->setPos(x, y, z); - this->setRot(yRot, xRot); + setPos(x, y, z); + setRot(yRot, xRot); } return; // 4J - return here stops the client-side version of this from ticking twice @@ -352,7 +299,7 @@ void Minecart::tick() int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); - if (RailTile::isRail(level, xt, yt - 1, zt)) + if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; } @@ -361,356 +308,330 @@ void Minecart::tick() double slideSpeed = 1 / 128.0; int tile = level->getTile(xt, yt, zt); - if (RailTile::isRail(tile)) + if (BaseRailTile::isRail(tile)) { - Vec3 *oldPos = getPos(x, y, z); int data = level->getData(xt, yt, zt); - y = yt; + moveAlongTrack(xt, yt, zt, max, slideSpeed, tile, data); - bool powerTrack = false; - bool haltTrack = false; - if (tile == Tile::goldenRail_Id) - { - powerTrack = (data & RailTile::RAIL_DATA_BIT) != 0; - haltTrack = !powerTrack; - } - if (((RailTile *) Tile::tiles[tile])->isUsesDataBit()) + if (tile == Tile::activatorRail_Id) { - data &= RailTile::RAIL_DIRECTION_MASK; + activateMinecart(xt, yt, zt, (data & BaseRailTile::RAIL_DATA_BIT) != 0); } + } + else + { + comeOffTrack(max); + } - if (data >= 2 && data <= 5) - { - y = yt + 1; - } + checkInsideTiles(); - if (data == 2) xd -= slideSpeed; - if (data == 3) xd += slideSpeed; - if (data == 4) zd += slideSpeed; - if (data == 5) zd -= slideSpeed; - - // 4J TODO Is this a good way to copy the bit of the array that we need? - int exits[2][3]; - memcpy( &exits, (void *)EXITS[data], sizeof(int) * 2 * 3); - //int exits[2][3] = EXITS[data]; - - double xD = exits[1][0] - exits[0][0]; - double zD = exits[1][2] - exits[0][2]; - double dd = sqrt(xD * xD + zD * zD); - - double flip = xd * xD + zd * zD; - if (flip < 0) - { - xD = -xD; - zD = -zD; - } + xRot = 0; + double xDiff = xo - x; + double zDiff = zo - z; + if (xDiff * xDiff + zDiff * zDiff > 0.001) + { + yRot = (float) (atan2(zDiff, xDiff) * 180 / PI); + if (flipped) yRot += 180; + } - double pow = sqrt(xd * xd + zd * zd); + double rotDiff = Mth::wrapDegrees(yRot - yRotO); - xd = pow * xD / dd; - zd = pow * zD / dd; - - shared_ptr<Entity> sharedRider = rider.lock(); - if (sharedRider != NULL) - { - double riderDist = (sharedRider->xd * sharedRider->xd + sharedRider->zd * sharedRider->zd); - double ownDist = xd * xd + zd * zd; + if (rotDiff < -170 || rotDiff >= 170) + { + yRot += 180; + flipped = !flipped; + } + setRot(yRot, xRot); - if (riderDist > 0.0001 && ownDist < 0.01) + vector<shared_ptr<Entity> > *entities = level->getEntities(shared_from_this(), bb->grow(0.2f, 0, 0.2f)); + if (entities != NULL && !entities->empty()) + { + AUTO_VAR(itEnd, entities->end()); + for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) + { + shared_ptr<Entity> e = (*it); //entities->at(i); + if (e != rider.lock() && e->isPushable() && e->instanceof(eTYPE_MINECART)) { - xd += sharedRider->xd * 0.1; - zd += sharedRider->zd * 0.1; + shared_ptr<Minecart> cart = dynamic_pointer_cast<Minecart>(e); + cart->m_bHasPushedCartThisTick = false; + cart->push(shared_from_this()); - haltTrack = false; + // 4J Added - We should only be pushed by one minecart per tick, the closest one + // Fix for #46937 - TU5: Gameplay: Crash/Freeze occurs when a minecart with an animal inside will be forced to despawn + if( cart->m_bHasPushedCartThisTick ) break; } } + } - // on golden rails without power, stop the cart - if (haltTrack) + if (rider.lock() != NULL) + { + if (rider.lock()->removed) { - double speedLength = sqrt(xd * xd + zd * zd); - if (speedLength < 0.03) - { - xd *= 0; - yd *= 0; - zd *= 0; - } - else + if (rider.lock()->riding == shared_from_this()) { - xd *= 0.5f; - yd *= 0; - zd *= 0.5f; + rider.lock()->riding = nullptr; } + rider = weak_ptr<Entity>(); } + } + } +} - double progress = 0; - double x0 = xt + 0.5 + exits[0][0] * 0.5; - double z0 = zt + 0.5 + exits[0][2] * 0.5; - double x1 = xt + 0.5 + exits[1][0] * 0.5; - double z1 = zt + 0.5 + exits[1][2] * 0.5; +void Minecart::activateMinecart(int xt, int yt, int zt, bool state) +{ +} - xD = x1 - x0; - zD = z1 - z0; +void Minecart::comeOffTrack(double maxSpeed) +{ + if (xd < -maxSpeed) xd = -maxSpeed; + if (xd > +maxSpeed) xd = +maxSpeed; + if (zd < -maxSpeed) zd = -maxSpeed; + if (zd > +maxSpeed) zd = +maxSpeed; + if (onGround) + { + xd *= 0.5f; + yd *= 0.5f; + zd *= 0.5f; + } + move(xd, yd, zd); - if (xD == 0) - { - x = xt + 0.5; - progress = z - zt; - } - else if (zD == 0) - { - z = zt + 0.5; - progress = x - xt; - } - else - { + if (!onGround) + { + xd *= 0.95f; + yd *= 0.95f; + zd *= 0.95f; + } +} - double xx = x - x0; - double zz = z - z0; +void Minecart::moveAlongTrack(int xt, int yt, int zt, double maxSpeed, double slideSpeed, int tile, int data) +{ + fallDistance = 0; - progress = (xx * xD + zz * zD) * 2; - } + Vec3 *oldPos = getPos(x, y, z); + y = yt; - x = x0 + xD * progress; - z = z0 + zD * progress; + bool powerTrack = false; + bool haltTrack = false; + if (tile == Tile::goldenRail_Id) + { + powerTrack = (data & BaseRailTile::RAIL_DATA_BIT) != 0; + haltTrack = !powerTrack; + } + if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) + { + data &= BaseRailTile::RAIL_DIRECTION_MASK; + } - setPos(x, y + heightOffset, z); + if (data >= 2 && data <= 5) + { + y = yt + 1; + } - double xdd = xd; - double zdd = zd; - if (rider.lock() != NULL) - { - xdd *= 0.75; - zdd *= 0.75; - } - if (xdd < -max) xdd = -max; - if (xdd > +max) xdd = +max; - if (zdd < -max) zdd = -max; - if (zdd > +max) zdd = +max; - move(xdd, 0, zdd); + if (data == 2) xd -= slideSpeed; + if (data == 3) xd += slideSpeed; + if (data == 4) zd += slideSpeed; + if (data == 5) zd -= slideSpeed; - if (exits[0][1] != 0 && Mth::floor(x) - xt == exits[0][0] && Mth::floor(z) - zt == exits[0][2]) - { - setPos(x, y + exits[0][1], z); - } - else if (exits[1][1] != 0 && Mth::floor(x) - xt == exits[1][0] && Mth::floor(z) - zt == exits[1][2]) - { - setPos(x, y + exits[1][1], z); - } - else - { - } + int exits[2][3]; + memcpy( exits, EXITS[data], sizeof(int) * 2 * 3); - if (rider.lock() != NULL) - { - xd *= 0.997f; - yd *= 0; - zd *= 0.997f; - } - else - { - if (type == Minecart::FURNACE) - { - double sd = xPush * xPush + zPush * zPush; - if (sd > 0.01 * 0.01) - { - sd = sqrt(sd); - xPush /= sd; - zPush /= sd; - double speed = 0.04; - xd *= 0.8f; - yd *= 0; - zd *= 0.8f; - xd += xPush * speed; - zd += zPush * speed; - } - else - { - xd *= 0.9f; - yd *= 0; - zd *= 0.9f; - } - } - xd *= 0.96f; - yd *= 0; - zd *= 0.96f; + double xD = exits[1][0] - exits[0][0]; + double zD = exits[1][2] - exits[0][2]; + double dd = sqrt(xD * xD + zD * zD); - } + double flip = xd * xD + zd * zD; + if (flip < 0) + { + xD = -xD; + zD = -zD; + } - Vec3 *newPos = getPos(x, y, z); - if (newPos != NULL && oldPos != NULL) - { - double speed = (oldPos->y - newPos->y) * 0.05; + double pow = sqrt(xd * xd + zd * zd); + if (pow > 2) + { + pow = 2; + } - pow = sqrt(xd * xd + zd * zd); - if (pow > 0) - { - xd = xd / pow * (pow + speed); - zd = zd / pow * (pow + speed); - } - setPos(x, newPos->y, z); - } + xd = pow * xD / dd; + zd = pow * zD / dd; - int xn = Mth::floor(x); - int zn = Mth::floor(z); - if (xn != xt || zn != zt) - { - pow = sqrt(xd * xd + zd * zd); + + if ( rider.lock() != NULL && rider.lock()->instanceof(eTYPE_LIVINGENTITY) ) + { + shared_ptr<LivingEntity> living = dynamic_pointer_cast<LivingEntity>(rider.lock()); - xd = pow * (xn - xt); - zd = pow * (zn - zt); - } + double forward = living->yya; - if (type == Minecart::FURNACE) - { - double sd = xPush * xPush + zPush * zPush; - if (sd > 0.01 * 0.01 && xd * xd + zd * zd > 0.001) - { - sd = sqrt(sd); - xPush /= sd; - zPush /= sd; + if (forward > 0) + { + double riderXd = -sin(living->yRot * PI / 180); + double riderZd = cos(living->yRot * PI / 180); - if (xPush * xd + zPush * zd < 0) - { - xPush = 0; - zPush = 0; - } - else - { - xPush = xd; - zPush = zd; - } - } - } + double ownDist = xd * xd + zd * zd; - // if on golden rail with power, increase speed - if (powerTrack) + if (ownDist < 0.01) { - double speedLength = sqrt(xd * xd + zd * zd); - if (speedLength > .01) - { - double speed = 0.06; - xd += xd / speedLength * speed; - zd += zd / speedLength * speed; - } - else - { - // if the minecart is standing still, accelerate it away - // from potentional walls - if (data == RailTile::DIR_FLAT_X) - { - if (level->isSolidBlockingTile(xt - 1, yt, zt)) - { - xd = .02; - } - else if (level->isSolidBlockingTile(xt + 1, yt, zt)) - { - xd = -.02; - } - } - else if (data == RailTile::DIR_FLAT_Z) - { - if (level->isSolidBlockingTile(xt, yt, zt - 1)) - { - zd = .02; - } - else if (level->isSolidBlockingTile(xt, yt, zt + 1)) - { - zd = -.02; - } - } - } + xd += riderXd * 0.1; + zd += riderZd * 0.1; + + haltTrack = false; } + } + } - checkInsideTiles(); + // on golden rails without power, stop the cart + if (haltTrack) + { + double speedLength = sqrt(xd * xd + zd * zd); + if (speedLength < .03) + { + xd *= 0; + yd *= 0; + zd *= 0; } else { - if (xd < -max) xd = -max; - if (xd > +max) xd = +max; - if (zd < -max) zd = -max; - if (zd > +max) zd = +max; - if (onGround) - { - xd *= 0.5f; - yd *= 0.5f; - zd *= 0.5f; - } - move(xd, yd, zd); - - if (onGround) - { - } - else - { - xd *= 0.95f; - yd *= 0.95f; - zd *= 0.95f; - } + xd *= 0.5f; + yd *= 0; + zd *= 0.5f; } + } - xRot = 0; - double xDiff = xo - x; - double zDiff = zo - z; - if (xDiff * xDiff + zDiff * zDiff > 0.001) + double progress = 0; + double x0 = xt + 0.5 + exits[0][0] * 0.5; + double z0 = zt + 0.5 + exits[0][2] * 0.5; + double x1 = xt + 0.5 + exits[1][0] * 0.5; + double z1 = zt + 0.5 + exits[1][2] * 0.5; + + xD = x1 - x0; + zD = z1 - z0; + + if (xD == 0) + { + x = xt + 0.5; + progress = z - zt; + } + else if (zD == 0) + { + z = zt + 0.5; + progress = x - xt; + } + else + { + + double xx = x - x0; + double zz = z - z0; + + progress = (xx * xD + zz * zD) * 2; + } + + x = x0 + xD * progress; + z = z0 + zD * progress; + + setPos(x, y + heightOffset, z); + + double xdd = xd; + double zdd = zd; + if (rider.lock() != NULL) + { + xdd *= 0.75; + zdd *= 0.75; + } + if (xdd < -maxSpeed) xdd = -maxSpeed; + if (xdd > +maxSpeed) xdd = +maxSpeed; + if (zdd < -maxSpeed) zdd = -maxSpeed; + if (zdd > +maxSpeed) zdd = +maxSpeed; + + move(xdd, 0, zdd); + + if (exits[0][1] != 0 && Mth::floor(x) - xt == exits[0][0] && Mth::floor(z) - zt == exits[0][2]) + { + setPos(x, y + exits[0][1], z); + } + else if (exits[1][1] != 0 && Mth::floor(x) - xt == exits[1][0] && Mth::floor(z) - zt == exits[1][2]) + { + setPos(x, y + exits[1][1], z); + } + + applyNaturalSlowdown(); + + Vec3 *newPos = getPos(x, y, z); + if (newPos != NULL && oldPos != NULL) + { + double speed = (oldPos->y - newPos->y) * 0.05; + + pow = sqrt(xd * xd + zd * zd); + if (pow > 0) { - yRot = (float) (atan2(zDiff, xDiff) * 180 / PI); - if (flipped) yRot += 180; + xd = xd / pow * (pow + speed); + zd = zd / pow * (pow + speed); } + setPos(x, newPos->y, z); + } - double rotDiff = Mth::wrapDegrees(yRot - yRotO); + int xn = Mth::floor(x); + int zn = Mth::floor(z); + if (xn != xt || zn != zt) + { + pow = sqrt(xd * xd + zd * zd); - if (rotDiff < -170 || rotDiff >= 170) + xd = pow * (xn - xt); + zd = pow * (zn - zt); + } + + // if on golden rail with power, increase speed + if (powerTrack) + { + double speedLength = sqrt(xd * xd + zd * zd); + if (speedLength > .01) { - yRot += 180; - flipped = !flipped; + double speed = 0.06; + xd += xd / speedLength * speed; + zd += zd / speedLength * speed; } - setRot(yRot, xRot); - - // if (!level->isClientSide) { + else { - vector<shared_ptr<Entity> > *entities = level->getEntities(shared_from_this(), this->bb->grow(0.2f, 0, 0.2f)); - if (entities != NULL && !entities->empty()) + // if the minecart is standing still, accelerate it away from + // potential walls + if (data == BaseRailTile::DIR_FLAT_X) { - AUTO_VAR(itEnd, entities->end()); - for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) + if (level->isSolidBlockingTile(xt - 1, yt, zt)) { - shared_ptr<Entity> e = (*it); //entities->at(i); - if (e != rider.lock() && e->isPushable() && e->GetType() == eTYPE_MINECART) - { - shared_ptr<Minecart> cart = dynamic_pointer_cast<Minecart>(e); - cart->m_bHasPushedCartThisTick = false; - cart->push(shared_from_this()); - - // 4J Added - We should only be pushed by one minecart per tick, the closest one - // Fix for #46937 - TU5: Gameplay: Crash/Freeze occurs when a minecart with an animal inside will be forced to despawn - if( cart->m_bHasPushedCartThisTick ) break; - } + xd = .02; + } + else if (level->isSolidBlockingTile(xt + 1, yt, zt)) + { + xd = -.02; } } - } - - if (rider.lock() != NULL) - { - if (rider.lock()->removed) + else if (data == BaseRailTile::DIR_FLAT_Z) { - if (rider.lock()->riding == shared_from_this()) + if (level->isSolidBlockingTile(xt, yt, zt - 1)) { - rider.lock()->riding = nullptr; + zd = .02; + } + else if (level->isSolidBlockingTile(xt, yt, zt + 1)) + { + zd = -.02; } - rider = weak_ptr<Entity>(); } } + } +} - if (fuel > 0) - { - fuel--; - } - if (fuel <= 0) - { - xPush = zPush = 0; - } - setHasFuel(fuel > 0); +void Minecart::applyNaturalSlowdown() +{ + if (rider.lock() != NULL) + { + xd *= 0.997f; + yd *= 0; + zd *= 0.997f; + } + else + { + xd *= 0.96f; + yd *= 0; + zd *= 0.96f; } } @@ -719,19 +640,19 @@ Vec3 *Minecart::getPosOffs(double x, double y, double z, double offs) int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); - if (RailTile::isRail(level, xt, yt - 1, zt)) + if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; } int tile = level->getTile(xt, yt, zt); - if (RailTile::isRail(tile)) + if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt); - if (((RailTile *) Tile::tiles[tile])->isUsesDataBit()) + if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { - data &= RailTile::RAIL_DIRECTION_MASK; + data &= BaseRailTile::RAIL_DIRECTION_MASK; } y = yt; @@ -762,9 +683,6 @@ Vec3 *Minecart::getPosOffs(double x, double y, double z, double offs) { y += exits[1][1]; } - else - { - } return getPos(x, y, z); } @@ -776,20 +694,20 @@ Vec3 *Minecart::getPos(double x, double y, double z) int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); - if (RailTile::isRail(level, xt, yt - 1, zt)) + if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; } int tile = level->getTile(xt, yt, zt); - if (RailTile::isRail(tile)) + if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt); y = yt; - if (((RailTile *) Tile::tiles[tile])->isUsesDataBit()) + if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { - data &= RailTile::RAIL_DIRECTION_MASK; + data &= BaseRailTile::RAIL_DIRECTION_MASK; } if (data >= 2 && data <= 5) @@ -843,57 +761,30 @@ Vec3 *Minecart::getPos(double x, double y, double z) return NULL; } - -void Minecart::addAdditonalSaveData(CompoundTag *base) +void Minecart::readAdditionalSaveData(CompoundTag *tag) { - base->putInt(L"Type", type); - - if (type == Minecart::FURNACE) + if (tag->getBoolean(L"CustomDisplayTile")) { - base->putDouble(L"PushX", xPush); - base->putDouble(L"PushZ", zPush); - base->putShort(L"Fuel", (short) fuel); + setDisplayTile(tag->getInt(L"DisplayTile")); + setDisplayData(tag->getInt(L"DisplayData")); + setDisplayOffset(tag->getInt(L"DisplayOffset")); } - else if (type == Minecart::CHEST) - { - ListTag<CompoundTag> *listTag = new ListTag<CompoundTag>(); - for (unsigned int i = 0; i < items->length; i++) - { - if ( (*items)[i] != NULL) - { - CompoundTag *tag = new CompoundTag(); - tag->putByte(L"Slot", (byte) i); - (*items)[i]->save(tag); - listTag->add(tag); - } - } - base->put(L"Items", listTag); - } + if (tag->contains(L"CustomName") && tag->getString(L"CustomName").length() > 0) name = tag->getString(L"CustomName"); } -void Minecart::readAdditionalSaveData(CompoundTag *base) +void Minecart::addAdditonalSaveData(CompoundTag *tag) { - type = base->getInt(L"Type"); - if (type == Minecart::FURNACE) - { - xPush = base->getDouble(L"PushX"); - zPush = base->getDouble(L"PushZ"); - fuel = base->getShort(L"Fuel"); - } - else if (type == Minecart::CHEST) + if (hasCustomDisplay()) { - ListTag<CompoundTag> *inventoryList = (ListTag<CompoundTag> *) base->getList(L"Items"); - items = new ItemInstanceArray( getContainerSize() ); - for (int i = 0; i < inventoryList->size(); i++) - { - CompoundTag *tag = inventoryList->get(i); - unsigned int slot = tag->getByte(L"Slot") & 0xff; - if (slot >= 0 && slot < items->length) (*items)[slot] = shared_ptr<ItemInstance>( ItemInstance::fromTag(tag) ); - } + tag->putBoolean(L"CustomDisplayTile", true); + tag->putInt(L"DisplayTile", getDisplayTile() == NULL ? 0 : getDisplayTile()->id); + tag->putInt(L"DisplayData", getDisplayData()); + tag->putInt(L"DisplayOffset", getDisplayOffset()); } -} + if (!name.empty()) tag->putString(L"CustomName", name); +} float Minecart::getShadowHeightOffs() { @@ -905,9 +796,9 @@ void Minecart::push(shared_ptr<Entity> e) if (level->isClientSide) return; if (e == rider.lock()) return; - if (( dynamic_pointer_cast<Mob>(e)!=NULL) && dynamic_pointer_cast<Player>(e)==NULL && dynamic_pointer_cast<VillagerGolem>(e) == NULL && type == Minecart::RIDEABLE && xd * xd + zd * zd > 0.01) + if ( e->instanceof(eTYPE_LIVINGENTITY) && !e->instanceof(eTYPE_PLAYER) && !e->instanceof(eTYPE_VILLAGERGOLEM) && (getType() == TYPE_RIDEABLE) && (xd * xd + zd * zd > 0.01) ) { - if (rider.lock() == NULL && e->riding == NULL) + if ( (rider.lock() == NULL) && (e->riding == NULL) ) { e->ride( shared_from_this() ); } @@ -934,7 +825,7 @@ void Minecart::push(shared_ptr<Entity> e) xa *= 0.5; za *= 0.5; - if (e->GetType() == eTYPE_MINECART) + if (e->instanceof(eTYPE_MINECART)) { double xo = e->x - x; double zo = e->z - z; @@ -955,16 +846,16 @@ void Minecart::push(shared_ptr<Entity> e) double zdd = (e->zd + zd); shared_ptr<Minecart> cart = dynamic_pointer_cast<Minecart>(e); - if (cart != NULL && cart->type == Minecart::FURNACE && type != Minecart::FURNACE) + if (cart != NULL && cart->getType() == TYPE_FURNACE && getType() != TYPE_FURNACE) { xd *= 0.2f; zd *= 0.2f; - this->Entity::push( e->xd - xa, 0, e->zd - za); + push( e->xd - xa, 0, e->zd - za); e->xd *= 0.95f; e->zd *= 0.95f; m_bHasPushedCartThisTick = true; } - else if (cart != NULL && cart->type != Minecart::FURNACE && type == Minecart::FURNACE) + else if (cart != NULL && cart->getType() != TYPE_FURNACE && getType() == TYPE_FURNACE) { e->xd *= 0.2f; e->zd *= 0.2f; @@ -979,7 +870,7 @@ void Minecart::push(shared_ptr<Entity> e) zdd /= 2; xd *= 0.2f; zd *= 0.2f; - this->Entity::push(xdd - xa, 0, zdd - za); + push(xdd - xa, 0, zdd - za); e->xd *= 0.2f; e->zd *= 0.2f; e->push(xdd + xa, 0, zdd + za); @@ -1006,206 +897,146 @@ void Minecart::push(shared_ptr<Entity> e) } else { - this->Entity::push(-xa, 0, -za); + push(-xa, 0, -za); e->push(xa / 4, 0, za / 4); } } } -unsigned int Minecart::getContainerSize() +void Minecart::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) { - return 9 * 3; + lx = x; + ly = y; + lz = z; + lyr = yRot; + lxr = xRot; + + lSteps = steps + 2; + + xd = lxd; + yd = lyd; + zd = lzd; } -shared_ptr<ItemInstance> Minecart::getItem(unsigned int slot) +void Minecart::lerpMotion(double xd, double yd, double zd) { - return (*items)[slot]; + lxd = this->xd = xd; + lyd = this->yd = yd; + lzd = this->zd = zd; } -shared_ptr<ItemInstance> Minecart::removeItem(unsigned int slot, int count) +void Minecart::setDamage(float damage) { - if ( (*items)[slot] != NULL) - { - if ( (*items)[slot]->count <= count) - { - shared_ptr<ItemInstance> item = (*items)[slot]; - (*items)[slot] = nullptr; - return item; - } - else - { - shared_ptr<ItemInstance> i = (*items)[slot]->remove(count); - if ((*items)[slot]->count == 0) (*items)[slot] = nullptr; - return i; - } - } - return nullptr; + entityData->set(DATA_ID_DAMAGE, damage); } -shared_ptr<ItemInstance> Minecart::removeItemNoUpdate(int slot) +float Minecart::getDamage() { - if ( (*items)[slot] != NULL) - { - shared_ptr<ItemInstance> item = (*items)[slot]; - (*items)[slot] = nullptr; - return item; - } - return nullptr; + return entityData->getFloat(DATA_ID_DAMAGE); } -void Minecart::setItem(unsigned int slot, shared_ptr<ItemInstance> item) +void Minecart::setHurtTime(int hurtTime) { - (*items)[slot] = item; - if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); + entityData->set(DATA_ID_HURT, hurtTime); } -int Minecart::getName() +int Minecart::getHurtTime() { - return IDS_ITEM_MINECART; + return entityData->getInteger(DATA_ID_HURT); } -int Minecart::getMaxStackSize() +void Minecart::setHurtDir(int hurtDir) { - return Container::LARGE_MAX_STACK_SIZE; + entityData->set(DATA_ID_HURTDIR, hurtDir); } -void Minecart::setChanged() +int Minecart::getHurtDir() { + return entityData->getInteger(DATA_ID_HURTDIR); } -bool Minecart::interact(shared_ptr<Player> player) +Tile *Minecart::getDisplayTile() { - if (type == Minecart::RIDEABLE) - { - if (rider.lock() != NULL && dynamic_pointer_cast<Player>(rider.lock())!=NULL && rider.lock() != player) return true; - if (!level->isClientSide) - { - // 4J HEG - Fixed issue with player not being able to dismount minecart (issue #4455) - player->ride( rider.lock() == player ? nullptr : shared_from_this() ); - } - } - else if (type == Minecart::CHEST) - { - if ( player->isAllowedToInteract(shared_from_this()) ) - { - if (!level->isClientSide) - player->openContainer( dynamic_pointer_cast<Container>( shared_from_this() ) ); - } - else - { - return false; - } - } - else if (type == Minecart::FURNACE) - { - shared_ptr<ItemInstance> selected = player->inventory->getSelected(); - if (selected != NULL && selected->id == Item::coal->id) - { - if (--selected->count == 0) player->inventory->setItem(player->inventory->selected, nullptr); - fuel += SharedConstants::TICKS_PER_SECOND * 180; - - } - xPush = x - player->x; - zPush = z - player->z; - } - return true; + if (!hasCustomDisplay()) return getDefaultDisplayTile(); + int id = getEntityData()->getInteger(DATA_ID_DISPLAY_TILE) & 0xFFFF; + return id > 0 && id < Tile::TILE_NUM_COUNT ? Tile::tiles[id] : NULL; } -float Minecart::getLootContent() +Tile *Minecart::getDefaultDisplayTile() { - int count = 0; - for (unsigned int i = 0; i < items->length; i++) - { - if ( (*items)[i] != NULL) count++; - } - return count / (float) items->length; + return NULL; } - -void Minecart::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) +int Minecart::getDisplayData() { - lx = x; - ly = y; - lz = z; - lyr = yRot; - lxr = xRot; - - lSteps = steps + 2; - - this->xd = lxd; - this->yd = lyd; - this->zd = lzd; + if (!hasCustomDisplay()) return getDefaultDisplayData(); + return getEntityData()->getInteger(DATA_ID_DISPLAY_TILE) >> 16; } -void Minecart::lerpMotion(double xd, double yd, double zd) +int Minecart::getDefaultDisplayData() { - lxd = this->xd = xd; - lyd = this->yd = yd; - lzd = this->zd = zd; + return 0; } -bool Minecart::stillValid(shared_ptr<Player> player) +int Minecart::getDisplayOffset() { - if (this->removed) return false; - if (player->distanceToSqr(shared_from_this()) > 8 * 8) return false; - return true; + if (!hasCustomDisplay()) return getDefaultDisplayOffset(); + return getEntityData()->getInteger(DATA_ID_DISPLAY_OFFSET); } -bool Minecart::hasFuel() +int Minecart::getDefaultDisplayOffset() { - return (entityData->getByte(DATA_ID_FUEL) & 1) != 0; + return 6; } -void Minecart::setHasFuel(bool fuel) +void Minecart::setDisplayTile(int id) { - if (fuel) - { - entityData->set(DATA_ID_FUEL, (byte) (entityData->getByte(DATA_ID_FUEL) | 1)); - } - else - { - entityData->set(DATA_ID_FUEL, (byte) (entityData->getByte(DATA_ID_FUEL) & ~1)); - } + getEntityData()->set(DATA_ID_DISPLAY_TILE, (id & 0xFFFF) | (getDisplayData() << 16)); + setCustomDisplay(true); } -void Minecart::startOpen() +void Minecart::setDisplayData(int data) { - // TODO Auto-generated method stub + Tile *tile = getDisplayTile(); + int id = tile == NULL ? 0 : tile->id; + getEntityData()->set(DATA_ID_DISPLAY_TILE, (id & 0xFFFF) | (data << 16)); + setCustomDisplay(true); } -void Minecart::stopOpen() +void Minecart::setDisplayOffset(int offset) { - // TODO Auto-generated method stub - + getEntityData()->set(DATA_ID_DISPLAY_OFFSET, offset); + setCustomDisplay(true); } -void Minecart::setDamage(int damage) +bool Minecart::hasCustomDisplay() { - entityData->set(DATA_ID_DAMAGE, damage); + return getEntityData()->getByte(DATA_ID_CUSTOM_DISPLAY) == 1; } -int Minecart::getDamage() +void Minecart::setCustomDisplay(bool value) { - return entityData->getInteger(DATA_ID_DAMAGE); + getEntityData()->set(DATA_ID_CUSTOM_DISPLAY, (byte) (value ? 1 : 0)); } -void Minecart::setHurtTime(int hurtTime) +void Minecart::setCustomName(const wstring &name) { - entityData->set(DATA_ID_HURT, hurtTime); + this->name = name; } -int Minecart::getHurtTime() +wstring Minecart::getAName() { - return entityData->getInteger(DATA_ID_HURT); + if (!name.empty()) return name; + return Entity::getAName(); } -void Minecart::setHurtDir(int hurtDir) +bool Minecart::hasCustomName() { - entityData->set(DATA_ID_HURTDIR, hurtDir); + return !name.empty(); } -int Minecart::getHurtDir() +wstring Minecart::getCustomName() { - return entityData->getInteger(DATA_ID_HURTDIR); + return name; }
\ No newline at end of file |
