landsWannaPlay = getLandsToPlay();
+
+ while(landsWannaPlay != null && !landsWannaPlay.isEmpty() && player.canPlayLand(null)) {
+ Card land = chooseBestLandToPlay(landsWannaPlay);
+ landsWannaPlay.remove(land);
+ player.playLand(land);
+ game.getPhaseHandler().setPriority(player);
+ }
+ }
+
+ private void playSpellAbilities(final GameState game)
+ {
+ SpellAbility sa;
+ do {
+ sa = getSpellAbilityToPlay();
+ if ( sa == null ) break;
+ //System.out.println("Playing sa: " + sa);
+ if (!ComputerUtil.handlePlayingSpellAbility(player, sa, game)) {
+ break;
+ }
+ } while ( sa != null );
+ }
+
}
diff --git a/src/main/java/forge/game/ai/AiInputCommon.java b/src/main/java/forge/game/ai/AiInputCommon.java
index a2f23c97f38..338f7a1ced2 100644
--- a/src/main/java/forge/game/ai/AiInputCommon.java
+++ b/src/main/java/forge/game/ai/AiInputCommon.java
@@ -17,18 +17,8 @@
*/
package forge.game.ai;
-import java.util.List;
-
-import com.esotericsoftware.minlog.Log;
-
-import forge.Card;
-import forge.card.spellability.SpellAbility;
+import forge.FThreads;
import forge.control.input.Input;
-import forge.game.GameState;
-import forge.game.phase.PhaseType;
-import forge.game.player.AIPlayer;
-import forge.game.player.Player;
-import forge.game.zone.ZoneType;
/**
*
@@ -43,8 +33,6 @@ public class AiInputCommon extends Input {
private static final long serialVersionUID = -3091338639571662216L;
private final AiController computer;
- private final AIPlayer player;
- private final GameState game;
/**
*
@@ -56,15 +44,13 @@ public class AiInputCommon extends Input {
*/
public AiInputCommon(final AiController iComputer) {
this.computer = iComputer;
- player = computer.getPlayer();
- this.game = computer.getGame();
}
/** {@inheritDoc} */
@Override
public final void showMessage() {
// should not think when the game is over
- if (game.isGameOver()) {
+ if (computer.getGame().isGameOver()) {
return;
}
@@ -76,100 +62,19 @@ public class AiInputCommon extends Input {
* \"Detailed Error Trace\" to the Forge forum.");
*/
- final PhaseType phase = game.getPhaseHandler().getPhase();
+ FThreads.invokeInNewThread(aiActions, true);
- if (game.getStack().size() > 0) {
- playSpellAbilities(game);
- } else {
- switch(phase) {
- case CLEANUP:
- if ( game.getPhaseHandler().getPlayerTurn() == player ) {
- final int size = player.getCardsIn(ZoneType.Hand).size();
-
- if (!player.isUnlimitedHandSize()) {
- int max = Math.min(player.getZone(ZoneType.Hand).size(), size - player.getMaxHandSize());
- final List toDiscard = player.getAi().getCardsToDiscard(max, (String[])null, null);
- for (int i = 0; i < toDiscard.size(); i++) {
- player.discard(toDiscard.get(i), null);
- }
- game.getStack().chooseOrderOfSimultaneousStackEntryAll();
- }
- }
- break;
-
- case COMBAT_DECLARE_ATTACKERS:
- declareAttackers();
- break;
-
- case MAIN1:
- case MAIN2:
- Log.debug("Computer " + phase.toString());
- playLands();
- // fall through is intended
- default:
- playSpellAbilities(game);
- break;
- }
- }
- player.getController().passPriority();
} // getMessage();
- /**
- * TODO: Write javadoc for this method.
- */
- private void declareAttackers() {
- // 12/2/10(sol) the decision making here has moved to getAttackers()
- game.setCombat(new AiAttackController(player, player.getOpponent()).getAttackers());
-
- final List att = game.getCombat().getAttackers();
- if (!att.isEmpty()) {
- game.getPhaseHandler().setCombat(true);
- }
-
- for (final Card element : att) {
- // tapping of attackers happens after Propaganda is paid for
- final StringBuilder sb = new StringBuilder();
- sb.append("Computer just assigned ").append(element.getName()).append(" as an attacker.");
- Log.debug(sb.toString());
- }
-
- player.getZone(ZoneType.Battlefield).updateObservers();
-
- game.getPhaseHandler().setPlayersPriorityPermission(false);
-
- // ai is about to attack, cancel all phase skipping
- for (Player p : game.getPlayers()) {
- p.getController().autoPassCancel();
- }
- }
-
- /**
- * TODO: Write javadoc for this method.
- */
- private void playLands() {
- final Player player = computer.getPlayer();
- List landsWannaPlay = computer.getLandsToPlay();
+ final Runnable aiActions = new Runnable() {
- while(landsWannaPlay != null && !landsWannaPlay.isEmpty() && player.canPlayLand(null)) {
- Card land = computer.chooseBestLandToPlay(landsWannaPlay);
- landsWannaPlay.remove(land);
- player.playLand(land);
- game.getPhaseHandler().setPriority(player);
+ @Override
+ public void run() {
+ computer.onPriorityRecieved();
}
- }
+ };
+
- protected void playSpellAbilities(final GameState game)
- {
- SpellAbility sa;
- do {
- sa = computer.getSpellAbilityToPlay();
- if ( sa == null ) break;
- //System.out.println("Playing sa: " + sa);
- if (!ComputerUtil.handlePlayingSpellAbility(player, sa, game)) {
- break;
- }
- } while ( sa != null );
- }
/* (non-Javadoc)
diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java
index 049922c5b02..9c7b0edd5ae 100644
--- a/src/main/java/forge/game/player/Player.java
+++ b/src/main/java/forge/game/player/Player.java
@@ -39,6 +39,7 @@ import forge.CardPredicates.Presets;
import forge.CardUtil;
import forge.Constant.Preferences;
import forge.CounterType;
+import forge.FThreads;
import forge.GameEntity;
import forge.Singletons;
import forge.card.ability.AbilityFactory;
@@ -1623,6 +1624,7 @@ public abstract class Player extends GameEntity implements Comparable {
* a {@link forge.card.spellability.SpellAbility} object.
*/
protected final void doDiscard(final Card c, final SpellAbility sa) {
+ FThreads.checkEDT("Player.doDiscard", false);
// TODO: This line should be moved inside CostPayment somehow
/*if (sa != null) {
sa.addCostToHashList(c, "Discarded");
@@ -1845,6 +1847,7 @@ public abstract class Player extends GameEntity implements Comparable {
* a {@link forge.Card} object.
*/
public final void playLand(final Card land) {
+ FThreads.checkEDT("Player.playSpellAbility", false);
if (this.canPlayLand(land)) {
land.setController(this, 0);
game.getAction().moveTo(this.getZone(ZoneType.Battlefield), land);
diff --git a/src/main/java/forge/gui/GuiUtils.java b/src/main/java/forge/gui/GuiUtils.java
index c93d287bff5..e8662c774cd 100644
--- a/src/main/java/forge/gui/GuiUtils.java
+++ b/src/main/java/forge/gui/GuiUtils.java
@@ -31,7 +31,6 @@ import java.util.List;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
-import javax.swing.SwingUtilities;
import forge.Card;
import forge.gui.match.VMatchUI;
@@ -89,26 +88,6 @@ public final class GuiUtils {
return ttf;
}
- /** Checks if calling method uses event dispatch thread.
- * Exception thrown if method is on "wrong" thread.
- * A boolean is passed to indicate if the method must be EDT or not.
- *
- * @param methodName String, part of the custom exception message.
- * @param mustBeEDT boolean: true = exception if not EDT, false = exception if EDT
- */
- public static void checkEDT(final String methodName, final boolean mustBeEDT) {
- boolean isEDT = SwingUtilities.isEventDispatchThread();
-
- if (!isEDT && mustBeEDT) {
- throw new IllegalStateException(
- methodName + " must be accessed from the event dispatch thread.");
- }
- else if (isEDT && !mustBeEDT) {
- throw new IllegalStateException(
- methodName + " may not be accessed from the event dispatch thread.");
- }
- }
-
/**
* Clear all visually highlighted card panels on the battlefield.
*/
diff --git a/src/main/java/forge/gui/InputProxy.java b/src/main/java/forge/gui/InputProxy.java
index cef0ac2573b..6ec76d739f2 100644
--- a/src/main/java/forge/gui/InputProxy.java
+++ b/src/main/java/forge/gui/InputProxy.java
@@ -21,6 +21,7 @@ import java.util.Observable;
import java.util.Observer;
import forge.Card;
+import forge.FThreads;
import forge.Singletons;
import forge.control.input.Input;
import forge.game.player.Player;
@@ -58,7 +59,17 @@ public class InputProxy implements Observer {
public final synchronized void setInput(final Input in) {
valid = true;
this.input = in;
- this.input.showMessage(); // this call may invalidate the input by the time it returns
+
+ if ( null == input ) {
+ throw new NullPointerException("input is null");
+ }
+
+ FThreads.invokeInEDT(new Runnable() {
+ @Override
+ public void run() {
+ InputProxy.this.input.showMessage(); // this call may invalidate the input by the time it returns
+ }
+ });
}
/**
diff --git a/src/main/java/forge/gui/match/controllers/CPicture.java b/src/main/java/forge/gui/match/controllers/CPicture.java
index 368bcad6e90..8dae6eb2f74 100644
--- a/src/main/java/forge/gui/match/controllers/CPicture.java
+++ b/src/main/java/forge/gui/match/controllers/CPicture.java
@@ -47,7 +47,7 @@ public enum CPicture implements ICDoc {
*/
public void showCard(final Card c) {
canFlip = c != null && (c.isDoubleFaced() || c.isFlipCard());
- this.currentCard = c;
+ currentCard = c;
flipped = canFlip && (c.getCurState() == CardCharacteristicName.Transformed ||
c.getCurState() == CardCharacteristicName.Flipped);
VPicture.SINGLETON_INSTANCE.getLblFlipcard().setVisible(canFlip);
@@ -59,14 +59,16 @@ public enum CPicture implements ICDoc {
showCard(((IPaperCard)item).getMatchingForgeCard());
return;
}
-
- this.currentCard = null;
+
+ canFlip = false;
+ flipped = false;
+ currentCard = null;
VPicture.SINGLETON_INSTANCE.getLblFlipcard().setVisible(false);
VPicture.SINGLETON_INSTANCE.getPnlPicture().setCard(item);
}
public Card getCurrentCard() {
- return this.currentCard;
+ return currentCard;
}
@Override
@@ -100,7 +102,8 @@ public enum CPicture implements ICDoc {
} else if (currentCard.isFlipCard()) {
newState = CardCharacteristicName.Flipped;
} else {
- // if this is hit, then there is a misalignment between this method and the showCard method above
+ // if this is hit, then then showCard has been modified to handle additional types, but
+ // this function is missing an else if statement above
throw new RuntimeException("unhandled flippable card");
}
} else {
diff --git a/src/main/java/forge/gui/toolbox/FProgressBar.java b/src/main/java/forge/gui/toolbox/FProgressBar.java
index bff0f133454..22015d5d7e0 100644
--- a/src/main/java/forge/gui/toolbox/FProgressBar.java
+++ b/src/main/java/forge/gui/toolbox/FProgressBar.java
@@ -5,7 +5,7 @@ import java.util.Date;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
-import forge.gui.GuiUtils;
+import forge.FThreads;
/**
* A simple progress bar component using the Forge skin.
@@ -37,7 +37,7 @@ public class FProgressBar extends JProgressBar {
* @param s0 A description to prepend before statistics.
*/
public void setDescription(final String s0) {
- GuiUtils.checkEDT("FProgressBar$setDescription", true);
+ FThreads.checkEDT("FProgressBar$setDescription", true);
this.desc = s0;
this.setString(s0);
}
@@ -77,7 +77,7 @@ public class FProgressBar extends JProgressBar {
/** Resets the various values required for this class. Must be called from EDT. */
public void reset() {
- GuiUtils.checkEDT("FProgressBar$reset", true);
+ FThreads.checkEDT("FProgressBar$reset", true);
this.setIndeterminate(true);
this.setValue(0);
this.tempVal = 0;
diff --git a/src/main/java/forge/gui/toolbox/FSkin.java b/src/main/java/forge/gui/toolbox/FSkin.java
index 12d707febad..88f723e3f15 100644
--- a/src/main/java/forge/gui/toolbox/FSkin.java
+++ b/src/main/java/forge/gui/toolbox/FSkin.java
@@ -37,6 +37,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;
+import forge.FThreads;
import forge.gui.GuiUtils;
import forge.view.FView;
@@ -419,7 +420,7 @@ public enum FSkin {
*/
public static void loadLight(final String skinName) {
// No need for this method to be loaded while on the EDT.
- GuiUtils.checkEDT("FSkin$constructor", false);
+ FThreads.checkEDT("FSkin$constructor", false);
// Non-default (preferred) skin name and dir.
FSkin.preferredName = skinName.toLowerCase().replace(' ', '_');
@@ -479,7 +480,7 @@ public enum FSkin {
*/
public static void loadFull() {
// No need for this method to be loaded while on the EDT.
- GuiUtils.checkEDT("FSkin$load", false);
+ FThreads.checkEDT("FSkin$load", false);
// Preferred skin name must be called via loadLight() method,
// which does some cleanup and init work.
diff --git a/src/main/java/forge/model/FModel.java b/src/main/java/forge/model/FModel.java
index 56a9f31bd40..5a40205d8e5 100644
--- a/src/main/java/forge/model/FModel.java
+++ b/src/main/java/forge/model/FModel.java
@@ -27,6 +27,7 @@ import java.util.List;
import forge.Constant;
import forge.Constant.Preferences;
+import forge.FThreads;
import forge.card.BoosterData;
import forge.card.CardBlock;
import forge.card.CardRulesReader;
@@ -43,7 +44,6 @@ import forge.game.MatchController;
import forge.game.limited.GauntletMini;
import forge.game.player.LobbyPlayer;
import forge.gauntlet.GauntletData;
-import forge.gui.GuiUtils;
import forge.item.CardDb;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
@@ -161,7 +161,7 @@ public enum FModel {
this.loadDynamicGamedata();
// Loads all cards (using progress bar).
- GuiUtils.checkEDT("CardFactory$constructor", false);
+ FThreads.checkEDT("CardFactory$constructor", false);
final CardStorageReader reader = new CardStorageReader(NewConstants.CARD_DATA_DIR, true);
try {
// this fills in our map of card names to Card instances.
diff --git a/src/main/java/forge/util/ThreadUtil.java b/src/main/java/forge/util/ThreadUtil.java
deleted file mode 100644
index 4abc7967ae9..00000000000
--- a/src/main/java/forge/util/ThreadUtil.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * The files in the directory "net/slightlymagic/braids" and in all subdirectories of it (the "Files") are
- * Copyright 2011 Braids Cabal-Conjurer. They are available under either Forge's
- * main license (the GNU Public License; see LICENSE.txt in Forge's top directory)
- * or under the Apache License, as explained below.
- *
- * The Files are additionally licensed under the Apache License, Version 2.0 (the
- * "Apache License"); you may not use the files in this directory except in
- * compliance with one of its two licenses. You may obtain a copy of the Apache
- * License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Apache License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License for the specific language governing permissions and
- * limitations under the Apache License.
- *
- */
-package forge.util;
-
-import java.lang.reflect.InvocationTargetException;
-
-import javax.swing.SwingUtilities;
-
-/**
- * Some general-purpose functions.
- */
-public final class ThreadUtil {
-
- /**
- * Invoke the given Runnable in an Event Dispatch Thread and wait for it to
- * finish; but try to use SwingUtilities.invokeLater instead whenever
- * feasible.
- *
- * Exceptions generated by SwingUtilities.invokeAndWait (if used), are
- * rethrown as RuntimeExceptions.
- *
- * @param proc
- * the Runnable to run
- * @see javax.swing.SwingUtilities#invokeLater(Runnable)
- */
- public static void invokeInEventDispatchThreadAndWait(final Runnable proc) {
- // by
- // Braids
- // on
- // 8/18/11
- // 11:19
- // PM
- if (SwingUtilities.isEventDispatchThread()) {
- // Just run in the current thread.
- proc.run();
- } else {
- try {
- SwingUtilities.invokeAndWait(proc);
- } catch (final InterruptedException exn) {
- throw new RuntimeException(exn);
- // 11:19 PM
- } catch (final InvocationTargetException exn) {
- throw new RuntimeException(exn);
- // 11:19 PM
- }
- }
- }
-
-
-}