Mirror von
https://github.com/PaperMC/Paper.git
synchronisiert 2024-11-16 21:10:17 +01:00
Scheduler
Dieser Commit ist enthalten in:
Ursprung
b64667cde4
Commit
9e7991ab52
@ -17,6 +17,7 @@ import java.net.UnknownHostException;
|
|||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import org.bukkit.command.ConsoleCommandSender;
|
import org.bukkit.command.ConsoleCommandSender;
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
import org.bukkit.craftbukkit.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.scheduler.CraftScheduler;
|
||||||
// CraftBukkit end
|
// CraftBukkit end
|
||||||
|
|
||||||
public class MinecraftServer implements ICommandListener, Runnable {
|
public class MinecraftServer implements ICommandListener, Runnable {
|
||||||
@ -275,6 +276,10 @@ public class MinecraftServer implements ICommandListener, Runnable {
|
|||||||
|
|
||||||
this.e.f();
|
this.e.f();
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
((CraftScheduler) server.getScheduler()).mainThreadHeartbeat(this.h);
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
while (this.e.d()) {
|
while (this.e.d()) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,15 @@ import org.bukkit.plugin.Plugin;
|
|||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.SimplePluginManager;
|
import org.bukkit.plugin.SimplePluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||||
|
import org.bukkit.scheduler.BukkitScheduler;
|
||||||
|
import org.bukkit.craftbukkit.scheduler.CraftScheduler;
|
||||||
|
|
||||||
public final class CraftServer implements Server {
|
public final class CraftServer implements Server {
|
||||||
private final String serverName = "Craftbukkit";
|
private final String serverName = "Craftbukkit";
|
||||||
private final String serverVersion;
|
private final String serverVersion;
|
||||||
private final String protocolVersion = "1.2_01";
|
private final String protocolVersion = "1.2_01";
|
||||||
private final PluginManager pluginManager = new SimplePluginManager(this);
|
private final PluginManager pluginManager = new SimplePluginManager(this);
|
||||||
|
private final BukkitScheduler scheduler = new CraftScheduler(this);
|
||||||
private final CommandMap commandMap = new SimpleCommandMap(this);
|
private final CommandMap commandMap = new SimpleCommandMap(this);
|
||||||
protected final MinecraftServer console;
|
protected final MinecraftServer console;
|
||||||
protected final ServerConfigurationManager server;
|
protected final ServerConfigurationManager server;
|
||||||
@ -145,6 +148,10 @@ public final class CraftServer implements Server {
|
|||||||
return pluginManager;
|
return pluginManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BukkitScheduler getScheduler() {
|
||||||
|
return scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
public World[] getWorlds() {
|
public World[] getWorlds() {
|
||||||
return new World[]{console.e.getWorld()};
|
return new World[]{console.e.getWorld()};
|
||||||
}
|
}
|
||||||
|
209
src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
Normale Datei
209
src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
Normale Datei
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
Normale Datei
110
src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java
Normale Datei
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java
Normale Datei
82
src/main/java/org/bukkit/craftbukkit/scheduler/CraftWorker.java
Normale Datei
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren