aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/Fireball.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/Fireball.cpp
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.World/Fireball.cpp')
-rw-r--r--Minecraft.World/Fireball.cpp415
1 files changed, 415 insertions, 0 deletions
diff --git a/Minecraft.World/Fireball.cpp b/Minecraft.World/Fireball.cpp
new file mode 100644
index 00000000..46be68f7
--- /dev/null
+++ b/Minecraft.World/Fireball.cpp
@@ -0,0 +1,415 @@
+#include "stdafx.h"
+#include "net.minecraft.world.level.h"
+#include "net.minecraft.world.level.tile.h"
+#include "net.minecraft.world.entity.player.h"
+#include "net.minecraft.world.phys.h"
+#include "net.minecraft.world.item.h"
+#include "net.minecraft.world.damagesource.h"
+#include "com.mojang.nbt.h"
+#include "Fireball.h"
+#include "net.minecraft.world.level.dimension.h"
+#include "SharedConstants.h"
+
+
+// 4J - added common ctor code.
+void Fireball::_init()
+{
+ xTile = -1;
+ yTile = -1;
+ zTile = -1;
+ lastTile = 0;
+ inGround = false;
+ flightTime = 0;
+
+ life = 0;
+ owner = nullptr;
+ xPower = 0.0;
+ yPower = 0.0;
+ zPower = 0.0;
+}
+
+Fireball::Fireball(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();
+
+ setSize(16 / 16.0f, 16 / 16.0f);
+
+}
+
+void Fireball::defineSynchedData()
+{
+
+}
+
+bool Fireball::shouldRenderAtSqrDistance(double distance)
+{
+ double size = bb->getSize() * 4;
+ size *= 64.0f;
+ return distance < size * size;
+}
+
+
+Fireball::Fireball(Level *level, double x, double y, double z, double xa, double ya, double za) : 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();
+
+ setSize(16 / 16.0f, 16 / 16.0f);
+
+ this->moveTo(x, y, z, yRot, xRot);
+ this->setPos(x, y, z);
+
+ double dd = sqrt(xa * xa + ya * ya + za * za);
+
+ // Fix for #69150 - [CRASH] TU8: Code: Gameplay: Nether portal mechanics can become permanently broken, causing a hard lock upon usage.
+ // IF xa, ya and za are 0 then dd is 0 and the xa/dd etc return NAN
+ if(dd == 0.0)
+ {
+ xPower = 0.0;
+ yPower = 0.0;
+ zPower = 0.0;
+ }
+ else
+ {
+ xPower = xa / dd * 0.10;
+ yPower = ya / dd * 0.10;
+ zPower = za / dd * 0.10;
+ }
+}
+
+Fireball::Fireball(Level *level, shared_ptr<Mob> mob, double xa, double ya, double za) : 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();
+
+ this->owner = mob;
+
+ setSize(16 / 16.0f, 16 / 16.0f);
+
+ this->moveTo(mob->x, mob->y, mob->z, mob->yRot, mob->xRot);
+ this->setPos(x, y, z);
+ this->heightOffset = 0;
+
+
+ xd = yd = zd = 0.0;
+
+ xa += random->nextGaussian() * 0.4;
+ ya += random->nextGaussian() * 0.4;
+ za += random->nextGaussian() * 0.4;
+ double dd = sqrt(xa * xa + ya * ya + za * za);
+
+ // Fix for #69150 - [CRASH] TU8: Code: Gameplay: Nether portal mechanics can become permanently broken, causing a hard lock upon usage.
+ // IF xa, ya and za are 0 then dd is 0 and the xa/dd etc return NAN
+ if(dd == 0.0)
+ {
+ xPower = 0.0;
+ yPower = 0.0;
+ zPower = 0.0;
+ }
+ else
+ {
+ xPower = xa / dd * 0.10;
+ yPower = ya / dd * 0.10;
+ zPower = za / dd * 0.10;
+ }
+}
+
+void Fireball::tick()
+{
+ // 4J-PB - Moved forward from 1.2.3
+ //if (!level->isClientSide && (owner == NULL || owner->removed))
+ if (!level->isClientSide)
+ {
+ if((owner != NULL && owner->removed) || !level->hasChunkAt((int) x, (int) y, (int) z))
+ {
+ app.DebugPrintf("Fireball removed - owner is null or removed is true for owner\n");
+ remove();
+ return;
+ }
+ else
+ {
+ // 4J-PB - TU9 bug fix - fireballs can hit the edge of the world, and stay there
+ int minXZ = - (level->dimension->getXZSize() * 16 ) / 2;
+ int maxXZ = (level->dimension->getXZSize() * 16 ) / 2 - 1;
+
+ if ((x<=minXZ) || (x>=maxXZ) || (z<=minXZ) || (z>=maxXZ))
+ {
+ remove();
+ app.DebugPrintf("Fireball removed - end of world\n");
+ return;
+ }
+ }
+ }
+
+ Entity::tick();
+
+ //app.DebugPrintf("Fireball x %d, y %d, z%d\n",(int)x,(int)y,(int)z);
+
+ if(shouldBurn()) setOnFire(1);
+
+ if (inGround)
+ {
+ int tile = level->getTile(xTile, yTile, zTile);
+ if (tile == lastTile)
+ {
+ life++;
+ if (life == SharedConstants::TICKS_PER_SECOND * 30)
+ {
+ remove();
+ app.DebugPrintf("Fireball removed - life is 20*60\n");
+ }
+ return;
+ }
+ else
+ {
+ inGround = false;
+
+ xd *= random->nextFloat() * 0.2f;
+ yd *= random->nextFloat() * 0.2f;
+ zd *= random->nextFloat() * 0.2f;
+ life = 0;
+ flightTime = 0;
+ }
+ }
+ else
+ {
+ flightTime++;
+ }
+
+ MemSect(41);
+ Vec3 *from = Vec3::newTemp(x, y, z);
+ Vec3 *to = Vec3::newTemp(x + xd, y + yd, z + zd);
+ HitResult *res = level->clip(from, to);
+
+ from = Vec3::newTemp(x, y, z);
+ to = Vec3::newTemp(x + xd, y + yd, z + zd);
+ if (res != NULL)
+ {
+ to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z);
+ }
+ shared_ptr<Entity> hitEntity = nullptr;
+ vector<shared_ptr<Entity> > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1));
+ double nearest = 0;
+ AUTO_VAR(itEnd, objects->end());
+ for (AUTO_VAR(it, objects->begin()); it != itEnd; it++)
+ {
+ shared_ptr<Entity> e = *it; //objects->at(i);
+ if (!e->isPickable() || (e->is(owner) )) continue; //4J Stu - Never collide with the owner (Enderdragon) // && flightTime < 25)) continue;
+
+ float rr = 0.3f;
+ AABB *bb = e->bb->grow(rr, rr, rr);
+ HitResult *p = bb->clip(from, to);
+ if (p != NULL)
+ {
+ double dd = from->distanceTo(p->pos);
+ if (dd < nearest || nearest == 0)
+ {
+ hitEntity = e;
+ nearest = dd;
+ }
+ delete p;
+ }
+
+ }
+
+ if (hitEntity != NULL)
+ {
+ delete res;
+ res = new HitResult(hitEntity);
+ }
+ MemSect(0);
+
+ if (res != NULL)
+ {
+ onHit(res);
+ }
+ delete res;
+ x += xd;
+ y += yd;
+ z += zd;
+
+ double sd = sqrt(xd * xd + zd * zd);
+ yRot = (float) (atan2(xd, zd) * 180 / PI);
+ xRot = (float) (atan2(yd, sd) * 180 / PI);
+
+ while (xRot - xRotO < -180)
+ xRotO -= 360;
+ while (xRot - xRotO >= 180)
+ xRotO += 360;
+
+ while (yRot - yRotO < -180)
+ yRotO -= 360;
+ while (yRot - yRotO >= 180)
+ yRotO += 360;
+
+ xRot = xRotO + (xRot - xRotO) * 0.2f;
+ yRot = yRotO + (yRot - yRotO) * 0.2f;
+
+
+ float inertia = 0.95f;
+ if (isInWater())
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ float s = 1 / 4.0f;
+ level->addParticle(eParticleType_bubble, x - xd * s, y - yd * s, z - zd * s, xd, yd, zd);
+ }
+ inertia = 0.80f;
+ }
+
+ xd += xPower;
+ yd += yPower;
+ zd += zPower;
+ xd *= inertia;
+ yd *= inertia;
+ zd *= inertia;
+
+ // 4J-PB - bug fix for the fireballs in a saved game - they are saved with no/very small velocity, so end up hanging around in the air
+ if (!level->isClientSide)
+ {
+ if((abs(xd)<0.002) && (abs(yd)<0.002) && (abs(zd)<0.002))
+ {
+ xd=0.0;
+ zd=0.0;
+ yd=0.0;
+ app.DebugPrintf("Removing a fireball with zero velocity\n");
+ remove();
+ }
+ }
+
+ level->addParticle(getTrailParticleType(), x, y + 0.5f, z, 0, 0.01, 0);
+
+ setPos(x, y, z);
+}
+
+void Fireball::onHit(HitResult *res)
+{
+ if (!level->isClientSide)
+ {
+ if (res->entity != NULL)
+ {
+ DamageSource *damageSource = DamageSource::fireball(dynamic_pointer_cast<Fireball>( shared_from_this() ), owner);
+ if (res->entity->hurt(damageSource, 6))
+ {
+ }
+ else
+ {
+ }
+ delete damageSource;
+ }
+
+ bool destroyBlocks = true;//level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
+ level->explode(nullptr, x, y, z, 1, true, destroyBlocks);
+
+ remove();
+ }
+}
+
+void Fireball::addAdditonalSaveData(CompoundTag *tag)
+{
+ tag->putShort(L"xTile", (short) xTile);
+ tag->putShort(L"yTile", (short) yTile);
+ tag->putShort(L"zTile", (short) zTile);
+ tag->putByte(L"inTile", (byte) lastTile);
+ tag->putByte(L"inGround", (byte) (inGround ? 1 : 0));
+ tag->put(L"direction", this->newDoubleList(3, this->xd, this->yd, this->zd));
+}
+
+void Fireball::readAdditionalSaveData(CompoundTag *tag)
+{
+ xTile = tag->getShort(L"xTile");
+ yTile = tag->getShort(L"yTile");
+ zTile = tag->getShort(L"zTile");
+ lastTile = tag->getByte(L"inTile") & 0xff;
+ inGround = tag->getByte(L"inGround") == 1;
+
+ // Load the stored direction and apply it to the fireball
+ // if it has no stored direction, remove it.
+ if (tag->contains(L"direction"))
+ {
+ ListTag<DoubleTag> *listTag = (ListTag<DoubleTag> *)tag->getList(L"direction");
+ this->xd = ((DoubleTag *) listTag->get(0))->data;
+ this->yd = ((DoubleTag *) listTag->get(1))->data;
+ this->zd = ((DoubleTag *) listTag->get(2))->data;
+ }
+ else
+ {
+ this->remove();
+ }
+}
+
+bool Fireball::isPickable()
+{
+ return true;
+}
+
+float Fireball::getPickRadius()
+{
+ return 1;
+}
+
+bool Fireball::hurt(DamageSource *source, int damage)
+{
+ markHurt();
+
+ if (source->getEntity() != NULL)
+ {
+ Vec3 *lookAngle = source->getEntity()->getLookAngle();
+ if (lookAngle != NULL)
+ {
+ xd = lookAngle->x;
+ yd = lookAngle->y;
+ zd = lookAngle->z;
+ xPower = xd * 0.1;
+ yPower = yd * 0.1;
+ zPower = zd * 0.1;
+ }
+ shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>( source->getEntity() );
+ if (mob != NULL)
+ {
+ owner = mob;
+ }
+ return true;
+ }
+ return false;
+}
+
+float Fireball::getShadowHeightOffs()
+{
+ return 0;
+}
+
+float Fireball::getBrightness(float a)
+{
+ return 1.0f;
+}
+
+int Fireball::getLightColor(float a)
+{
+ return 15 << 20 | 15 << 4;
+}
+
+bool Fireball::shouldBurn()
+{
+ return true;
+}
+
+int Fireball::getIcon()
+{
+ return 14 + 2 * 16;
+}
+
+ePARTICLE_TYPE Fireball::getTrailParticleType()
+{
+ return eParticleType_smoke;
+} \ No newline at end of file