From 973d61c41897b2312699c4ba13c2b93d13858311 Mon Sep 17 00:00:00 2001 From: Raphfrk Date: Sat, 12 Feb 2011 00:29:23 +0000 Subject: [PATCH] Allows calling of functions in the main thread --- .../craftbukkit/scheduler/CraftFuture.java | 106 ++++++++++++++++++ .../craftbukkit/scheduler/CraftScheduler.java | 12 +- .../scheduler/ObjectContainer.java | 15 +++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java create mode 100644 src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java new file mode 100644 index 0000000000..0952a2caa9 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftFuture.java @@ -0,0 +1,106 @@ +package org.bukkit.craftbukkit.scheduler; + +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.CancellationException; + +public class CraftFuture implements Runnable, Future { + + private final CraftScheduler craftScheduler; + private final Callable callable; + private final ObjectContainer returnStore = new ObjectContainer(); + private boolean done = false; + private boolean running = false; + private boolean cancelled = false; + private Exception e = null; + private int taskId = -1; + + CraftFuture(CraftScheduler craftScheduler, Callable callable) { + this.callable = callable; + this.craftScheduler = craftScheduler; + } + + public void run() { + synchronized(this) { + if(cancelled) { + return; + } + running = true; + } + try { + returnStore.setObject(callable.call()); + } catch (Exception e) { + this.e = e; + } + synchronized(this) { + running = false; + done = true; + this.notify(); + } + } + + public T get() throws InterruptedException, ExecutionException { + try { + return get(0L, TimeUnit.MILLISECONDS); + } catch (TimeoutException te) {} + return null; + } + + public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + synchronized(this) { + if(isDone()) { + return getResult(); + } + this.wait(TimeUnit.MILLISECONDS.convert(timeout, unit)); + return getResult(); + } + } + + public T getResult() throws ExecutionException { + if(cancelled) { + throw new CancellationException(); + } + if(e!=null) { + throw new ExecutionException(e); + } + return returnStore.getObject(); + } + + public boolean isDone() { + synchronized(this) { + return done; + } + } + + public boolean isCancelled() { + synchronized(this) { + return cancelled; + } + } + + public boolean cancel(boolean mayInterruptIfRunning) { + synchronized(this) { + if(cancelled) { + return false; + } + cancelled = true; + if(taskId!=-1) { + craftScheduler.cancelTask(taskId); + } + if(!running && !done) { + return true; + } else { + return false; + } + } + } + + public void setTaskId(int taskId) { + synchronized(this) { + this.taskId = taskId; + } + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java index edf5bae8d2..46e095bc88 100644 --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java @@ -6,6 +6,8 @@ import java.util.Iterator; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.plugin.Plugin; @@ -105,7 +107,6 @@ public class CraftScheduler implements BukkitScheduler, Runnable { } - // If the main thread cannot obtain the lock, it doesn't wait public void mainThreadHeartbeat(long currentTick) { if (mainThreadLock.tryLock()) { @@ -177,6 +178,15 @@ public class CraftScheduler implements BukkitScheduler, Runnable { return newTask.getIdNumber(); } + public Future callSyncMethod(Plugin plugin, Callable task) { + CraftFuture craftFuture = new CraftFuture(this, task); + synchronized(craftFuture) { + int taskId = scheduleSyncDelayedTask(plugin, craftFuture); + craftFuture.setTaskId(taskId); + } + return craftFuture; + } + public void cancelTask(int taskId) { synchronized (schedulerQueue) { Iterator itr = schedulerQueue.keySet().iterator(); diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java b/src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java new file mode 100644 index 0000000000..c0fa37cb11 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/ObjectContainer.java @@ -0,0 +1,15 @@ +package org.bukkit.craftbukkit.scheduler; + +public class ObjectContainer { + + T object; + + public void setObject(T object) { + this.object = object; + } + + public T getObject() { + return object; + } + +}