Added syncPoint between a moment when Game thread adds input to stack and EDT->showMessage, to ensure Game thread's changes happen-before whatever EDT will read

input/InputAttack.java is initialized with combat instead of game (cosmtic change though)
CMatchUI stopAtPhase will use an existing method to get the needed checkBox
This commit is contained in:
Maxmtg
2013-05-29 18:41:04 +00:00
parent f939aa13a5
commit 0a33b93903
5 changed files with 29 additions and 35 deletions

View File

@@ -88,11 +88,19 @@ public class InputQueue extends MyObservable implements java.io.Serializable {
public void setInputAndWait(InputSynchronized input) {
this.inputStack.push(input);
syncPoint();
this.updateObservers();
input.awaitLatchRelease();
}
public void syncPoint() {
synchronized (inputLock) {
// acquire and release lock, so that actions from Game thread happen before EDT reads their results
}
}
/**
* TODO: Write javadoc for this method.
*/

View File

@@ -493,7 +493,7 @@ public class PlayerControllerHuman extends PlayerController {
case COMBAT_DECLARE_ATTACKERS:
game.getCombat().initiatePossibleDefenders(player.getOpponents());
InputSynchronized inpAttack = new InputAttack(player);
InputSynchronized inpAttack = new InputAttack(player, game.getCombat());
Singletons.getControl().getInputQueue().setInputAndWait(inpAttack);
return;

View File

@@ -62,6 +62,7 @@ public class InputProxy implements Observer {
Runnable showMessage = new Runnable() {
@Override public void run() {
Input current = getInput();
Singletons.getControl().getInputQueue().syncPoint();
//System.out.printf("\t%s > showMessage @ %s/%s during %s%n", FThreads.debugGetCurrThreadId(), nextInput.getClass().getSimpleName(), current.getClass().getSimpleName(), game.getPhaseHandler().debugPrintState());
current.showMessageInitial();
}

View File

@@ -26,10 +26,9 @@ import com.google.common.collect.Iterables;
import forge.Card;
import forge.CardPredicates;
import forge.GameEntity;
import forge.game.Game;
import forge.game.phase.Combat;
import forge.game.phase.CombatUtil;
import forge.game.player.Player;
import forge.game.zone.Zone;
import forge.game.zone.ZoneType;
import forge.util.MyObservable;
import forge.view.ButtonUtil;
@@ -47,14 +46,15 @@ public class InputAttack extends InputSyncronizedBase {
private static final long serialVersionUID = 7849903731842214245L;
private final Game game;
private List<GameEntity> defenders;
private final Combat combat;
private final List<GameEntity> defenders;
private GameEntity currentDefender;
private final Player player;
public InputAttack(Player human) {
player = human;
game = human.getGame();
public InputAttack(Player human, Combat combat) {
this.player = human;
this.combat = combat;
this.defenders = combat.getDefenders();
}
@@ -64,7 +64,7 @@ public class InputAttack extends InputSyncronizedBase {
// TODO still seems to have some issues with multiple planeswalkers
ButtonUtil.enableOnlyOk();
defenders = game.getCombat().getDefenders();
setCurrentDefender(defenders.isEmpty() ? null : defenders.get(0));
if ( null == currentDefender ) {
@@ -78,8 +78,8 @@ public class InputAttack extends InputSyncronizedBase {
continue; // do not force
for(GameEntity def : defenders ) {
if( CombatUtil.canAttack(c, def, game.getCombat()) ) {
game.getCombat().addAttacker(c, currentDefender);
if( CombatUtil.canAttack(c, def, combat) ) {
combat.addAttacker(c, currentDefender);
break;
}
}
@@ -110,9 +110,9 @@ public class InputAttack extends InputSyncronizedBase {
/** {@inheritDoc} */
@Override
protected final void onCardSelected(final Card card, boolean isMetaDown) {
final List<Card> att = game.getCombat().getAttackers();
final List<Card> att = combat.getAttackers();
if (isMetaDown && att.contains(card) && !card.hasKeyword("CARDNAME attacks each turn if able.")) {
game.getCombat().removeFromCombat(card);
combat.removeFromCombat(card);
showCombat();
return;
}
@@ -128,12 +128,11 @@ public class InputAttack extends InputSyncronizedBase {
}
}
Zone zone = game.getZoneOf(card);
if (zone.is(ZoneType.Battlefield, player) && CombatUtil.canAttack(card, currentDefender, game.getCombat())) {
if( game.getCombat().isAttacking(card)) {
game.getCombat().removeFromCombat(card);
if (player.getZone(ZoneType.Battlefield).contains(card) && CombatUtil.canAttack(card, currentDefender, combat)) {
if( combat.isAttacking(card)) {
combat.removeFromCombat(card);
}
game.getCombat().addAttacker(card, currentDefender);
combat.addAttacker(card, currentDefender);
showCombat();
}
else {

View File

@@ -42,6 +42,7 @@ import forge.gui.match.controllers.CMessage;
import forge.gui.match.controllers.CPicture;
import forge.gui.match.nonsingleton.VCommand;
import forge.gui.match.nonsingleton.VField;
import forge.gui.match.nonsingleton.VField.PhaseLabel;
import forge.gui.match.nonsingleton.VHand;
import forge.gui.match.views.VPlayers;
import forge.gui.toolbox.FSkin;
@@ -233,23 +234,8 @@ public enum CMatchUI {
*/
public final boolean stopAtPhase(final Player turn, final PhaseType phase) {
VField vf = getFieldViewFor(turn);
switch (phase) {
case UPKEEP: return vf.getLblUpkeep().getEnabled();
case DRAW: return vf.getLblDraw().getEnabled();
case MAIN1: return vf.getLblMain1().getEnabled();
case COMBAT_BEGIN: return vf.getLblBeginCombat().getEnabled();
case COMBAT_DECLARE_ATTACKERS: return vf.getLblDeclareAttackers().getEnabled();
case COMBAT_DECLARE_BLOCKERS: return vf.getLblDeclareBlockers().getEnabled();
case COMBAT_FIRST_STRIKE_DAMAGE: return vf.getLblFirstStrike().getEnabled();
case COMBAT_DAMAGE: return vf.getLblCombatDamage().getEnabled();
case COMBAT_END: return vf.getLblEndCombat().getEnabled();
case MAIN2: return vf.getLblMain2().getEnabled();
case END_OF_TURN: return vf.getLblEndTurn().getEnabled();
default:
}
return true;
PhaseLabel label = vf.getLabelFor(phase);
return label == null || label.isTurnedOn();
}
public void setCard(final Card c) {