aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.World/ExperienceOrb.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/ExperienceOrb.cpp
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.World/ExperienceOrb.cpp')
-rw-r--r--Minecraft.World/ExperienceOrb.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/Minecraft.World/ExperienceOrb.cpp b/Minecraft.World/ExperienceOrb.cpp
new file mode 100644
index 00000000..76f2a9ae
--- /dev/null
+++ b/Minecraft.World/ExperienceOrb.cpp
@@ -0,0 +1,330 @@
+#include "stdafx.h"
+#include "net.minecraft.world.level.h"
+#include "net.minecraft.world.level.material.h"
+#include "net.minecraft.world.phys.h"
+#include "net.minecraft.world.level.tile.h"
+#include "net.minecraft.world.damagesource.h"
+#include "com.mojang.nbt.h"
+#include "JavaMath.h"
+#include "SharedConstants.h"
+#include "ExperienceOrb.h"
+#include "SoundTypes.h"
+
+
+
+const int ExperienceOrb::LIFETIME = 5 * 60 * SharedConstants::TICKS_PER_SECOND; // Five minutes!
+
+void ExperienceOrb::_init()
+{
+ tickCount = 0;
+ age = 0;
+
+ throwTime = 0;
+
+ health = 5;
+ value = 0;
+ followingPlayer = nullptr;
+ followingTime = 0;
+}
+
+ExperienceOrb::ExperienceOrb(Level *level, double x, double y, double z, int count) : Entity(level)
+{
+ _init();
+
+ setSize(0.5f, 0.5f);
+ heightOffset = bbHeight / 2.0f;
+ setPos(x, y, z);
+
+ yRot = (float) (Math::random() * 360);
+
+ xd = (float) (Math::random() * 0.2f - 0.1f) * 2;
+ yd = (float) (Math::random() * 0.2) * 2;
+ zd = (float) (Math::random() * 0.2f - 0.1f) * 2;
+
+ value = count;
+}
+
+bool ExperienceOrb::makeStepSound()
+{
+ return false;
+}
+
+ExperienceOrb::ExperienceOrb(Level *level) : Entity( level )
+{
+ _init();
+
+ setSize(0.25f, 0.25f);
+ heightOffset = bbHeight / 2.0f;
+}
+
+void ExperienceOrb::defineSynchedData()
+{
+}
+
+int ExperienceOrb::getLightColor(float a)
+{
+ float l = 0.5f;
+ if (l < 0) l = 0;
+ if (l > 1) l = 1;
+ int br = Entity::getLightColor(a);
+
+ int br1 = (br) & 0xff;
+ int br2 = (br >> 16) & 0xff;
+ br1 += (int) (l * 15 * 16);
+ if (br1 > 15 * 16) br1 = 15 * 16;
+ // br2 = 15*16;
+ return br1 | br2 << 16;
+}
+
+void ExperienceOrb::tick()
+{
+ Entity::tick();
+ if (throwTime > 0) throwTime--;
+ xo = x;
+ yo = y;
+ zo = z;
+
+ yd -= 0.03f;
+ if (level->getMaterial(Mth::floor(x), Mth::floor(y), Mth::floor(z)) == Material::lava)
+ {
+ yd = 0.2f;
+ xd = (random->nextFloat() - random->nextFloat()) * 0.2f;
+ zd = (random->nextFloat() - random->nextFloat()) * 0.2f;
+ level->playSound(shared_from_this(), eSoundType_RANDOM_FIZZ, 0.4f, 2.0f + random->nextFloat() * 0.4f);
+ }
+ checkInTile(x, (bb->y0 + bb->y1) / 2, z);
+
+ double maxDist = 8;
+ // 4J - PC Comment
+ // Usually exp orbs will get created at the same time so smoothen the lagspikes
+ if (followingTime < tickCount - SharedConstants::TICKS_PER_SECOND + (entityId % 100))
+ {
+ if (followingPlayer == NULL || followingPlayer->distanceToSqr(shared_from_this()) > maxDist * maxDist)
+ {
+ followingPlayer = level->getNearestPlayer(shared_from_this(), maxDist);
+ }
+ followingTime = tickCount;
+ }
+ if (followingPlayer != NULL)
+ {
+ double xdd = (followingPlayer->x - x) / maxDist;
+ double ydd = (followingPlayer->y + followingPlayer->getHeadHeight() - y) / maxDist;
+ double zdd = (followingPlayer->z - z) / maxDist;
+ double dd = sqrt(xdd * xdd + ydd * ydd + zdd * zdd);
+ double power = 1 - dd;
+ if (power > 0)
+ {
+ power = power * power;
+ xd += xdd / dd * power * 0.1;
+ yd += ydd / dd * power * 0.1;
+ zd += zdd / dd * power * 0.1;
+ }
+ }
+
+ move(xd, yd, zd);
+
+ float friction = 0.98f;
+ if (onGround)
+ {
+ friction = 0.6f * 0.98f;
+ int t = level->getTile(Mth::floor(x), Mth::floor(bb->y0) - 1, Mth::floor(z));
+ if (t > 0)
+ {
+ friction = Tile::tiles[t]->friction * 0.98f;
+ }
+ }
+
+ xd *= friction;
+ yd *= 0.98f;
+ zd *= friction;
+
+ if (onGround)
+ {
+ yd *= -0.9f;
+ }
+
+ tickCount++;
+
+ age++;
+ if (age >= LIFETIME)
+ {
+ remove();
+ }
+}
+
+bool ExperienceOrb::updateInWaterState()
+{
+ return level->checkAndHandleWater(bb, Material::water, shared_from_this());
+}
+
+void ExperienceOrb::burn(int dmg)
+{
+ hurt(DamageSource::inFire, dmg);
+}
+
+bool ExperienceOrb::hurt(DamageSource *source, int damage)
+{
+ markHurt();
+ health -= damage;
+ if (health <= 0)
+ {
+ remove();
+ }
+ return false;
+}
+
+void ExperienceOrb::addAdditonalSaveData(CompoundTag *entityTag)
+{
+ entityTag->putShort(L"Health", (byte) health);
+ entityTag->putShort(L"Age", (short) age);
+ entityTag->putShort(L"Value", (short) value);
+}
+
+void ExperienceOrb::readAdditionalSaveData(CompoundTag *tag)
+{
+ health = tag->getShort(L"Health") & 0xff;
+ age = tag->getShort(L"Age");
+ value = tag->getShort(L"Value");
+}
+
+void ExperienceOrb::playerTouch(shared_ptr<Player> player)
+{
+ if (level->isClientSide) return;
+
+ if (throwTime == 0 && player->takeXpDelay == 0)
+ {
+ player->takeXpDelay = 2;
+ // 4J - sound change brought forward from 1.2.3
+ level->playSound(shared_from_this(), eSoundType_RANDOM_ORB, 0.1f, 0.5f * ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.8f));
+ player->take(shared_from_this(), 1);
+ player->increaseXp(value);
+ remove();
+ }
+}
+
+int ExperienceOrb::getValue()
+{
+ return value;
+}
+
+int ExperienceOrb::getIcon()
+{
+
+ if (value >= 2477)
+ {
+ return 10;
+ }
+ else if (value >= 1237)
+ {
+ return 9;
+ }
+ else if (value >= 617)
+ {
+ return 8;
+ }
+ else if (value >= 307)
+ {
+ return 7;
+ }
+ else if (value >= 149)
+ {
+ return 6;
+ }
+ else if (value >= 73)
+ {
+ return 5;
+ }
+ else if (value >= 37)
+ {
+ return 4;
+ }
+ else if (value >= 17)
+ {
+ return 3;
+ }
+ else if (value >= 7)
+ {
+ return 2;
+ }
+ else if (value >= 3)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+* Fetches the biggest possible experience orb value based on a maximum
+* value. The current algorithm is next prime which is at least twice more
+* than the previous one.
+*
+* @param maxValue
+* @return
+*/
+int ExperienceOrb::getExperienceValue(int maxValue)
+{
+
+ if (maxValue >= 2477)
+ {
+ return 2477;
+ }
+ else if (maxValue >= 1237)
+ {
+ return 1237;
+ }
+ else if (maxValue >= 617)
+ {
+ return 617;
+ }
+ else if (maxValue >= 307)
+ {
+ return 307;
+ }
+ else if (maxValue >= 149)
+ {
+ return 149;
+ }
+ else if (maxValue >= 73)
+ {
+ return 73;
+ }
+ else if (maxValue >= 37)
+ {
+ return 37;
+ }
+ else if (maxValue >= 17)
+ {
+ return 17;
+ }
+ else if (maxValue >= 7)
+ {
+ return 7;
+ }
+ else if (maxValue >= 3)
+ {
+ return 3;
+ }
+
+ return 1;
+}
+
+bool ExperienceOrb::isAttackable()
+{
+ return false;
+}
+
+// 4J added
+bool ExperienceOrb::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;
+
+ // 4J - don't render experience orbs that are less than 2 metres away, to try and avoid large particles that are causing us problems with photosensitivity testing - issues when you go
+ // near a large pile of experience orbs that all rush towards the near clip plane
+ if( distance < 4 ) return false;
+
+ return Entity::shouldRender(c);
+} \ No newline at end of file