Minestom/src/main/java/net/minestom/server/entity/ExperienceOrb.java
2020-12-31 13:53:21 -05:00

142 lines
4.4 KiB
Java

package net.minestom.server.entity;
import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.server.play.SpawnExperienceOrbPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ExperienceOrb extends Entity {
private short experienceCount;
private Player target;
private long lastTargetUpdateTick;
public ExperienceOrb(short experienceCount, @NotNull Position spawnPosition) {
super(EntityType.EXPERIENCE_ORB, spawnPosition);
setGravity(0.02f, 0.04f, 1.96f);
setBoundingBox(0.5f, 0.5f, 0.5f);
//todo vanilla sets random velocity here?
this.experienceCount = experienceCount;
}
public ExperienceOrb(short experienceCount, @NotNull Position spawnPosition, @Nullable Instance instance) {
this(experienceCount, spawnPosition);
if (instance != null) {
setInstance(instance);
}
}
@Override
public void update(long time) {
// TODO slide toward nearest player
//todo water movement
if (hasNoGravity()) {
setVelocity(getVelocity().add(0, -0.3f, 0));
}
//todo lava
double d = 8.0;
if (lastTargetUpdateTick < time - 20 + getEntityId() % 100) {
if (target == null || target.getPosition().getDistanceSquared(getPosition()) > 64) {
this.target = getClosestPlayer(this, 8);
}
lastTargetUpdateTick = time;
}
if (target != null && target.getGameMode() == GameMode.SPECTATOR) {
target = null;
}
if (target != null) {
Position pos = getPosition();
Position targetPos = target.getPosition();
Vector toTarget = new Vector(targetPos.getX() - pos.getX(), targetPos.getY() + (target.getEyeHeight() / 2) - pos.getY(), targetPos.getZ() - pos.getZ());
double e = toTarget.length(); //could really be lengthSquared
if (e < 8) {
double f = 1 - (e / 8);
setVelocity(getVelocity().add(toTarget.normalize().multiply(f * f * 0.1)));
}
}
// Move should be called here
float g = 0.98f;
if (this.onGround) {
// g = 2f;
g = 0.6f * 0.98f;
}
// apply slipperiness
setVelocity(getVelocity().multiply(new Vector(g, 0.98f, g)));
if (isOnGround())
setVelocity(getVelocity().multiply(new Vector(1, -0.9f, 1)));
}
@Override
public void spawn() {
}
@Override
public boolean addViewer(@NotNull Player player) {
final boolean result = super.addViewer(player); // Add player to viewers list
if (!result)
return false;
final PlayerConnection playerConnection = player.getPlayerConnection();
SpawnExperienceOrbPacket experienceOrbPacket = new SpawnExperienceOrbPacket();
experienceOrbPacket.entityId = getEntityId();
experienceOrbPacket.position = getPosition();
experienceOrbPacket.expCount = experienceCount;
playerConnection.sendPacket(experienceOrbPacket);
playerConnection.sendPacket(getVelocityPacket());
return true;
}
/**
* Gets the experience count.
*
* @return the experience count
*/
public short getExperienceCount() {
return experienceCount;
}
/**
* Changes the experience count.
*
* @param experienceCount the new experience count
*/
public void setExperienceCount(short experienceCount) {
// Remove the entity in order to respawn it with the correct experience count
getViewers().forEach(this::removeViewer);
this.experienceCount = experienceCount;
getViewers().forEach(this::addViewer);
}
private Player getClosestPlayer(Entity entity, float maxDistance) {
Player closest = entity.getInstance()
.getPlayers()
.stream()
.min((a, b) -> Float.compare(a.getDistance(entity), b.getDistance(entity)))
.orElse(null);
if (closest == null) return null;
if (closest.getDistance(entity) > maxDistance) return null;
return closest;
}
}