aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/Boat.cpp
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.World/Boat.cpp
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.World/Boat.cpp')
-rw-r--r--Minecraft.World/Boat.cpp519
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;
+}