mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-28 07:20:24 +01:00
Scheduler
By: Raphfrk <raphfrk@gmail.com>
This commit is contained in:
parent
68f094f38b
commit
622ca3e68c
5 changed files with 463 additions and 0 deletions
|
@ -16,12 +16,15 @@ import org.bukkit.plugin.Plugin;
|
|||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.craftbukkit.scheduler.CraftScheduler;
|
||||
|
||||
public final class CraftServer implements Server {
|
||||
private final String serverName = "Craftbukkit";
|
||||
private final String serverVersion;
|
||||
private final String protocolVersion = "1.2_01";
|
||||
private final PluginManager pluginManager = new SimplePluginManager(this);
|
||||
private final BukkitScheduler scheduler = new CraftScheduler(this);
|
||||
private final CommandMap commandMap = new SimpleCommandMap(this);
|
||||
protected final MinecraftServer console;
|
||||
protected final ServerConfigurationManager server;
|
||||
|
@ -145,6 +148,10 @@ public final class CraftServer implements Server {
|
|||
return pluginManager;
|
||||
}
|
||||
|
||||
public BukkitScheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public World[] getWorlds() {
|
||||
return new World[]{console.e.getWorld()};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
package org.bukkit.craftbukkit.scheduler;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.scheduler.CraftTask;
|
||||
|
||||
public class CraftScheduler implements BukkitScheduler, Runnable {
|
||||
|
||||
private final CraftServer server;
|
||||
|
||||
private final CraftThreadManager craftThreadManager = new CraftThreadManager();
|
||||
|
||||
private final LinkedList<Runnable> mainThreadQueue = new LinkedList<Runnable>();
|
||||
|
||||
private final TreeMap<CraftTask,Boolean> schedulerQueue = new TreeMap<CraftTask,Boolean>();
|
||||
|
||||
private final Object currentTickSync = new Object();
|
||||
private Long currentTick = 0L;
|
||||
|
||||
// This lock locks the mainThreadQueue and the currentTick value
|
||||
private final Lock mainThreadLock = new ReentrantLock();
|
||||
|
||||
public void run() {
|
||||
|
||||
while (true) {
|
||||
boolean stop = false;
|
||||
long firstTick = -1;
|
||||
long currentTick = -1;
|
||||
CraftTask first = null;
|
||||
do {
|
||||
synchronized (schedulerQueue) {
|
||||
first = null;
|
||||
if (!schedulerQueue.isEmpty()) {
|
||||
first = schedulerQueue.firstKey();
|
||||
if (first!=null) {
|
||||
currentTick = getCurrentTick();
|
||||
|
||||
firstTick = first.getExecutionTick();
|
||||
|
||||
if (currentTick >= firstTick ) {
|
||||
schedulerQueue.remove(first);
|
||||
processTask(first);
|
||||
if (first.getPeriod()>=0) {
|
||||
first.updateExecution();
|
||||
schedulerQueue.put(first, first.isSync());
|
||||
}
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
} else {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
} while (!stop);
|
||||
|
||||
long sleepTime = 0;
|
||||
if (first == null) {
|
||||
sleepTime = 60000L;
|
||||
} else {
|
||||
currentTick = getCurrentTick();
|
||||
sleepTime = (firstTick-currentTick)*50 + 25;
|
||||
}
|
||||
|
||||
if (sleepTime < 50L) {
|
||||
sleepTime = 50L;
|
||||
} else if (sleepTime > 60000L) {
|
||||
sleepTime = 60000L;
|
||||
}
|
||||
|
||||
synchronized (schedulerQueue) {
|
||||
try {
|
||||
schedulerQueue.wait(sleepTime);
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processTask(CraftTask task) {
|
||||
if (task.isSync()) {
|
||||
addToMainThreadQueue(task.getTask());
|
||||
} else {
|
||||
craftThreadManager.executeTask(task.getTask(), task.getOwner(), task.getIdNumber());
|
||||
}
|
||||
}
|
||||
|
||||
public CraftScheduler(CraftServer server) {
|
||||
this.server = server;
|
||||
|
||||
Thread t = new Thread(this);
|
||||
t.start();
|
||||
|
||||
}
|
||||
|
||||
|
||||
// If the main thread cannot obtain the lock, it doesn't wait
|
||||
public void mainThreadHeartbeat(long currentTick) {
|
||||
if (mainThreadLock.tryLock()) {
|
||||
try {
|
||||
this.currentTick = currentTick;
|
||||
while (!mainThreadQueue.isEmpty()) {
|
||||
mainThreadQueue.removeFirst().run();
|
||||
}
|
||||
} finally {
|
||||
mainThreadLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long getCurrentTick() {
|
||||
mainThreadLock.lock();
|
||||
long tempTick = 0;
|
||||
try {
|
||||
tempTick = currentTick;
|
||||
} finally {
|
||||
mainThreadLock.unlock();
|
||||
}
|
||||
return tempTick;
|
||||
}
|
||||
|
||||
void addToMainThreadQueue(Runnable task) {
|
||||
mainThreadLock.lock();
|
||||
try {
|
||||
mainThreadQueue.addLast(task);
|
||||
} finally {
|
||||
mainThreadLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task, long delay) {
|
||||
return scheduleSyncRepeatingTask(plugin, task, delay, -1);
|
||||
}
|
||||
|
||||
public int scheduleSyncDelayedTask(Plugin plugin, Runnable task) {
|
||||
return scheduleSyncDelayedTask(plugin, task, 0L);
|
||||
}
|
||||
|
||||
public int scheduleSyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
|
||||
CraftTask newTask = new CraftTask(plugin, task, true, getCurrentTick()+delay, period);
|
||||
synchronized (schedulerQueue) {
|
||||
schedulerQueue.put(newTask, true);
|
||||
schedulerQueue.notify();
|
||||
}
|
||||
return newTask.getIdNumber();
|
||||
}
|
||||
|
||||
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task, long delay) {
|
||||
return scheduleAsyncRepeatingTask(plugin, task, delay, -1);
|
||||
}
|
||||
|
||||
public int scheduleAsyncDelayedTask(Plugin plugin, Runnable task) {
|
||||
return scheduleAsyncDelayedTask(plugin, task, 0L);
|
||||
}
|
||||
|
||||
public int scheduleAsyncRepeatingTask(Plugin plugin, Runnable task, long delay, long period) {
|
||||
CraftTask newTask = new CraftTask(plugin, task, false, getCurrentTick()+delay, period);
|
||||
synchronized (schedulerQueue) {
|
||||
schedulerQueue.put(newTask, false);
|
||||
schedulerQueue.notify();
|
||||
}
|
||||
return newTask.getIdNumber();
|
||||
}
|
||||
|
||||
public void cancelTask(int taskId) {
|
||||
synchronized (schedulerQueue) {
|
||||
Iterator<CraftTask> itr = schedulerQueue.keySet().iterator();
|
||||
while (itr.hasNext()) {
|
||||
CraftTask current = itr.next();
|
||||
if (current.getIdNumber() == taskId) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
craftThreadManager.interruptTask(taskId);
|
||||
}
|
||||
|
||||
public void cancelTasks(Plugin plugin) {
|
||||
synchronized (schedulerQueue) {
|
||||
Iterator<CraftTask> itr = schedulerQueue.keySet().iterator();
|
||||
while (itr.hasNext()) {
|
||||
CraftTask current = itr.next();
|
||||
if (current.getOwner().equals(plugin)) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
craftThreadManager.interruptTask(plugin);
|
||||
}
|
||||
|
||||
public void cancelAllTasks() {
|
||||
synchronized (schedulerQueue) {
|
||||
schedulerQueue.clear();
|
||||
}
|
||||
craftThreadManager.interruptAllTasks();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package org.bukkit.craftbukkit.scheduler;
|
||||
|
||||
import java.lang.Comparable;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class CraftTask implements Comparable {
|
||||
|
||||
private final Runnable task;
|
||||
private final boolean syncTask;
|
||||
private long executionTick;
|
||||
private final long period;
|
||||
private final Plugin owner;
|
||||
private final int idNumber;
|
||||
|
||||
private static Integer idCounter = 1;
|
||||
private static Object idCounterSync = new Object();
|
||||
|
||||
CraftTask(Plugin owner, Runnable task, boolean syncTask) {
|
||||
this(owner, task, syncTask, -1, -1);
|
||||
}
|
||||
|
||||
CraftTask(Plugin owner, Runnable task, boolean syncTask, long executionTick) {
|
||||
this(owner, task, syncTask, executionTick, -1);
|
||||
}
|
||||
|
||||
CraftTask(Plugin owner, Runnable task, boolean syncTask, long executionTick, long period) {
|
||||
this.task = task;
|
||||
this.syncTask = syncTask;
|
||||
this.executionTick = executionTick;
|
||||
this.period = period;
|
||||
this.owner = owner;
|
||||
this.idNumber = CraftTask.getNextId();
|
||||
}
|
||||
|
||||
static int getNextId() {
|
||||
synchronized (idCounterSync) {
|
||||
idCounter++;
|
||||
return idCounter;
|
||||
}
|
||||
}
|
||||
|
||||
Runnable getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
boolean isSync() {
|
||||
return syncTask;
|
||||
}
|
||||
|
||||
long getExecutionTick() {
|
||||
return executionTick;
|
||||
}
|
||||
|
||||
long getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
Plugin getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
void updateExecution() {
|
||||
executionTick += period;
|
||||
}
|
||||
|
||||
int getIdNumber() {
|
||||
return idNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object other) {
|
||||
if (!(other instanceof CraftTask)) {
|
||||
return 0;
|
||||
} else {
|
||||
CraftTask o = (CraftTask) other;
|
||||
long timeDiff = executionTick - o.getExecutionTick();
|
||||
if (timeDiff>0) {
|
||||
return 1;
|
||||
} else if (timeDiff<0) {
|
||||
return -1;
|
||||
} else {
|
||||
CraftTask otherCraftTask = (CraftTask) other;
|
||||
return getIdNumber() - otherCraftTask.getIdNumber();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(other instanceof CraftTask)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CraftTask otherCraftTask = (CraftTask) other;
|
||||
return otherCraftTask.getIdNumber() == getIdNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getIdNumber();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.bukkit.craftbukkit.scheduler;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class CraftThreadManager {
|
||||
|
||||
final HashSet<CraftWorker> workers = new HashSet<CraftWorker>();
|
||||
|
||||
void executeTask(Runnable task, Plugin owner, int taskId) {
|
||||
|
||||
CraftWorker craftWorker = new CraftWorker(this, task, owner, taskId);
|
||||
synchronized (workers) {
|
||||
workers.add(craftWorker);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void interruptTask(int taskId) {
|
||||
synchronized (workers) {
|
||||
Iterator<CraftWorker> itr = workers.iterator();
|
||||
while (itr.hasNext()) {
|
||||
CraftWorker craftWorker = itr.next();
|
||||
if (craftWorker.getTaskId() == taskId) {
|
||||
craftWorker.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void interruptTask(Plugin owner) {
|
||||
synchronized (workers) {
|
||||
Iterator<CraftWorker> itr = workers.iterator();
|
||||
while (itr.hasNext()) {
|
||||
CraftWorker craftWorker = itr.next();
|
||||
if (craftWorker.getOwner().equals(owner)) {
|
||||
craftWorker.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void interruptAllTasks() {
|
||||
synchronized (workers) {
|
||||
Iterator<CraftWorker> itr = workers.iterator();
|
||||
while (itr.hasNext()) {
|
||||
CraftWorker craftWorker = itr.next();
|
||||
craftWorker.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package org.bukkit.craftbukkit.scheduler;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class CraftWorker implements Runnable {
|
||||
|
||||
private static int hashIdCounter = 1;
|
||||
private static Object hashIdCounterSync = new Object();
|
||||
|
||||
private final int hashId;
|
||||
|
||||
private final Plugin owner;
|
||||
private final int taskId;
|
||||
|
||||
private final Thread t;
|
||||
private final CraftThreadManager parent;
|
||||
|
||||
private final Runnable task;
|
||||
|
||||
CraftWorker(CraftThreadManager parent, Runnable task, Plugin owner, int taskId) {
|
||||
this.parent = parent;
|
||||
this.taskId = taskId;
|
||||
this.task = task;
|
||||
this.owner = owner;
|
||||
this.hashId = CraftWorker.getNextHashId();
|
||||
t = new Thread(this);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
task.run();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
synchronized (parent.workers) {
|
||||
parent.workers.remove(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public Plugin getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void interrupt() {
|
||||
t.interrupt();
|
||||
}
|
||||
|
||||
private static int getNextHashId() {
|
||||
synchronized (hashIdCounterSync) {
|
||||
return hashIdCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object other ) {
|
||||
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(other instanceof CraftWorker)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CraftWorker otherCraftWorker = (CraftWorker) other;
|
||||
return otherCraftWorker.hashCode() == hashId;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue