From 099c1ed11c82393608b8e522e0074ed521b8adf1 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 20:23:46 +0000 Subject: [PATCH] Changing new input setup. A special thread will set up new input to actual state. This will eliminate the longest stack traces --- .gitattributes | 2 +- .../ability/effects/RestartGameEffect.java | 2 +- .../forge/control/input/InputControl.java | 25 ++- src/main/java/forge/game/GameNew.java | 151 ++++++++++-------- src/main/java/forge/game/MatchController.java | 7 +- .../gui/{GuiInput.java => InputProxy.java} | 30 ++-- .../forge/gui/match/controllers/CMessage.java | 6 +- 7 files changed, 125 insertions(+), 98 deletions(-) rename src/main/java/forge/gui/{GuiInput.java => InputProxy.java} (69%) diff --git a/.gitattributes b/.gitattributes index d0cd306df1e..a2d664be4c6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14220,9 +14220,9 @@ src/main/java/forge/gui/GuiChoose.java -text src/main/java/forge/gui/GuiDialog.java -text src/main/java/forge/gui/GuiDisplayUtil.java svneol=native#text/plain src/main/java/forge/gui/GuiImportPicture.java svneol=native#text/plain -src/main/java/forge/gui/GuiInput.java svneol=native#text/plain src/main/java/forge/gui/GuiProgressBarWindow.java svneol=native#text/plain src/main/java/forge/gui/GuiUtils.java svneol=native#text/plain +src/main/java/forge/gui/InputProxy.java svneol=native#text/plain src/main/java/forge/gui/ListChooser.java svneol=native#text/plain src/main/java/forge/gui/MultiLineLabel.java svneol=native#text/plain src/main/java/forge/gui/MultiLineLabelUI.java svneol=native#text/plain diff --git a/src/main/java/forge/card/ability/effects/RestartGameEffect.java b/src/main/java/forge/card/ability/effects/RestartGameEffect.java index a4d60190aae..91fa1d8ccaa 100644 --- a/src/main/java/forge/card/ability/effects/RestartGameEffect.java +++ b/src/main/java/forge/card/ability/effects/RestartGameEffect.java @@ -48,7 +48,7 @@ public class RestartGameEffect extends SpellAbilityEffect { playerLibraries.put(p, newLibrary); } - GameNew.restartGame(game, sa.getActivatingPlayer(), playerLibraries); + GameNew.restartGame(Singletons.getModel().getMatch(), game, sa.getActivatingPlayer(), playerLibraries); } /* (non-Javadoc) diff --git a/src/main/java/forge/control/input/InputControl.java b/src/main/java/forge/control/input/InputControl.java index 83a3def162e..01cccb60cbf 100644 --- a/src/main/java/forge/control/input/InputControl.java +++ b/src/main/java/forge/control/input/InputControl.java @@ -25,6 +25,7 @@ import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.zone.MagicStack; +import forge.gui.match.controllers.CMessage; import forge.util.MyObservable; /** @@ -65,7 +66,7 @@ public class InputControl extends MyObservable implements java.io.Serializable { */ public final void setInput(final Input in) { boolean isInputEmpty = this.input == null || this.input instanceof InputPassPriority; - System.out.println(in.getClass().getName()); + //System.out.println(in.getClass().getName()); if (!this.game.getStack().isResolving() && isInputEmpty) { this.input = in; } else { @@ -134,12 +135,9 @@ public class InputControl extends MyObservable implements java.io.Serializable { * @param update * a boolean. */ - public final void resetInput() { resetInput(true); } - public final void resetInput(final boolean update) { + public final void resetInput() { this.input = null; - if (update) { - this.updateObservers(); - } + this.updateObservers(); } /** @@ -244,4 +242,19 @@ public class InputControl extends MyObservable implements java.io.Serializable { return pc.getDefaultInput(); } // getInput() + public final void setNewInput(GameState game) { + PhaseHandler ph = game.getPhaseHandler(); + + final Input tmp = getActualInput(); + //String message = String.format("%s's %s, priority of %s [%sP] input is %s", ph.getPlayerTurn(), ph.getPhase(), ph.getPriorityPlayer(), ph.isPlayerPriorityAllowed() ? "+" : "-", tmp == null ? "null" : tmp.getClass().getSimpleName()); + //System.out.println(message); + if (tmp != null) { + //System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() ); + CMessage.SINGLETON_INSTANCE.getInputControl().setInput(tmp); + } else if (!ph.isPlayerPriorityAllowed()) { + // System.out.println("cannot have priority, forced to pass"); + ph.getPriorityPlayer().getController().passPriority(); + } + } + } // InputControl diff --git a/src/main/java/forge/game/GameNew.java b/src/main/java/forge/game/GameNew.java index f0ad3c3b15d..e80a1fa73c2 100644 --- a/src/main/java/forge/game/GameNew.java +++ b/src/main/java/forge/game/GameNew.java @@ -11,8 +11,6 @@ import java.util.Set; import javax.swing.JOptionPane; - - import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; @@ -25,11 +23,13 @@ import forge.CardUtil; import forge.Singletons; import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerType; +import forge.control.input.Input; import forge.control.input.InputControl; import forge.control.input.InputMulligan; import forge.deck.Deck; import forge.deck.CardPool; import forge.deck.DeckSection; +import forge.error.BugReporter; import forge.game.event.FlipCoinEvent; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; @@ -38,9 +38,11 @@ import forge.game.player.LobbyPlayer; import forge.game.player.Player; import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; +import forge.gui.match.controllers.CMessage; import forge.gui.match.views.VAntes; import forge.item.CardPrinted; import forge.item.IPaperCard; +import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; import forge.util.Aggregates; import forge.util.MyRandom; @@ -50,6 +52,45 @@ import forge.util.MyRandom; * All of these methods can and should be static. */ public class GameNew { + + /** + * TODO: Write javadoc for this type. + * + */ + public static final class GameInputUpdatesThread extends Thread { + private final MatchController match; + private final GameState game; + private boolean wasChangedRecently; + + /** + * TODO: Write javadoc for Constructor. + * @param match + * @param game + */ + public GameInputUpdatesThread(MatchController match, GameState game) { + this.match = match; + this.game = game; + } + + public void run(){ + while(!game.isGameOver()) { + boolean needsNewInput = CMessage.SINGLETON_INSTANCE.getInputControl().isValid() == false; + if ( needsNewInput ) { + match.getInput().setNewInput(game); + wasChangedRecently = true; + } + try { + Thread.sleep(wasChangedRecently ? 2 : 40); + wasChangedRecently = false; + } catch (InterruptedException e) { + BugReporter.reportException(e); + break; + } + } + } + } + + public static final ForgePreferences preferences = Singletons.getModel().getPreferences(); private static void preparePlayerLibrary(Player player, final ZoneType zoneType, CardPool secion, boolean canRandomFoil, Random generator) { PlayerZone library = player.getZone(zoneType); @@ -60,7 +101,7 @@ public class GameNew { final Card card = cardPrinted.toForgeCard(player); // apply random pictures for cards - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_CARD_ART)) { + if (preferences.getPrefBoolean(FPref.UI_RANDOM_CARD_ART)) { final int cntVariants = cardPrinted.getRules().getEditionInfo(cardPrinted.getEdition()).getCopiesCount(); if (cntVariants > 1) { card.setRandomPicture(generator.nextInt(cntVariants - 1) + 1); @@ -86,8 +127,8 @@ public class GameNew { * TODO: Accept something like match state as parameter. Match should be aware of players, * their decks and other special starting conditions. */ - public static void newGame(final Map playersConditions, final GameState game, final boolean canRandomFoil) { - Singletons.getModel().getMatch().getInput().clearInput(); + public static void newGame(final MatchController match, final Map playersConditions, final GameState game, final boolean canRandomFoil) { + match.getInput().clearInput(); Card.resetUniqueNumber(); // need this code here, otherwise observables fail @@ -97,7 +138,7 @@ public class GameNew { trigHandler.clearDelayedTrigger(); // friendliness - boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE); + boolean useAnte = preferences.getPrefBoolean(FPref.UI_ANTE); final Set rAICards = new HashSet(); Map> removedAnteCards = new HashMap>(); @@ -112,8 +153,8 @@ public class GameNew { initVariantsZones(player, psc); - GameType gameType = Singletons.getModel().getMatch().getGameType(); - boolean isFirstGame = Singletons.getModel().getMatch().getPlayedGames().isEmpty(); + GameType gameType = match.getGameType(); + boolean isFirstGame = match.getPlayedGames().isEmpty(); boolean hasSideboard = psc.getOriginalDeck().has(DeckSection.Sideboard); boolean canSideBoard = !isFirstGame && gameType.isSideboardingAllowed() && hasSideboard; @@ -132,7 +173,7 @@ public class GameNew { preparePlayerLibrary(player, ZoneType.Sideboard, myDeck.get(DeckSection.Sideboard), canRandomFoil, generator); // Shuffling - if (player instanceof AIPlayer && Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_SMOOTH_LAND)) { + if (player instanceof AIPlayer && preferences.getPrefBoolean(FPref.UI_SMOOTH_LAND)) { // AI may do this instead of shuffling its deck final Iterable c1 = GameNew.smoothComputerManaCurve(player.getCardsIn(ZoneType.Library)); player.getZone(ZoneType.Library).setCards(c1); @@ -174,7 +215,7 @@ public class GameNew { JOptionPane.showMessageDialog(null, ante.toString(), "", JOptionPane.INFORMATION_MESSAGE); } - GameNew.actuateGame(game, false); + GameNew.actuateGame(match, game, false); } private static void initVariantsZones(final Player player, final PlayerStartConditions psc) { @@ -243,8 +284,7 @@ public class GameNew { } // ultimate of Karn the Liberated - public static void restartGame(final GameState game, final Player startingTurn, Map> playerLibraries) { - MatchController match = Singletons.getModel().getMatch(); + public static void restartGame(final MatchController match, final GameState game, final Player startingTurn, Map> playerLibraries) { Map players = match.getPlayers(); Map playersConditions = new HashMap(); @@ -291,7 +331,7 @@ public class GameNew { PhaseHandler phaseHandler = game.getPhaseHandler(); phaseHandler.setPlayerTurn(startingTurn); - GameNew.actuateGame(game, true); + GameNew.actuateGame(match, game, true); } /** @@ -302,10 +342,10 @@ public class GameNew { * newGame, then when all is ready, call this function. * @param isRestartedGame Whether the actuated game is the first start or a restart */ - private static void actuateGame(final GameState game, boolean isRestartedGame) { + private static void actuateGame(final MatchController match, final GameState game, boolean isRestartedGame) { if (!isRestartedGame) { // Deciding which cards go to ante - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE)) { + if (preferences.getPrefBoolean(FPref.UI_ANTE)) { final String nl = System.getProperty("line.separator"); final StringBuilder msg = new StringBuilder(); for (final Player p : game.getPlayers()) { @@ -324,15 +364,24 @@ public class GameNew { JOptionPane.showMessageDialog(null, msg, "Ante", JOptionPane.INFORMATION_MESSAGE); } - GameOutcome lastGameOutcome = Singletons.getModel().getMatch().getLastGameOutcome(); + GameOutcome lastGameOutcome = match.getLastGameOutcome(); // Only cut/coin toss if it's the first game of the match - if (lastGameOutcome == null) { - GameNew.seeWhoPlaysFirstDice(); + Player goesFirst; + Player humanPlayer = Singletons.getControl().getPlayer(); + boolean isFirstGame = lastGameOutcome == null; + if (isFirstGame) { + goesFirst = GameNew.seeWhoPlaysFirstDice(game); } else { - Player human = Singletons.getControl().getPlayer(); - Player goesFirst = lastGameOutcome.isWinner(human.getLobbyPlayer()) ? human.getOpponent() : human; - setPlayersFirstTurn(goesFirst, false); + + goesFirst = lastGameOutcome.isWinner(humanPlayer.getLobbyPlayer()) ? humanPlayer.getOpponent() : humanPlayer; } + String message = goesFirst + ( isFirstGame ? " has won the coin toss." : " lost the last game."); + boolean willPlay = goesFirst.getController().getWillPlayOnFirstTurn(message); + if ( goesFirst != humanPlayer ) { + JOptionPane.showMessageDialog(null, message + "\nComputer Going First", "You are drawing", JOptionPane.INFORMATION_MESSAGE); + } + goesFirst = willPlay ? goesFirst : goesFirst.getOpponent(); + game.getPhaseHandler().setPlayerTurn(goesFirst); } // Draw cards @@ -340,9 +389,20 @@ public class GameNew { p.drawCards(p.getMaxHandSize()); } + + game.getPhaseHandler().setPhaseState(PhaseType.MULLIGAN); - InputControl control = Singletons.getModel().getMatch().getInput(); - control.setInput(new InputMulligan()); + + InputControl control = match.getInput(); + Input tmp = new InputMulligan(); + control.setInput(tmp); + + + Thread thGame = new GameInputUpdatesThread(match, game); + + match.getInput().getInput().showMessage(); + thGame.setName("Game input updater"); + thGame.start(); } // newGame() private static String buildFourColumnList(String firstLine, Iterable cAnteRemoved) { @@ -418,49 +478,14 @@ public class GameNew { *

