2012-03-13 11:54:51 +01:00
|
|
|
package com.massivecraft.factions.util;
|
|
|
|
|
2014-04-04 20:55:21 +02:00
|
|
|
import com.massivecraft.factions.FLocation;
|
|
|
|
import com.massivecraft.factions.P;
|
2012-03-13 11:54:51 +01:00
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.World;
|
|
|
|
|
2014-04-04 20:55:21 +02:00
|
|
|
import java.util.logging.Level;
|
2012-03-13 11:54:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* reference diagram, task should move in this pattern out from chunk 0 in the center.
|
|
|
|
* 8 [>][>][>][>][>] etc.
|
|
|
|
* [^][6][>][>][>][>][>][6]
|
|
|
|
* [^][^][4][>][>][>][4][v]
|
|
|
|
* [^][^][^][2][>][2][v][v]
|
|
|
|
* [^][^][^][^][0][v][v][v]
|
|
|
|
* [^][^][^][1][1][v][v][v]
|
|
|
|
* [^][^][3][<][<][3][v][v]
|
|
|
|
* [^][5][<][<][<][<][5][v]
|
|
|
|
* [7][<][<][<][<][<][<][7]
|
|
|
|
*/
|
|
|
|
|
2014-04-04 20:55:21 +02:00
|
|
|
public abstract class SpiralTask implements Runnable {
|
2014-08-05 17:17:27 +02:00
|
|
|
|
2014-04-04 20:55:21 +02:00
|
|
|
// general task-related reference data
|
|
|
|
private transient World world = null;
|
|
|
|
private transient boolean readyToGo = false;
|
|
|
|
private transient int taskID = -1;
|
|
|
|
private transient int limit = 0;
|
|
|
|
|
|
|
|
// values for the spiral pattern routine
|
|
|
|
private transient int x = 0;
|
|
|
|
private transient int z = 0;
|
|
|
|
private transient boolean isZLeg = false;
|
|
|
|
private transient boolean isNeg = false;
|
|
|
|
private transient int length = -1;
|
|
|
|
private transient int current = 0;
|
|
|
|
|
|
|
|
@SuppressWarnings("LeakingThisInConstructor")
|
|
|
|
public SpiralTask(FLocation fLocation, int radius) {
|
|
|
|
// limit is determined based on spiral leg length for given radius; see insideRadius()
|
|
|
|
this.limit = (radius - 1) * 2;
|
|
|
|
|
2014-07-01 22:10:18 +02:00
|
|
|
this.world = Bukkit.getWorld(fLocation.getWorldName());
|
|
|
|
if (this.world == null) {
|
|
|
|
P.p.log(Level.WARNING, "[SpiralTask] A valid world must be specified!");
|
|
|
|
this.stop();
|
|
|
|
return;
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
|
2014-07-01 22:10:18 +02:00
|
|
|
this.x = (int) fLocation.getX();
|
|
|
|
this.z = (int) fLocation.getZ();
|
2014-04-04 20:55:21 +02:00
|
|
|
|
|
|
|
this.readyToGo = true;
|
|
|
|
|
|
|
|
// get this party started
|
|
|
|
this.setTaskID(Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(P.p, this, 2, 2));
|
|
|
|
}
|
|
|
|
|
2018-07-12 18:11:07 +02:00
|
|
|
private static long now() {
|
|
|
|
return System.currentTimeMillis();
|
|
|
|
}
|
|
|
|
|
2014-04-04 20:55:21 +02:00
|
|
|
/*
|
|
|
|
* This is where the necessary work is done; you'll need to override this method with whatever you want
|
|
|
|
* done at each chunk in the spiral pattern.
|
|
|
|
* Return false if the entire task needs to be aborted, otherwise return true to continue.
|
|
|
|
*/
|
|
|
|
public abstract boolean work();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns an FLocation pointing at the current chunk X and Z values.
|
|
|
|
*/
|
|
|
|
public final FLocation currentFLocation() {
|
|
|
|
return new FLocation(world.getName(), x, z);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns a Location pointing at the current chunk X and Z values.
|
|
|
|
* note that the Location is at the corner of the chunk, not the center.
|
|
|
|
*/
|
|
|
|
public final Location currentLocation() {
|
|
|
|
return new Location(world, FLocation.chunkToBlock(x), 65.0, FLocation.chunkToBlock(z));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns current chunk X and Z values.
|
|
|
|
*/
|
|
|
|
public final int getX() {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2012-03-13 11:54:51 +01:00
|
|
|
|
|
|
|
|
2018-01-05 02:40:27 +01:00
|
|
|
/*
|
|
|
|
* Below are the guts of the class, which you normally wouldn't need to mess with.
|
|
|
|
*/
|
2012-03-13 11:54:51 +01:00
|
|
|
|
2018-07-12 18:11:07 +02:00
|
|
|
public final int getZ() {
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
2014-04-04 20:55:21 +02:00
|
|
|
public final void setTaskID(int ID) {
|
2014-07-01 22:10:18 +02:00
|
|
|
if (ID == -1) {
|
|
|
|
this.stop();
|
|
|
|
}
|
|
|
|
taskID = ID;
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public final void run() {
|
2014-07-01 22:10:18 +02:00
|
|
|
if (!this.valid() || !readyToGo) {
|
|
|
|
return;
|
|
|
|
}
|
2014-04-04 20:55:21 +02:00
|
|
|
|
|
|
|
// this is set so it only does one iteration at a time, no matter how frequently the timer fires
|
|
|
|
readyToGo = false;
|
|
|
|
|
|
|
|
// make sure we're still inside the specified radius
|
2014-07-01 22:10:18 +02:00
|
|
|
if (!this.insideRadius()) {
|
|
|
|
return;
|
|
|
|
}
|
2014-04-04 20:55:21 +02:00
|
|
|
|
|
|
|
// track this to keep one iteration from dragging on too long and possibly choking the system
|
|
|
|
long loopStartTime = now();
|
|
|
|
|
|
|
|
// keep going until the task has been running for 20ms or more, then stop to take a breather
|
|
|
|
while (now() < loopStartTime + 20) {
|
|
|
|
// run the primary task on the current X/Z coordinates
|
|
|
|
if (!this.work()) {
|
2014-07-01 22:10:18 +02:00
|
|
|
this.finish();
|
|
|
|
return;
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// move on to next chunk in spiral
|
2014-07-01 22:10:18 +02:00
|
|
|
if (!this.moveToNext()) {
|
|
|
|
return;
|
|
|
|
}
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ready for the next iteration to run
|
|
|
|
readyToGo = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// step through chunks in spiral pattern from center; returns false if we're done, otherwise returns true
|
|
|
|
public final boolean moveToNext() {
|
2014-07-01 22:10:18 +02:00
|
|
|
if (!this.valid()) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-04-04 20:55:21 +02:00
|
|
|
|
|
|
|
// make sure we don't need to turn down the next leg of the spiral
|
|
|
|
if (current < length) {
|
|
|
|
current++;
|
|
|
|
|
|
|
|
// if we're outside the radius, we're done
|
2014-07-01 22:10:18 +02:00
|
|
|
if (!this.insideRadius()) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-01 21:52:40 +02:00
|
|
|
} else { // one leg/side of the spiral down...
|
2014-07-01 22:10:18 +02:00
|
|
|
current = 0;
|
|
|
|
isZLeg ^= true;
|
2014-04-04 20:55:21 +02:00
|
|
|
// every second leg (between X and Z legs, negative or positive), length increases
|
|
|
|
if (isZLeg) {
|
2014-07-01 22:10:18 +02:00
|
|
|
isNeg ^= true;
|
|
|
|
length++;
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// move one chunk further in the appropriate direction
|
2014-07-01 22:10:18 +02:00
|
|
|
if (isZLeg) {
|
|
|
|
z += (isNeg) ? -1 : 1;
|
|
|
|
} else {
|
|
|
|
x += (isNeg) ? -1 : 1;
|
|
|
|
}
|
2014-04-04 20:55:21 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public final boolean insideRadius() {
|
2014-07-01 22:10:18 +02:00
|
|
|
boolean inside = current < limit;
|
|
|
|
if (!inside) {
|
|
|
|
this.finish();
|
|
|
|
}
|
|
|
|
return inside;
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// for successful completion
|
|
|
|
public void finish() {
|
2012-03-13 11:54:51 +01:00
|
|
|
// P.p.log("SpiralTask successfully completed!");
|
2014-04-04 20:55:21 +02:00
|
|
|
this.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// we're done, whether finished or cancelled
|
|
|
|
public final void stop() {
|
2014-07-01 22:10:18 +02:00
|
|
|
if (!this.valid()) {
|
|
|
|
return;
|
|
|
|
}
|
2014-04-04 20:55:21 +02:00
|
|
|
|
2014-07-01 22:10:18 +02:00
|
|
|
readyToGo = false;
|
|
|
|
Bukkit.getServer().getScheduler().cancelTask(taskID);
|
|
|
|
taskID = -1;
|
2014-04-04 20:55:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// is this task still valid/workable?
|
|
|
|
public final boolean valid() {
|
|
|
|
return taskID != -1;
|
|
|
|
}
|
2012-03-13 11:54:51 +01:00
|
|
|
}
|