diff --git a/forge-core/src/main/java/forge/util/ThreadUtil.java b/forge-core/src/main/java/forge/util/ThreadUtil.java index 6e02ef9e794..bded34a71c3 100644 --- a/forge-core/src/main/java/forge/util/ThreadUtil.java +++ b/forge-core/src/main/java/forge/util/ThreadUtil.java @@ -1,5 +1,6 @@ package forge.util; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -7,11 +8,10 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; public class ThreadUtil { - - static { + static { System.out.printf("(ThreadUtil first call): Running on a machine with %d cpu core(s)%n", Runtime.getRuntime().availableProcessors() ); } - + private static class WorkerThreadFactory implements ThreadFactory { private int countr = 0; private String prefix = ""; @@ -24,9 +24,7 @@ public class ThreadUtil { return new Thread(r, prefix + "-" + countr++); } } - - - + private final static ExecutorService gameThreadPool = Executors.newCachedThreadPool(new WorkerThreadFactory("Game")); private static ExecutorService getGameThreadPool() { return gameThreadPool; } private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2, new WorkerThreadFactory("Delayed")); @@ -36,18 +34,40 @@ public class ThreadUtil { public final static ExecutorService getComputingPool(float loadFactor) { return Executors.newFixedThreadPool((int)(Runtime.getRuntime().availableProcessors() / (1-loadFactor))); } - + public static boolean isMultiCoreSystem() { return Runtime.getRuntime().availableProcessors() > 1; } - + public static void invokeInGameThread(Runnable toRun) { getGameThreadPool().execute(toRun); } + + public static void invokeInGameThreadAndWait(final Runnable toRun) { + if (isGameThread()) { + toRun.run(); //just run in the current thread + return; + } + final CountDownLatch latch = new CountDownLatch(1); + getGameThreadPool().execute(new Runnable() { + @Override + public void run() { + toRun.run(); + latch.countDown(); + } + }); + try { + latch.await(); + } + catch (final InterruptedException ex) { + throw new RuntimeException(ex); + } + } + public static void delay(int milliseconds, Runnable inputUpdater) { getScheduledPool().schedule(inputUpdater, milliseconds, TimeUnit.MILLISECONDS); } - + public static boolean isGameThread() { return Thread.currentThread().getName().startsWith("Game"); } diff --git a/forge-gui/src/main/java/forge/gui/input/InputPayMana.java b/forge-gui/src/main/java/forge/gui/input/InputPayMana.java index 2ef6f62093b..66f956abaaa 100644 --- a/forge-gui/src/main/java/forge/gui/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/gui/input/InputPayMana.java @@ -25,6 +25,7 @@ import forge.game.spellability.AbilityManaPart; import forge.game.spellability.SpellAbility; import forge.gui.GuiChoose; import forge.util.Evaluator; +import forge.util.ThreadUtil; import forge.view.ButtonUtil; /** @@ -288,13 +289,19 @@ public abstract class InputPayMana extends InputSyncronizedBase { protected void onOk() { if (supportAutoPay()) { //use AI utility to automatically pay mana cost if possible - Runnable proc = new Runnable() { + final Runnable proc = new Runnable() { @Override public void run() { ComputerUtilMana.payManaCost(manaCost, saPaidFor, player); } }; - runAsAi(proc); + //must run in game thread as certain payment actions can only be automated there + ThreadUtil.invokeInGameThreadAndWait(new Runnable() { + @Override + public void run() { + runAsAi(proc); + } + }); this.showMessage(); } }