Last active
May 23, 2019 23:02
-
-
Save thekeenant/883985b94c81e92e97ebd3c9e6ea1664 to your computer and use it in GitHub Desktop.
An implementation of ScheduledExecutorService for LibGDX which executes tasks on the main game thread.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.badlogic.gdx.Gdx; | |
import java.util.Collection; | |
import java.util.List; | |
import java.util.concurrent.Callable; | |
import java.util.concurrent.CountDownLatch; | |
import java.util.concurrent.ExecutionException; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.Future; | |
import java.util.concurrent.ScheduledExecutorService; | |
import java.util.concurrent.ScheduledFuture; | |
import java.util.concurrent.TimeUnit; | |
import java.util.concurrent.TimeoutException; | |
import java.util.concurrent.atomic.AtomicReference; | |
import java.util.stream.Collectors; | |
/** | |
* A {@link ScheduledExecutorService} implementation that executes operations on the game loop | |
* thread using {@link com.badlogic.gdx.Application#postRunnable(Runnable)} via {@link Gdx#app} | |
* and a delegated scheduled executor service. | |
*/ | |
public class GdxScheduledExecutorService implements ScheduledExecutorService { | |
private final ScheduledExecutorService delegate; | |
public GdxScheduledExecutorService(ScheduledExecutorService delegate) { | |
this.delegate = delegate; | |
} | |
/** | |
* Creates a new {@link GdxScheduledExecutorService} with a thread pool as the delegate. | |
* @param corePoolSize the number of threads to keep in the pool | |
* @return the new executor service | |
*/ | |
public static GdxScheduledExecutorService create(int corePoolSize) { | |
return new GdxScheduledExecutorService(Executors.newScheduledThreadPool(corePoolSize)); | |
} | |
@Override | |
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { | |
return delegate.schedule(() -> runTask(command), delay, unit); | |
} | |
@Override | |
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { | |
return delegate.schedule(() -> runCallable(callable), delay, unit); | |
} | |
@Override | |
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { | |
return delegate.scheduleAtFixedRate(() -> runTask(command), initialDelay, period, unit); | |
} | |
@Override | |
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { | |
return delegate.scheduleWithFixedDelay(() -> runTask(command), initialDelay, delay, unit); | |
} | |
@Override | |
public void shutdown() { | |
delegate.shutdown(); | |
} | |
@Override | |
public List<Runnable> shutdownNow() { | |
return delegate.shutdownNow(); | |
} | |
@Override | |
public boolean isShutdown() { | |
return delegate.isShutdown(); | |
} | |
@Override | |
public boolean isTerminated() { | |
return delegate.isTerminated(); | |
} | |
@Override | |
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { | |
return delegate.awaitTermination(timeout, unit); | |
} | |
@Override | |
public <T> Future<T> submit(Callable<T> task) { | |
return delegate.submit(() -> runCallable(task)); | |
} | |
@Override | |
public <T> Future<T> submit(Runnable task, T result) { | |
return delegate.submit(() -> runTask(task), result); | |
} | |
@Override | |
public Future<?> submit(Runnable task) { | |
return delegate.submit(() -> runTask(task)); | |
} | |
@Override | |
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) | |
throws InterruptedException { | |
return delegate.invokeAll(gdxTasks(tasks)); | |
} | |
@Override | |
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, | |
TimeUnit unit) throws InterruptedException { | |
return delegate.invokeAll(gdxTasks(tasks), timeout, unit); | |
} | |
@Override | |
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) | |
throws InterruptedException, ExecutionException { | |
return delegate.invokeAny(gdxTasks(tasks)); | |
} | |
@Override | |
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) | |
throws InterruptedException, ExecutionException, TimeoutException { | |
return delegate.invokeAny(gdxTasks(tasks), timeout, unit); | |
} | |
@Override | |
public void execute(Runnable command) { | |
delegate.execute(() -> runTask(command)); | |
} | |
private void runTask(Runnable command) { | |
CountDownLatch lock = new CountDownLatch(1); | |
Gdx.app.postRunnable(() -> { | |
command.run(); | |
lock.countDown(); | |
}); | |
try { | |
lock.await(); | |
} | |
catch (InterruptedException e) { | |
// ignored | |
} | |
} | |
private <V> V runCallable(Callable<V> callable) throws Exception { | |
AtomicReference<V> result = new AtomicReference<>(); | |
AtomicReference<Exception> exception = new AtomicReference<>(); | |
CountDownLatch lock = new CountDownLatch(1); | |
Gdx.app.postRunnable(() -> { | |
try { | |
result.set(callable.call()); | |
} | |
catch (Exception e) { | |
exception.set(e); | |
} | |
lock.countDown(); | |
}); | |
lock.await(); | |
if (exception.get() != null) { | |
throw exception.get(); | |
} | |
return result.get(); | |
} | |
private <T> List<? extends Callable<T>> gdxTasks(Collection<? extends Callable<T>> tasks) { | |
return tasks.stream() | |
.map(task -> (Callable<T>) () -> runCallable(task)) | |
.collect(Collectors.toList()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment