From b691c43c44ff180d10e7d4a9afc83b98551ff586 Mon Sep 17 00:00:00 2001 From: daoge_cmd <3523206925@qq.com> Date: Sun, 1 Mar 2026 12:16:08 +0800 Subject: Initial commit --- Minecraft.World/ExperienceOrb.cpp | 330 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 Minecraft.World/ExperienceOrb.cpp (limited to 'Minecraft.World/ExperienceOrb.cpp') 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) +{ + 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 -- cgit v1.2.3