futher doctoring of InputQueues: ai input no longer locks UI,

priorityAutoPass is executed even without switching to EDT 
showMessage is executed for the current input of InputProxy, not the one passed as parameter
FThreads.invokeInNewThread is wrapped into InputQueue.invokeGameAction that may run action is same thread if it is not EDT
This commit is contained in:
Maxmtg
2013-05-26 12:11:37 +00:00
parent 21e17a5fd6
commit 86b848c80a
13 changed files with 67 additions and 47 deletions

View File

@@ -115,18 +115,6 @@ public class FThreads {
getCachedPool().execute(toRun); getCachedPool().execute(toRun);
} }
public static void dumpStackTrace(PrintStream stream) {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
stream.printf("%s > %s called from %s%n", debugGetCurrThreadId(), trace[2].getClassName()+"."+trace[2].getMethodName(), trace[3].toString());
int i = 0;
for(StackTraceElement se : trace) {
if(i<2) i++;
else stream.println(se.toString());
}
}
/** /**
* TODO: Write javadoc for this method. * TODO: Write javadoc for this method.
* @return * @return
@@ -150,7 +138,34 @@ public class FThreads {
} }
public static String debugGetCurrThreadId() { public static String debugGetCurrThreadId() {
return isEDT() ? "EDT" : Long.toString(Thread.currentThread().getId()); return isEDT() ? "EDT" : Thread.currentThread().getName();
}
public static void dumpStackTrace(PrintStream stream) {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
stream.printf("%s > %s called from %s%n", debugGetCurrThreadId(), trace[2].getClassName()+"."+trace[2].getMethodName(), trace[3].toString());
int i = 0;
for(StackTraceElement se : trace) {
if(i<2) i++;
else stream.println(se.toString());
}
}
public static String debugGetStackTraceItem(int depth, boolean shorter) {
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
String lastItem = trace[depth].toString();
if( shorter ) {
int lastPeriod = lastItem.lastIndexOf('.');
lastPeriod = lastItem.lastIndexOf('.', lastPeriod-1);
lastPeriod = lastItem.lastIndexOf('.', lastPeriod-1);
lastItem = lastItem.substring(lastPeriod+1);
return String.format("%s > from %s", debugGetCurrThreadId(), lastItem);
}
return String.format("%s > %s called from %s", debugGetCurrThreadId(), trace[2].getClassName()+"."+trace[2].getMethodName(), lastItem);
}
public static String debugGetStackTraceItem(int depth) {
return debugGetStackTraceItem(depth, false);
} }
} }

View File

@@ -74,7 +74,7 @@ public class InputCleanup extends InputPassPriorityBase {
if (!player.getZone(ZoneType.Hand).contains(card)) if (!player.getZone(ZoneType.Hand).contains(card))
return; return;
game.getInputQueue().LockAndInvokeGameAction(new Runnable() { game.getInputQueue().lockAndInvokeGameAction(new Runnable() {
@Override @Override
public void run() { public void run() {
card.getController().discard(card, null); card.getController().discard(card, null);

View File

@@ -73,7 +73,7 @@ public class InputPassPriority extends InputPassPriorityBase {
} }
}; };
player.getGame().getInputQueue().LockAndInvokeGameAction(execAbility); player.getGame().getInputQueue().lockAndInvokeGameAction(execAbility);
} }
else { else {
flashIncorrectAction(); flashIncorrectAction();

View File

@@ -1,6 +1,5 @@
package forge.control.input; package forge.control.input;
import forge.FThreads;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.player.Player; import forge.game.player.Player;
@@ -20,11 +19,7 @@ public abstract class InputPassPriorityBase extends InputBase {
protected final void pass() { // no futher overloads possible protected final void pass() { // no futher overloads possible
setFinished(); setFinished();
getQueue().invokeGameAction(passPriority);
if( FThreads.isEDT() )
FThreads.invokeInNewThread(passPriority);
else
passPriority.run();
} }
protected String getTurnPhasePriorityMessage() { protected String getTurnPhasePriorityMessage() {

View File

@@ -197,7 +197,7 @@ public abstract class InputPayManaBase extends InputSyncronizedBase implements I
onManaAbilityPlayed(chosen); onManaAbilityPlayed(chosen);
} }
}; };
game.getInputQueue().LockAndInvokeGameAction(proc); game.getInputQueue().lockAndInvokeGameAction(proc);
// EDT that removes lockUI from input stack will call our showMessage() method // EDT that removes lockUI from input stack will call our showMessage() method
} }

View File

@@ -130,13 +130,17 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
*/ */
public final Input getActualInput() { public final Input getActualInput() {
GameAge age = game.getAge(); GameAge age = game.getAge();
if ( age != GameAge.Play && age != GameAge.Mulligan)
if ( game.isGameOver() )
return inputLock; return inputLock;
Input topMost = inputStack.peek(); // incoming input to Control Input topMost = inputStack.peek(); // incoming input to Control
if (topMost != null ) if (topMost != null )
return topMost; return topMost;
if ( age != GameAge.Play )
return inputLock;
final PhaseHandler handler = game.getPhaseHandler(); final PhaseHandler handler = game.getPhaseHandler();
final PhaseType phase = handler.getPhase(); final PhaseType phase = handler.getPhase();
final Player playerTurn = handler.getPlayerTurn(); final Player playerTurn = handler.getPlayerTurn();
@@ -216,7 +220,7 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
input.awaitLatchRelease(); input.awaitLatchRelease();
} }
public void LockAndInvokeGameAction(final Runnable proc) { public void lockAndInvokeGameAction(final Runnable proc) {
Runnable toRun = new Runnable() { Runnable toRun = new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -225,10 +229,14 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
InputQueue.this.unlock(); InputQueue.this.unlock();
} }
}; };
invokeGameAction(toRun);
}
public void invokeGameAction(final Runnable proc) {
if(FThreads.isEDT()) { if(FThreads.isEDT()) {
FThreads.invokeInNewThread(toRun); FThreads.invokeInNewThread(proc);
} else { // this branch is experimental } else { // this branch is experimental
toRun.run(); proc.run();
} }
} }

View File

@@ -37,6 +37,7 @@ import forge.CardPredicates;
import forge.CardUtil; import forge.CardUtil;
import forge.Command; import forge.Command;
import forge.CounterType; import forge.CounterType;
import forge.FThreads;
import forge.GameEntity; import forge.GameEntity;
import forge.card.CardType; import forge.card.CardType;
import forge.card.TriggerReplacementBase; import forge.card.TriggerReplacementBase;
@@ -854,6 +855,7 @@ public class GameAction {
/** */ /** */
public final void checkStaticAbilities() { public final void checkStaticAbilities() {
FThreads.assertExecutedByEdt(false);
if (game.isGameOver()) if (game.isGameOver())
return; return;
@@ -904,6 +906,7 @@ public class GameAction {
*/ */
public final void checkStateEffects() { public final void checkStateEffects() {
// sol(10/29) added for Phase updates, state effects shouldn't be // sol(10/29) added for Phase updates, state effects shouldn't be
// checked during Spell Resolution (except when persist-returning // checked during Spell Resolution (except when persist-returning
if (game.getStack().isResolving()) { if (game.getStack().isResolving()) {

View File

@@ -8,7 +8,6 @@ import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.Card; import forge.Card;
import forge.FThreads;
import forge.Singletons; import forge.Singletons;
import forge.control.FControl; import forge.control.FControl;
import forge.error.BugReporter; import forge.error.BugReporter;
@@ -130,7 +129,7 @@ public class MatchController {
final Player firstPlayer = determineFirstTurnPlayer(getLastGameOutcome(), currentGame); final Player firstPlayer = determineFirstTurnPlayer(getLastGameOutcome(), currentGame);
// This code was run from EDT. // This code was run from EDT.
FThreads.invokeInNewThread( new Runnable() { currentGame.getInputQueue().invokeGameAction(new Runnable() {
@Override @Override
public void run() { public void run() {
currentGame.getInputQueue().clearInput(); currentGame.getInputQueue().clearInput();

View File

@@ -64,7 +64,7 @@ public class AiInputCommon extends InputPassPriorityBase implements AiInput {
* the \"Detailed Error Trace\" to the Forge forum."); * the \"Detailed Error Trace\" to the Forge forum.");
*/ */
computer.getGame().getInputQueue().LockAndInvokeGameAction(aiActions); computer.getGame().getInputQueue().invokeGameAction(aiActions);
} // getMessage(); } // getMessage();

View File

@@ -40,7 +40,6 @@ import forge.CardCharacteristicName;
import forge.CardLists; import forge.CardLists;
import forge.CardPredicates; import forge.CardPredicates;
import forge.CounterType; import forge.CounterType;
import forge.FThreads;
import forge.Singletons; import forge.Singletons;
import forge.card.spellability.AbilityManaPart; import forge.card.spellability.AbilityManaPart;
import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellAbility;
@@ -136,10 +135,10 @@ public final class GuiDisplayUtil {
private static void setupGameState(final int humanLife, final int computerLife, final Map<ZoneType, String> humanCardTexts, private static void setupGameState(final int humanLife, final int computerLife, final Map<ZoneType, String> humanCardTexts,
final Map<ZoneType, String> aiCardTexts, final String tChangePlayer, final String tChangePhase) { final Map<ZoneType, String> aiCardTexts, final String tChangePlayer, final String tChangePhase) {
FThreads.invokeInNewThread(new Runnable() { final GameState game = getGame();
game.getInputQueue().invokeGameAction(new Runnable() {
@Override @Override
public void run() { public void run() {
final GameState game = getGame();
final Player human = game.getPlayers().get(0); final Player human = game.getPlayers().get(0);
final Player ai = game.getPlayers().get(1); final Player ai = game.getPlayers().get(1);
@@ -411,7 +410,7 @@ public final class GuiDisplayUtil {
return; // happens if cancelled return; // happens if cancelled
} }
FThreads.invokeInNewThread(new Runnable() { game.getInputQueue().invokeGameAction(new Runnable() {
@Override @Override
public void run() { public void run() {
game.getAction().moveToHand(forgeCard); // this is really needed (for rollbacks at least) game.getAction().moveToHand(forgeCard); // this is really needed (for rollbacks at least)
@@ -472,7 +471,7 @@ public final class GuiDisplayUtil {
PlanarDice.roll(p, res); PlanarDice.roll(p, res);
FThreads.invokeInNewThread(new Runnable() { getGame().getInputQueue().invokeGameAction(new Runnable() {
@Override @Override
public void run() { public void run() {
p.getGame().getStack().chooseOrderOfSimultaneousStackEntryAll(); p.getGame().getStack().chooseOrderOfSimultaneousStackEntryAll();

View File

@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
import forge.Card; import forge.Card;
import forge.FThreads; import forge.FThreads;
import forge.control.input.Input; import forge.control.input.Input;
import forge.control.input.InputAutoPassPriority;
import forge.game.GameState; import forge.game.GameState;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.player.Player; import forge.game.player.Player;
@@ -59,7 +60,7 @@ public class InputProxy implements Observer {
final PhaseHandler ph = game.getPhaseHandler(); final PhaseHandler ph = game.getPhaseHandler();
if(INPUT_DEBUG) if(INPUT_DEBUG)
System.out.printf("%s > InputProxy.update() =>%n", FThreads.debugGetCurrThreadId()); System.out.println(FThreads.debugGetStackTraceItem(6, true));
if ( game.getInputQueue().isEmpty() && ph.hasPhaseEffects()) { if ( game.getInputQueue().isEmpty() && ph.hasPhaseEffects()) {
if(INPUT_DEBUG) if(INPUT_DEBUG)
@@ -76,14 +77,15 @@ public class InputProxy implements Observer {
Runnable showMessage = new Runnable() { Runnable showMessage = new Runnable() {
@Override public void run() { @Override public void run() {
if(INPUT_DEBUG) if(INPUT_DEBUG)
System.out.printf("%s > showMessage @ %s during %s%n", FThreads.debugGetCurrThreadId(), nextInput.getClass().getSimpleName(), ph.debugPrintState()); System.out.printf("%s > showMessage @ %s/%s during %s%n%n", FThreads.debugGetCurrThreadId(), nextInput.getClass().getSimpleName(), getInput().getClass().getSimpleName(), ph.debugPrintState());
nextInput.showMessage(game.getInputQueue()); getInput().showMessage(game.getInputQueue());
} }
}; };
// if( nextInput instanceof AiInput )
// FThreads.invokeInNewThread(showMessage, true); if( nextInput instanceof InputAutoPassPriority )
// else nextInput.showMessage(game.getInputQueue());
FThreads.invokeInEdtLater(showMessage); else
FThreads.invokeInEdtLater(showMessage);
} }
/** /**
* <p> * <p>

View File

@@ -95,8 +95,7 @@ public enum CDock implements ICDoc {
if( p == null ) return; if( p == null ) return;
// if( c.isMindSlaved() ) return // if( c.isMindSlaved() ) return
FThreads.invokeInNewThread(new Runnable() { game.getInputQueue().invokeGameAction(new Runnable() {
@Override @Override
public void run() { public void run() {
p.concede(); p.concede();

View File

@@ -155,7 +155,7 @@ public class CField implements ICDoc {
// should I check for who owns these cards? Are there any abilities to be played from opponent's graveyard? // should I check for who owns these cards? Are there any abilities to be played from opponent's graveyard?
final SpellAbility ab = player.getController().getAbilityToPlay(game.getAbilitesOfCard(c, player)); final SpellAbility ab = player.getController().getAbilityToPlay(game.getAbilitesOfCard(c, player));
if ( null != ab) { if ( null != ab) {
FThreads.invokeInNewThread(new Runnable(){ @Override public void run(){ game.getInputQueue().invokeGameAction(new Runnable(){ @Override public void run(){
HumanPlay.playSpellAbility(player, c, ab); HumanPlay.playSpellAbility(player, c, ab);
}}); }});
} }