Files
MinecraftConsoles/Minecraft.World/ExperienceOrb.cpp
Loki Rautio 087b7e7abf Revert "Project modernization (#630)"
This code was not tested and breaks in Release builds, reverting to restore
functionality of the nightly. All in-game menus do not work and generating
a world crashes.

This reverts commit a9be52c41a.
2026-03-07 21:12:22 -06:00

331 lines
6.1 KiB
C++

#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;
playSound(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, float damage)
{
if (isInvulnerable()) return false;
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
playSound(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);
}