blob: 40e3c1980b1ebdbaad4df9c3563136cd3c242840 [file] [log] [blame] [raw]
package net.glowstone;
import lombok.Getter;
import net.glowstone.entity.GlowPlayer;
import net.glowstone.net.message.play.game.WorldBorderMessage;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldBorder;
public class GlowWorldBorder implements WorldBorder {
private final World world;
@Getter
private double size;
private double futureSize;
private double step;
private Location center;
private double damageBuffer;
private double damagePerBlock;
private int warningTime;
private int warningDistance;
private long time;
private long lastWorldTick;
/**
* Initializes a new {@link WorldBorder} for the given world.
*
* @param world the world to initialize a new {@link WorldBorder} for.
*/
public GlowWorldBorder(World world) {
this.world = world;
lastWorldTick = world.getFullTime();
size = 60000000;
time = 0;
futureSize = size;
step = 0;
center = new Location(world, 0, 0, 0);
damageBuffer = 5;
damagePerBlock = 0.2;
warningTime = 15;
warningDistance = 5;
}
/**
* Creates a {@link WorldBorderMessage} containing information to initialize the world border on
* the client-side.
*
* @return a new {@link WorldBorderMessage} for this world border.
*/
public WorldBorderMessage createMessage() {
return new WorldBorderMessage(
WorldBorderMessage.Action.INITIALIZE, center.getX(), center.getZ(),
size, futureSize, time * 1000, 29999984,
warningTime, warningDistance);
}
/**
* Pulses the world border for each tick.
*
* <p>Attempts to call this method more than once per tick will be ignored.
*/
public void pulse() {
if (lastWorldTick >= world.getFullTime()) {
// The pulse method is being called more than once per tick; abort.
return;
}
lastWorldTick = world.getFullTime();
if (step != 0) {
size += step;
if (Math.abs(size - futureSize) < 1) {
// completed
size = futureSize;
time = 0;
step = 0;
}
}
}
@Override
public void reset() {
setSize(60000000);
time = 0;
futureSize = size;
step = 0;
setCenter(new Location(world, 0, 0, 0));
setDamageBuffer(5);
setDamageAmount(0.2);
setWarningTime(15);
setWarningDistance(5);
}
@Override
public void setSize(double size) {
this.size = size;
this.futureSize = size;
broadcast(new WorldBorderMessage(WorldBorderMessage.Action.SET_SIZE, size));
}
@Override
public void setSize(double size, long seconds) {
if (seconds <= 0) {
setSize(size);
return;
}
long ticks = seconds * 20;
step = (size - this.size) / (double) ticks;
futureSize = size;
time = seconds;
broadcast(new WorldBorderMessage(
WorldBorderMessage.Action.LERP_SIZE, this.size, futureSize, time * 1000));
}
@Override
public Location getCenter() {
return center;
}
@Override
public void setCenter(Location location) {
center = location.clone();
broadcast(new WorldBorderMessage(
WorldBorderMessage.Action.SET_CENTER, center.getX(), center.getZ()));
}
@Override
public void setCenter(double x, double z) {
setCenter(new Location(world, x, 0, z));
}
@Override
public double getDamageBuffer() {
return damageBuffer;
}
@Override
public void setDamageBuffer(double blocks) {
this.damageBuffer = blocks;
}
@Override
public double getDamageAmount() {
return damagePerBlock;
}
@Override
public void setDamageAmount(double damage) {
this.damagePerBlock = damage;
}
@Override
public int getWarningTime() {
return warningTime;
}
@Override
public void setWarningTime(int seconds) {
this.warningTime = seconds;
broadcast(new WorldBorderMessage(WorldBorderMessage.Action.SET_WARNING_TIME, seconds));
}
@Override
public int getWarningDistance() {
return warningDistance;
}
@Override
public void setWarningDistance(int distance) {
this.warningDistance = distance;
broadcast(new WorldBorderMessage(WorldBorderMessage.Action.SET_WARNING_BLOCKS, distance));
}
@Override
public boolean isInside(Location location) {
Location max = center.clone().add(size / 2, 0, size / 2);
Location min = center.clone().subtract(size / 2, 0, size / 2);
return location.getX() <= max.getX() && location.getZ() <= max.getZ()
&& location.getX() >= min.getX() && location.getZ() >= min.getZ();
}
/**
* The target side length the world border is being resized to, in blocks.
*
* @return the target side length the world border is being resized to.
*/
public double getSizeLerpTarget() {
return futureSize;
}
/**
* The delay in ticks until the world border's sides should reach the target length.
*
* @return the delay until the world border's sides should reach the target length.
*/
public long getSizeLerpTime() {
return time;
}
private void broadcast(WorldBorderMessage message) {
world.getPlayers().forEach(player -> ((GlowPlayer) player).getSession().send(message));
}
}