diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.World/Boat.cpp | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.World/Boat.cpp')
| -rw-r--r-- | Minecraft.World/Boat.cpp | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/Minecraft.World/Boat.cpp b/Minecraft.World/Boat.cpp new file mode 100644 index 00000000..39211e44 --- /dev/null +++ b/Minecraft.World/Boat.cpp @@ -0,0 +1,519 @@ +#include "stdafx.h" +#include "com.mojang.nbt.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.material.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.damagesource.h" +#include "Boat.h" + +const double Boat::MAX_SPEED = 0.35; +const double Boat::MAX_COLLISION_SPEED = MAX_SPEED * 0.75; +const double Boat::MIN_ACCELERATION = 0.07; +const double Boat::MAX_ACCELERATION = 0.35; + +// 4J - added for common ctor code +void Boat::_init() +{ + doLerp = true; + acceleration = MIN_ACCELERATION; + + lSteps = 0; + lx = ly = lz = lyr = lxr = 0.0; + lxd = lyd = lzd = 0.0; + + blocksBuilding = true; + setSize(1.5f, 0.6f); + heightOffset = bbHeight / 2.0f; + + // 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(); +} + + + +Boat::Boat(Level *level) : Entity( level ) +{ + + _init(); +} + + +bool Boat::makeStepSound() +{ + return false; +} + +void Boat::defineSynchedData() +{ + entityData->define(DATA_ID_HURT, 0); + entityData->define(DATA_ID_HURTDIR, 1); + entityData->define(DATA_ID_DAMAGE, 0); +} + + +AABB *Boat::getCollideAgainstBox(shared_ptr<Entity> entity) +{ + return entity->bb; +} + +AABB *Boat::getCollideBox() +{ + return bb; +} + +bool Boat::isPushable() +{ + return true; +} + +Boat::Boat(Level *level, double x, double y, double z) : Entity( level ) +{ + _init(); + setPos(x, y + heightOffset, z); + + xd = 0; + yd = 0; + zd = 0; + + xo = x; + yo = y; + zo = z; +} + +double Boat::getRideHeight() +{ + return bbHeight * 0.0f - 0.3f; +} + +bool Boat::hurt(DamageSource *source, int hurtDamage) +{ + if (level->isClientSide || removed) return true; + + // 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() )) + return false; + } + + setHurtDir(-getHurtDir()); + setHurtTime(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; + + setDamage(getDamage() + hurtDamage * 10); + markHurt(); + + // 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) setDamage(100); + + if (getDamage() > 20 * 2) + { + if (rider.lock() != NULL) rider.lock()->ride( shared_from_this() ); + spawnAtLocation(Item::boat_Id, 1, 0); + remove(); + } + return true; +} + +void Boat::animateHurt() +{ + setHurtDir(-getHurtDir()); + setHurtTime(10); + setDamage(getDamage() * 11); +} + +bool Boat::isPickable() +{ + return !removed; +} + + +void Boat::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) +{ + if (doLerp) + { + lSteps = steps + 5; + } + else + { + double xdiff = x - this->x; + double ydiff = y - this->y; + double zdiff = z - this->z; + double diff = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; + + if (diff > 1) + { + lSteps = 3; + } + else + { + return; + } + } + + lx = x; + ly = y; + lz = z; + lyr = yRot; + lxr = xRot; + + this->xd = lxd; + this->yd = lyd; + this->zd = lzd; +} + +void Boat::lerpMotion(double xd, double yd, double zd) +{ + lxd = this->xd = xd; + lyd = this->yd = yd; + lzd = this->zd = zd; +} + +void Boat::tick() +{ + Entity::tick(); + if (getHurtTime() > 0) setHurtTime(getHurtTime() - 1); + if (getDamage() > 0) setDamage(getDamage() - 1); + xo = x; + yo = y; + zo = z; + + + int steps = 5; + double waterPercentage = 0; + for (int i = 0; i < steps; i++) + { + double y0 = bb->y0 + (bb->y1 - bb->y0) * (i + 0) / steps - 2 / 16.0f; + double y1 = bb->y0 + (bb->y1 - bb->y0) * (i + 1) / steps - 2 / 16.0f; + AABB *bb2 = AABB::newTemp(bb->x0, y0, bb->z0, bb->x1, y1, bb->z1); + if (level->containsLiquid(bb2, Material::water)) + { + waterPercentage += 1.0 / steps; + } + } + + double lastSpeed = sqrt(xd * xd + zd * zd); + if (lastSpeed > MAX_COLLISION_SPEED) + { + double xa = cos(yRot * PI / 180); + double za = sin(yRot * PI / 180); + + for (int i = 0; i < 1 + lastSpeed * 60; i++) + { + + double side = (random->nextFloat() * 2 - 1); + + double side2 = (random->nextInt(2) * 2 - 1) * 0.7; + if (random->nextBoolean()) + { + double xx = x - xa * side * 0.8 + za * side2; + double zz = z - za * side * 0.8 - xa * side2; + level->addParticle(eParticleType_splash, xx, y - 2 / 16.0f, zz, +xd, yd, +zd); + } + else + { + double xx = x + xa + za * side * 0.7; + double zz = z + za - xa * side * 0.7; + level->addParticle(eParticleType_splash, xx, y - 2 / 16.0f, zz, +xd, yd, +zd); + } + } + } + + if (level->isClientSide && doLerp) + { + if (lSteps > 0) + { + double xt = x + (lx - x) / lSteps; + double yt = y + (ly - y) / lSteps; + double zt = z + (lz - z) / lSteps; + + double yrd = Mth::wrapDegrees(lyr - yRot); + + yRot += (float) ( (yrd) / lSteps ); + xRot += (float) ( (lxr - xRot) / lSteps ); + + lSteps--; + this->setPos(xt, yt, zt); + this->setRot(yRot, xRot); + } + else + { +#if 1 + // Original + //double xt = x + xd; + //double yt = y + yd; + //double zt = z + zd; + //this->setPos(xt, yt, zt); + + // 4J Stu - Fix for various boat bugs, ensure that we check collision on client-side movement + this->move(xd,yd,zd); + + if (onGround) + { + xd *= 0.5f; + yd *= 0.5f; + zd *= 0.5f; + } + xd *= 0.99f; + yd *= 0.95f; + zd *= 0.99f; +#else + // 4J Stu - Fix for #8280 - Gameplay : Boats behave erratically when exited next to land. + // The client shouldn't change the position of the boat + double xt = x;// + xd; + double yt = y + yd; + double zt = z;// + zd; + this->setPos(xt, yt, zt); + + // 4J Stu - Fix for #9579 - GAMEPLAY: Boats with a player in them slowly sink under the water over time, and with no player in them they float into the sky. + // Just make the boats bob up and down rather than any other client-side movement when not receiving packets from server + if (waterPercentage < 1) + { + double bob = waterPercentage * 2 - 1; + yd += 0.04f * bob; + } + else + { + if (yd < 0) yd /= 2; + yd += 0.007f; + } + //if (onGround) + //{ + xd *= 0.5f; + yd *= 0.5f; + zd *= 0.5f; + //} + //xd *= 0.99f; + //yd *= 0.95f; + //zd *= 0.99f; +#endif + } + return; + } + + if (waterPercentage < 1) + { + double bob = waterPercentage * 2 - 1; + yd += 0.04f * bob; + } + else + { + if (yd < 0) yd /= 2; + yd += 0.007f; + } + + + if (rider.lock() != NULL) + { + xd += rider.lock()->xd * acceleration; + zd += rider.lock()->zd * acceleration; + } + + double curSpeed = sqrt(xd * xd + zd * zd); + + if (curSpeed > MAX_SPEED) + { + double ratio = MAX_SPEED / curSpeed; + + xd *= ratio; + zd *= ratio; + curSpeed = MAX_SPEED; + } + + if (curSpeed > lastSpeed && acceleration < MAX_ACCELERATION) + { + acceleration += (MAX_ACCELERATION - acceleration) / 35; + if (acceleration > MAX_ACCELERATION) acceleration = MAX_ACCELERATION; + } + else + { + acceleration -= (acceleration - MIN_ACCELERATION) / 35; + if (acceleration < MIN_ACCELERATION) acceleration = MIN_ACCELERATION; + } + + if (onGround) + { + xd *= 0.5f; + yd *= 0.5f; + zd *= 0.5f; + } + move(xd, yd, zd); + + if ((horizontalCollision && lastSpeed > 0.20)) + { + if (!level->isClientSide) + { + remove(); + for (int i = 0; i < 3; i++) + { + spawnAtLocation(Tile::wood_Id, 1, 0); + } + for (int i = 0; i < 2; i++) + { + spawnAtLocation(Item::stick->id, 1, 0); + } + } + } + else + { + xd *= 0.99f; + yd *= 0.95f; + zd *= 0.99f; + } + + xRot = 0; + double yRotT = yRot; + double xDiff = xo - x; + double zDiff = zo - z; + if (xDiff * xDiff + zDiff * zDiff > 0.001) + { + yRotT = (float) (atan2(zDiff, xDiff) * 180 / PI); + } + + double rotDiff = Mth::wrapDegrees(yRotT - yRot); + + if (rotDiff > 20) rotDiff = 20; + if (rotDiff < -20) rotDiff = -20; + + yRot += (float) rotDiff; + setRot(yRot, xRot); + + if(level->isClientSide) return; + + vector<shared_ptr<Entity> > *entities = level->getEntities(shared_from_this(), 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->GetType() == eTYPE_BOAT) + { + e->push(shared_from_this()); + } + } + } + + for (int i = 0; i < 4; i++) + { + int xx = Mth::floor(x + ((i % 2) - 0.5) * 0.8); + int zz = Mth::floor(z + ((i / 2) - 0.5) * 0.8); + + for (int j = 0; j < 2; j++) + { + int yy = Mth::floor(y) + j; + int tile = level->getTile(xx, yy, zz); + int data = level->getData(xx, yy, zz); + + if (tile == Tile::topSnow_Id) + { + level->setTile(xx, yy, zz, 0); + } + else if (tile == Tile::waterLily_Id) + { + Tile::waterLily->spawnResources(level, xx, yy, zz, data, 0.3f, 0); + level->setTile(xx, yy, zz, 0); + } + } + + } + + if (rider.lock() != NULL) + { + if (rider.lock()->removed) rider = weak_ptr<Entity>(); + } +} + +void Boat::positionRider() +{ + if (rider.lock() == NULL) return; + + double xa = cos(yRot * PI / 180) * 0.4; + double za = sin(yRot * PI / 180) * 0.4; + rider.lock()->setPos(x + xa, y + getRideHeight() + rider.lock()->getRidingHeight(), z + za); +} + + +void Boat::addAdditonalSaveData(CompoundTag *base) +{ +} + +void Boat::readAdditionalSaveData(CompoundTag *base) +{ +} + + +float Boat::getShadowHeightOffs() +{ + return 0; +} + +wstring Boat::getName() +{ + return L"Boat"; +} + +bool Boat::interact(shared_ptr<Player> player) +{ + 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 boat (issue #4446) + player->ride( rider.lock() == player ? nullptr : shared_from_this() ); + } + return true; +} + +void Boat::setDamage(int damage) +{ + entityData->set(DATA_ID_DAMAGE, damage); +} + +int Boat::getDamage() +{ + return entityData->getInteger(DATA_ID_DAMAGE); +} + +void Boat::setHurtTime(int hurtTime) +{ + entityData->set(DATA_ID_HURT, hurtTime); +} + +int Boat::getHurtTime() +{ + return entityData->getInteger(DATA_ID_HURT); +} + +void Boat::setHurtDir(int hurtDir) +{ + entityData->set(DATA_ID_HURTDIR, hurtDir); +} + +int Boat::getHurtDir() +{ + return entityData->getInteger(DATA_ID_HURTDIR); +} + +bool Boat::getDoLerp() +{ + return doLerp; +} + +void Boat::setDoLerp(bool doLerp) +{ + this->doLerp = doLerp; +} |