* seeWhoPlaysFirstCoinToss. *

+ * @return */ - private static void seeWhoPlaysFirstDice() { - int playerDie = 0; - int computerDie = 0; - - while (playerDie == computerDie) { - playerDie = MyRandom.getRandom().nextInt(20); - computerDie = MyRandom.getRandom().nextInt(20); - } - + private static Player seeWhoPlaysFirstDice(final GameState game) { // Play the Flip Coin sound - Singletons.getModel().getGame().getEvents().post(new FlipCoinEvent()); + game.getEvents().post(new FlipCoinEvent()); - List allPlayers = Singletons.getModel().getGame().getPlayers(); - setPlayersFirstTurn(allPlayers.get(MyRandom.getRandom().nextInt(allPlayers.size())), true); + List allPlayers = game.getPlayers(); + return allPlayers.get(MyRandom.getRandom().nextInt(allPlayers.size())); } - private static void setPlayersFirstTurn(Player goesFirst, boolean firstGame) { - StringBuilder sb = new StringBuilder(goesFirst.toString()); - if (firstGame) { - sb.append(" has won the coin toss."); - } - else { - sb.append(" lost the last game."); - } - if (goesFirst.isHuman()) { - if (!humanPlayOrDraw(sb.toString())) { - goesFirst = goesFirst.getOpponent(); - } - } else { - sb.append("\nComputer Going First"); - JOptionPane.showMessageDialog(null, sb.toString(), "Play or Draw?", JOptionPane.INFORMATION_MESSAGE); - } - Singletons.getModel().getGame().getPhaseHandler().setPlayerTurn(goesFirst); - } // seeWhoPlaysFirstDice() - - private static boolean humanPlayOrDraw(String message) { - final String[] possibleValues = { "Play", "Draw" }; - - final Object playDraw = JOptionPane.showOptionDialog(null, message + "\n\nWould you like to play or draw?", - "Play or Draw?", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, - possibleValues, possibleValues[0]); - - return !playDraw.equals(1); - } } diff --git a/src/main/java/forge/game/MatchController.java b/src/main/java/forge/game/MatchController.java index c3c87c78df6..4f0e9455979 100644 --- a/src/main/java/forge/game/MatchController.java +++ b/src/main/java/forge/game/MatchController.java @@ -19,7 +19,7 @@ import forge.game.player.Player; import forge.game.player.PlayerStatistics; import forge.game.player.PlayerType; import forge.game.zone.ZoneType; -import forge.gui.GuiInput; +import forge.gui.InputProxy; import forge.gui.framework.EDocID; import forge.gui.framework.SDisplayUtil; import forge.gui.match.CMatchUI; @@ -149,8 +149,7 @@ public class MatchController { Singletons.getControl().changeState(FControl.Screens.MATCH_SCREEN); SDisplayUtil.showTab(EDocID.REPORT_LOG.getDoc()); - // set all observers - GuiInput inputControl = CMessage.SINGLETON_INSTANCE.getInputControl(); + InputProxy inputControl = CMessage.SINGLETON_INSTANCE.getInputControl(); input.addObserver(inputControl); currentGame.getStack().addObserver(inputControl); currentGame.getPhaseHandler().addObserver(inputControl); @@ -159,7 +158,7 @@ public class MatchController { // some observers are set in CMatchUI.initMatch final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed; - GameNew.newGame(startConditions, currentGame, canRandomFoil); + GameNew.newGame(this, startConditions, currentGame, canRandomFoil); // TODO restore this functionality!!! //VMatchUI.SINGLETON_INSTANCE.getViewDevMode().getDocument().setVisible(Preferences.DEV_MODE); diff --git a/src/main/java/forge/gui/GuiInput.java b/src/main/java/forge/gui/InputProxy.java similarity index 69% rename from src/main/java/forge/gui/GuiInput.java rename to src/main/java/forge/gui/InputProxy.java index 787f195b2c1..d767040375b 100644 --- a/src/main/java/forge/gui/GuiInput.java +++ b/src/main/java/forge/gui/InputProxy.java @@ -21,9 +21,7 @@ import java.util.Observable; import java.util.Observer; import forge.Card; -import forge.Singletons; import forge.control.input.Input; -import forge.game.phase.PhaseHandler; import forge.game.player.Player; import forge.game.zone.PlayerZone; import forge.util.MyObservable; @@ -36,28 +34,16 @@ import forge.util.MyObservable; * @author Forge * @version $Id$ */ -public class GuiInput extends MyObservable implements Observer { +public class InputProxy extends MyObservable implements Observer { /** The input. */ private Input input; + private volatile boolean valid = false; - - /** {@inheritDoc} */ @Override public final void update(final Observable observable, final Object obj) { - PhaseHandler ph = Singletons.getModel().getGame().getPhaseHandler(); - - final Input tmp = Singletons.getModel().getMatch().getInput().getActualInput(); - // System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ actual input is " + ( tmp == null ? "null" : tmp.getClass().getName()) + "; MHP = " + ph.mayPlayerHavePriority() ); - if (tmp != null) { - // System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() ); - this.setInput(tmp); - } else if (!ph.isPlayerPriorityAllowed()) { - //System.out.println("cannot have priority, forced to pass"); - ph.passPriority(); - } + valid = false; } - /** *

* Setter for the field input. @@ -66,9 +52,10 @@ public class GuiInput extends MyObservable implements Observer { * @param in * a {@link forge.control.input.Input} object. */ - private void setInput(final Input in) { + public void setInput(final Input in) { + valid = true; this.input = in; - this.input.showMessage(); + this.input.showMessage(); // this call may invalidate the input by the time it returns } /** @@ -121,10 +108,13 @@ public class GuiInput extends MyObservable implements Observer { return this.getInput().toString(); } - /** @return {@link forge.gui.GuiInput.Input} */ + /** @return {@link forge.gui.InputProxy.Input} */ public Input getInput() { return this.input; } + public boolean isValid() { + return valid; + } } diff --git a/src/main/java/forge/gui/match/controllers/CMessage.java b/src/main/java/forge/gui/match/controllers/CMessage.java index 0e4573e6d5c..ba32802f0b8 100644 --- a/src/main/java/forge/gui/match/controllers/CMessage.java +++ b/src/main/java/forge/gui/match/controllers/CMessage.java @@ -28,7 +28,7 @@ import javax.swing.JButton; import forge.Command; import forge.game.MatchController; -import forge.gui.GuiInput; +import forge.gui.InputProxy; import forge.gui.framework.ICDoc; import forge.gui.framework.SDisplayUtil; import forge.gui.match.views.VMessage; @@ -42,7 +42,7 @@ public enum CMessage implements ICDoc { /** */ SINGLETON_INSTANCE; - private GuiInput inputControl = new GuiInput(); + private InputProxy inputControl = new InputProxy(); private Component lastFocusedButton = null; private final ActionListener actCancel = new ActionListener() { @@ -87,7 +87,7 @@ public enum CMessage implements ICDoc { * * @return GuiInput */ - public GuiInput getInputControl() { + public InputProxy getInputControl() { return this.inputControl; }