diff --git a/src/main/java/forge/FThreads.java b/src/main/java/forge/FThreads.java index 56b4fa3c965..7e0f0bb9caa 100644 --- a/src/main/java/forge/FThreads.java +++ b/src/main/java/forge/FThreads.java @@ -3,6 +3,8 @@ package forge; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import javax.swing.SwingUtilities; @@ -13,15 +15,16 @@ import forge.control.input.InputSynchronized; * */ public class FThreads { - static { System.out.printf("(FThreads static ctor): Running on a machine with %d cpu core(s)%n", Runtime.getRuntime().availableProcessors() ); } + private FThreads() { } // no instances supposed + private final static ExecutorService threadPool = Executors.newCachedThreadPool(); - public static ExecutorService getCachedPool() { - return threadPool; - } + private static ExecutorService getCachedPool() { return threadPool; } + private final static ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1); + private static ScheduledExecutorService getScheduledPool() { return scheduledPool; } // This pool is designed to parallel CPU or IO intensive tasks like parse cards or download images, assuming a load factor of 0.5 public final static ExecutorService getComputingPool(float loadFactor) { @@ -115,5 +118,10 @@ public class FThreads { public static boolean isEDT() { return SwingUtilities.isEventDispatchThread(); } + + + public static void delay(int milliseconds, Runnable inputUpdater) { + getScheduledPool().schedule(inputUpdater, milliseconds, TimeUnit.MILLISECONDS); + } } diff --git a/src/main/java/forge/control/input/InputBase.java b/src/main/java/forge/control/input/InputBase.java index c0421c4ca43..f835e028ab3 100644 --- a/src/main/java/forge/control/input/InputBase.java +++ b/src/main/java/forge/control/input/InputBase.java @@ -58,6 +58,10 @@ public abstract class InputBase implements java.io.Serializable, Input { Singletons.getModel().getMatch().getInput().removeInput(this); afterStop(); // sync inputs will release their latch there } + + protected final boolean isActive() { + return Singletons.getModel().getMatch().getInput().getInput() == this; + } protected void afterStop() { } } \ No newline at end of file diff --git a/src/main/java/forge/control/input/InputControl.java b/src/main/java/forge/control/input/InputControl.java index e6dcffbdc54..a2be674d7e9 100644 --- a/src/main/java/forge/control/input/InputControl.java +++ b/src/main/java/forge/control/input/InputControl.java @@ -64,7 +64,7 @@ public class InputControl extends MyObservable implements java.io.Serializable { * @return a {@link forge.control.input.InputBase} object. */ public final Input getInput() { - return this.inputStack.peek(); + return inputStack.isEmpty() ? null : this.inputStack.peek(); } /** diff --git a/src/main/java/forge/control/input/InputLockUI.java b/src/main/java/forge/control/input/InputLockUI.java index 6ee7944c2c7..2fb4c2eba7e 100644 --- a/src/main/java/forge/control/input/InputLockUI.java +++ b/src/main/java/forge/control/input/InputLockUI.java @@ -1,5 +1,8 @@ package forge.control.input; +import java.util.concurrent.atomic.AtomicInteger; + +import forge.FThreads; import forge.view.ButtonUtil; /** @@ -9,14 +12,40 @@ import forge.view.ButtonUtil; public class InputLockUI extends InputBase { private static final long serialVersionUID = 5777143577098597374L; + private final AtomicInteger iCall = new AtomicInteger(); + public void showMessage() { - ButtonUtil.disableAll(); - //showMessage("Waiting for actions..."); + int ixCall = 1 + iCall.getAndIncrement(); + FThreads.delay(500, new InputUpdater(ixCall)); } @Override public String toString() { return "lockUI"; } + + private class InputUpdater implements Runnable { + final int ixCall; + + public InputUpdater(final int idxCall) { + ixCall = idxCall; + } + + @Override + public void run() { + if ( ixCall != iCall.get() || !isActive()) // cancel the message if it's not from latest call or input is gone already + return; + FThreads.invokeInEDT(showMessageFromEdt); + } + }; + + private final Runnable showMessageFromEdt = new Runnable() { + + @Override + public void run() { + ButtonUtil.disableAll(); + showMessage("Waiting for actions..."); + } + }; } diff --git a/src/main/java/forge/gui/InputProxy.java b/src/main/java/forge/gui/InputProxy.java index df312f47f3a..f56bc619f10 100644 --- a/src/main/java/forge/gui/InputProxy.java +++ b/src/main/java/forge/gui/InputProxy.java @@ -27,7 +27,6 @@ import forge.game.GameState; import forge.game.MatchController; import forge.game.phase.PhaseHandler; import forge.game.player.Player; -import forge.view.ButtonUtil; /** *

@@ -49,7 +48,7 @@ public class InputProxy implements Observer { @Override public final synchronized void update(final Observable observable, final Object obj) { - ButtonUtil.disableAll(); + this.input = null; final GameState game = match.getCurrentGame(); final PhaseHandler ph = game.getPhaseHandler(); @@ -81,7 +80,8 @@ public class InputProxy implements Observer { *

*/ public final void selectButtonOK() { - this.getInput().selectButtonOK(); + if ( null == input ) return; + input.selectButtonOK(); } /** @@ -90,7 +90,8 @@ public class InputProxy implements Observer { *

*/ public final void selectButtonCancel() { - this.getInput().selectButtonCancel(); + if ( null == input ) return; + input.selectButtonCancel(); } /** @@ -102,7 +103,8 @@ public class InputProxy implements Observer { * a {@link forge.game.player.Player} object. */ public final void selectPlayer(final Player player) { - this.getInput().selectPlayer(player); + if ( null == input ) return; + input.selectPlayer(player); } /** @@ -116,13 +118,15 @@ public class InputProxy implements Observer { * a {@link forge.game.zone.PlayerZone} object. */ public final void selectCard(final Card card) { - this.getInput().selectCard(card); + if ( null == input ) return; + input.selectCard(card); } /** {@inheritDoc} */ @Override public final String toString() { - return this.getInput().toString(); + if ( null == input ) return "(null)"; + return this.input.toString(); } /** @return {@link forge.gui.InputProxy.InputBase} */ diff --git a/src/main/java/forge/gui/match/nonsingleton/CField.java b/src/main/java/forge/gui/match/nonsingleton/CField.java index 71f65f6bddd..6b3a0561f9e 100644 --- a/src/main/java/forge/gui/match/nonsingleton/CField.java +++ b/src/main/java/forge/gui/match/nonsingleton/CField.java @@ -426,7 +426,7 @@ public class CField implements ICDoc { ((InputBlock) input).removeFromAllBlocking(c); CombatUtil.showCombat(); } - } else { + } else if ( input != null ){ //Yosei, the Morning Star required cards to be chosen on computer side //earlier it was enforced that cards must be in player zone //this can potentially break some other functionality