Prevent crash when starting game without name configured

Avoid unnecessary duplication of event handling when two human players
Avoid duplicate copies of views when two human players
This commit is contained in:
drdev
2014-09-25 15:49:23 +00:00
parent 70f780ab11
commit a89c9df904
5 changed files with 146 additions and 95 deletions

View File

@@ -63,10 +63,12 @@ import forge.view.LocalGameView;
import forge.view.PlayerView;
public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
private final LocalGameView gameView;
public FControlGameEventHandler(final LocalGameView gameView0) {
private final boolean isMainHandler;
public FControlGameEventHandler(final LocalGameView gameView0, final boolean isMainHandler0) {
gameView = gameView0;
isMainHandler = isMainHandler0;
}
@Subscribe
@@ -77,7 +79,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
private final AtomicBoolean phaseUpdPlanned = new AtomicBoolean(false);
@Override
public Void visit(final GameEventTurnPhase ev) {
if (phaseUpdPlanned.getAndSet(true)) return null;
if (!isMainHandler || phaseUpdPlanned.getAndSet(true)) { return null; }
FThreads.invokeInEdtNowOrLater(gameView.getGui(), new Runnable() {
@Override
@@ -95,7 +97,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
private final AtomicBoolean combatUpdPlanned = new AtomicBoolean(false);
@Override
public Void visit(GameEventPlayerPriority event) {
if (combatUpdPlanned.getAndSet(true)) { return null; }
if (!isMainHandler || combatUpdPlanned.getAndSet(true)) { return null; }
FThreads.invokeInEdtNowOrLater(gameView.getGui(), new Runnable() {
@Override
public void run() {
@@ -109,6 +112,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
private final AtomicBoolean turnUpdPlanned = new AtomicBoolean(false);
@Override
public Void visit(final GameEventTurnBegan event) {
if (!isMainHandler) { return null; }
if (FModel.getPreferences().getPrefBoolean(FPref.UI_STACK_CREATURES) && event.turnOwner != null) {
// anything except stack will get here
updateZone(Pair.of(gameView.getPlayerView(event.turnOwner), ZoneType.Battlefield));
@@ -128,6 +133,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventAnteCardsSelected ev) {
if (!isMainHandler) { return null; }
final List<CardView> options = Lists.newArrayList();
for (final Entry<Player, Card> kv : ev.cards.entries()) {
final CardView fakeCard = new CardView(true); //use fake card so real cards appear with proper formatting
@@ -176,13 +183,11 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
InputBase.cancelAwaitNextInput(); //ensure "Waiting for opponent..." doesn't appear behind WinLo
MatchUtil.getController().showPromptMessage(localPlayer, ""); //clear prompt behind WinLose overlay
ButtonUtil.update(localPlayer, "", "", false, false, false);
//only finish game once, and only if player is Gui player or Gui player isn't playing
if (localPlayer.getLobbyPlayer() == GamePlayerUtil.getGuiPlayer() || MatchUtil.getHumanCount() == 0) {
if (isMainHandler) {
MatchUtil.getController().finishGame();
}
gameView.updateAchievements();
}
}
});
return null;
}
@@ -198,6 +203,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventSpellAbilityCast event) {
if (!isMainHandler) { return null; }
if (!stackUpdPlanned.getAndSet(true)) {
FThreads.invokeInEdtNowOrLater(gameView.getGui(), updStack);
}
@@ -205,6 +212,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
}
@Override
public Void visit(GameEventSpellResolved event) {
if (!isMainHandler) { return null; }
if (!stackUpdPlanned.getAndSet(true)) {
FThreads.invokeInEdtNowOrLater(gameView.getGui(), updStack);
}
@@ -212,6 +221,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
}
@Override
public Void visit(GameEventSpellRemovedFromStack event) {
if (!isMainHandler) { return null; }
if (!stackUpdPlanned.getAndSet(true)) {
FThreads.invokeInEdtNowOrLater(gameView.getGui(), updStack);
}
@@ -231,6 +242,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventZone event) {
if (!isMainHandler) { return null; }
if (event.player != null) {
// anything except stack will get here
updateZone(Pair.of(gameView.getPlayerView(event.player), event.zoneType));
@@ -240,6 +253,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventCardAttachment event) {
if (!isMainHandler) { return null; }
final Game game = event.equipment.getGame();
final PlayerZone zEq = (PlayerZone)game.getZoneOf(event.equipment);
if (event.oldEntiy instanceof Card) {
@@ -283,26 +298,36 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(final GameEventCardTapped event) {
if (!isMainHandler) { return null; }
return updateSingleCard(gameView.getCardView(event.card));
}
@Override
public Void visit(final GameEventCardPhased event) {
if (!isMainHandler) { return null; }
return updateSingleCard(gameView.getCardView(event.card));
}
@Override
public Void visit(final GameEventCardDamaged event) {
if (!isMainHandler) { return null; }
return updateSingleCard(gameView.getCardView(event.card));
}
@Override
public Void visit(final GameEventCardCounters event) {
if (!isMainHandler) { return null; }
return updateSingleCard(gameView.getCardView(event.card));
}
@Override
public Void visit(final GameEventBlockersDeclared event) { // This is to draw icons on blockers declared by AI
if (!isMainHandler) { return null; }
for (MapOfLists<Card, Card> kv : event.blockers.values()) {
for (Collection<Card> blockers : kv.values()) {
updateManyCards(gameView.getCardViews(blockers));
@@ -313,13 +338,15 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventAttackersDeclared event) {
if (!isMainHandler) { return null; }
// Skip redraw for GUI player?
if (event.player.getLobbyPlayer() == GamePlayerUtil.getGuiPlayer()) {
return null;
}
// Update all attackers.
// Although they might have been updated when they were apped, there could be someone with vigilance, not redrawn yet.
// Although they might have been updated when they were tapped, there could be someone with vigilance, not redrawn yet.
updateManyCards(gameView.getCardViews(event.attackersMap.values()));
return super.visit(event);
@@ -327,6 +354,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventCombatEnded event) {
if (!isMainHandler) { return null; }
// This should remove sword/shield icons from combatants by the time game moves to M2
updateManyCards(gameView.getCardViews(event.attackers));
updateManyCards(gameView.getCardViews(event.blockers));
@@ -361,6 +390,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventCardChangeZone event) {
if (!isMainHandler) { return null; }
if (event.from != null) {
updateZone(event.from);
}
@@ -375,6 +406,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
*/
@Override
public Void visit(GameEventCardStatsChanged event) {
if (!isMainHandler) { return null; }
final Iterable<CardView> cardViews = gameView.getCardViews(event.cards);
MatchUtil.getController().refreshCardDetails(cardViews);
return updateManyCards(cardViews);
@@ -382,6 +415,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventPlayerStatsChanged event) {
if (!isMainHandler) { return null; }
for (final Player p : event.players) {
MatchUtil.getController().refreshCardDetails(gameView.getCardViews(p.getAllCards()));
}
@@ -390,6 +425,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventShuffle event) {
if (!isMainHandler) { return null; }
updateZone(event.player.getZone(ZoneType.Library));
return null;
}
@@ -407,6 +444,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventManaPool event) {
if (!isMainHandler) { return null; }
boolean invokeUpdate = false;
synchronized (manaPoolUpdate) {
if (!manaPoolUpdate.contains(event.player)) {
@@ -432,6 +471,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
};
@Override
public Void visit(GameEventPlayerLivesChanged event) {
if (!isMainHandler) { return null; }
boolean invokeUpdate = false;
synchronized (livesUpdate) {
if (!livesUpdate.contains(event.player)) {
@@ -447,6 +488,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
@Override
public Void visit(GameEventPlayerPoisoned event) {
if (!isMainHandler) { return null; }
boolean invokeUpdate = false;
synchronized (livesUpdate) {
if (!livesUpdate.contains(event.receiver)) {

View File

@@ -40,6 +40,8 @@ import forge.game.card.CounterType;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.RegisteredPlayer;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.match.input.InputPlaybackControl;
@@ -49,7 +51,6 @@ import forge.model.FModel;
import forge.player.GamePlayerUtil;
import forge.player.LobbyPlayerHuman;
import forge.player.PlayerControllerHuman;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.quest.QuestController;
import forge.sound.MusicPlaylist;
@@ -57,16 +58,29 @@ import forge.sound.SoundSystem;
import forge.util.GuiDisplayUtil;
import forge.util.NameGenerator;
import forge.util.gui.SOptionPane;
import forge.view.Cache;
import forge.view.CardView;
import forge.view.GameEntityView;
import forge.view.LocalGameView;
import forge.view.PlayerView;
import forge.view.SpellAbilityView;
import forge.view.StackItemView;
import forge.view.WatchLocalGame;
public class MatchUtil {
private static IMatchController controller;
private static Game game;
private static List<LocalGameView> gameViews = new ArrayList<LocalGameView>();
/** Cache of players. */
public static final Cache<Player, PlayerView> players = new Cache<>();
/** Cache of cards. */
public static final Cache<Card, CardView> cards = new Cache<>();
/** Cache of spellabilities. */
public static final Cache<SpellAbility, SpellAbilityView> spabs = new Cache<>();
/** Cache of stack items. */
public static final Cache<SpellAbilityStackInstance, StackItemView> stackItems = new Cache<>();
private static int humanCount;
private static final EventBus uiEvents;
private static FControlGamePlayback playbackControl;
@@ -122,16 +136,6 @@ public class MatchUtil {
public static void startGame(final Match match) {
if (!controller.resetForNewGame()) { return; }
//prompt user for player one name if needed
final ForgePreferences prefs = FModel.getPreferences();
if (StringUtils.isBlank(prefs.getPref(FPref.PLAYER_NAME))) {
boolean isPlayerOneHuman = match.getPlayers().get(0).getPlayer() instanceof LobbyPlayerHuman;
boolean isPlayerTwoComputer = match.getPlayers().get(1).getPlayer() instanceof LobbyPlayerAi;
if (isPlayerOneHuman && isPlayerTwoComputer) {
GamePlayerUtil.setPlayerName(GuiBase.getInterface());
}
}
SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MATCH);
game = match.createGame();
@@ -147,7 +151,7 @@ public class MatchUtil {
game.subscribeToEvents(SoundSystem.instance);
final String[] indices = prefs.getPref(FPref.UI_AVATARS).split(",");
final String[] indices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
// Instantiate all required field slots (user at 0)
final List<Player> sortedPlayers = new ArrayList<Player>(game.getRegisteredPlayers());
@@ -175,7 +179,7 @@ public class MatchUtil {
if (p.getController() instanceof PlayerControllerHuman) {
final PlayerControllerHuman controller = (PlayerControllerHuman) p.getController();
LocalGameView gameView = controller.getGameView();
game.subscribeToEvents(new FControlGameEventHandler(gameView));
game.subscribeToEvents(new FControlGameEventHandler(gameView, humanCount == 0));
gameViews.add(gameView);
humanCount++;
}
@@ -184,7 +188,7 @@ public class MatchUtil {
if (humanCount == 0) { //watch game but do not participate
LocalGameView gameView = new WatchLocalGame(GuiBase.getInterface(), game);
gameView.setLocalPlayer(sortedPlayers.get(0));
game.subscribeToEvents(new FControlGameEventHandler(gameView));
game.subscribeToEvents(new FControlGameEventHandler(gameView, true));
gameViews.add(gameView);
}
else if (humanCount == sortedPlayers.size() && controller.hotSeatMode()) {
@@ -207,6 +211,14 @@ public class MatchUtil {
game.getAction().invoke(new Runnable() {
@Override
public void run() {
//prompt user for player one name if needed
if (StringUtils.isBlank(FModel.getPreferences().getPref(FPref.PLAYER_NAME))) {
boolean isPlayerOneHuman = match.getPlayers().get(0).getPlayer() instanceof LobbyPlayerHuman;
boolean isPlayerTwoComputer = match.getPlayers().get(1).getPlayer() instanceof LobbyPlayerAi;
if (isPlayerOneHuman && isPlayerTwoComputer) {
GamePlayerUtil.setPlayerName(GuiBase.getInterface());
}
}
match.startGame(game);
}
});

View File

@@ -6,6 +6,7 @@ import forge.ai.AiProfileUtil;
import forge.ai.LobbyPlayerAi;
import forge.game.player.Player;
import forge.interfaces.IGuiBase;
import forge.match.MatchUtil;
import forge.model.FModel;
import forge.properties.ForgePreferences.FPref;
import forge.util.GuiDisplayUtil;
@@ -73,18 +74,30 @@ public final class GamePlayerUtil {
public static void setPlayerName(final IGuiBase gui) {
String oldPlayerName = FModel.getPreferences().getPref(FPref.PLAYER_NAME);
String newPlayerName = null;
String newPlayerName;
if (StringUtils.isBlank(oldPlayerName)) {
newPlayerName = getVerifiedPlayerName(getPlayerNameUsingFirstTimePrompt(gui), oldPlayerName);
} else {
}
else {
newPlayerName = getVerifiedPlayerName(getPlayerNameUsingStandardPrompt(gui, oldPlayerName), oldPlayerName);
}
//update name for player in active game if needed
if (MatchUtil.getGame() != null) {
for (Player player : MatchUtil.getGame().getPlayers()) {
if (player.getLobbyPlayer() == MatchUtil.getGuiPlayer()) {
player.setName(newPlayerName);
player.getLobbyPlayer().setName(newPlayerName);
break;
}
}
}
FModel.getPreferences().setPref(FPref.PLAYER_NAME, newPlayerName);
FModel.getPreferences().save();
if (StringUtils.isBlank(oldPlayerName) && newPlayerName != "Human") {
if (StringUtils.isBlank(oldPlayerName) && !newPlayerName.equals("Human")) {
showThankYouPrompt(gui, newPlayerName);
}
}

View File

@@ -93,7 +93,6 @@ import forge.match.input.InputConfirmMulligan;
import forge.match.input.InputPassPriority;
import forge.match.input.InputPayMana;
import forge.match.input.InputProliferate;
import forge.match.input.InputProxy;
import forge.match.input.InputSelectCardsForConvoke;
import forge.match.input.InputSelectCardsFromList;
import forge.match.input.InputSelectEntitiesFromList;
@@ -153,10 +152,6 @@ public class PlayerControllerHuman extends PlayerController {
return gameView.getGui();
}
public InputProxy getInputProxy() {
return gameView.getInputProxy();
}
public LocalGameView getGameView() {
return gameView;
}

View File

@@ -28,6 +28,7 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.zone.ZoneType;
import forge.interfaces.IGuiBase;
import forge.match.MatchUtil;
import forge.match.input.InputProxy;
import forge.match.input.InputQueue;
@@ -69,15 +70,6 @@ public abstract class LocalGameView implements IGameView {
localPlayerView = getPlayerView(localPlayer);
}
/** Cache of players. */
private final Cache<Player, PlayerView> players = new Cache<>();
/** Cache of cards. */
private final Cache<Card, CardView> cards = new Cache<>();
/** Cache of spellabilities. */
private final Cache<SpellAbility, SpellAbilityView> spabs = new Cache<>();
/** Cache of stack items. */
private final Cache<SpellAbilityStackInstance, StackItemView> stackItems = new Cache<>();
/* (non-Javadoc)
* @see forge.view.IGameView#isCommander()
*/
@@ -261,7 +253,7 @@ public abstract class LocalGameView implements IGameView {
final List<SpellAbilityStackInstance> stack = Lists.newArrayList(game.getStack());
final List<StackItemView> items = Collections.unmodifiableList(getStack(stack));
// clear the cache
stackItems.retainAllKeys(stack);
MatchUtil.stackItems.retainAllKeys(stack);
return items;
}
@@ -278,20 +270,18 @@ public abstract class LocalGameView implements IGameView {
}
private List<StackItemView> getStack(final Iterable<SpellAbilityStackInstance> stack) {
synchronized (this) {
stackItems.retainAllKeys(Lists.newArrayList(stack));
MatchUtil.stackItems.retainAllKeys(Lists.newArrayList(stack));
final List<StackItemView> items = Lists.newLinkedList();
for (final SpellAbilityStackInstance si : stack) {
final int id = si.getId();
if (stackItems.containsKey(id)) {
items.add(stackItems.get(id));
if (MatchUtil.stackItems.containsKey(id)) {
items.add(MatchUtil.stackItems.get(id));
} else {
items.add(getStackItemView(si));
}
}
return items;
}
}
public StackItemView getStackItemView(final SpellAbilityStackInstance si) {
if (si == null) {
@@ -304,7 +294,7 @@ public abstract class LocalGameView implements IGameView {
si.getStackDescription(), getCardView(si.getSourceCard()),
getPlayerView(si.getActivator()), getCardViews(si.getTargetChoices().getTargetCards()),
getPlayerViews(si.getTargetChoices().getTargetPlayers()), si.isAbility(), si.isOptionalTrigger());
stackItems.put(si, newItem);
MatchUtil.stackItems.put(si, newItem);
return newItem;
}
@@ -312,7 +302,7 @@ public abstract class LocalGameView implements IGameView {
if (view == null) {
return null;
}
return stackItems.getKey(view.getId());
return MatchUtil.stackItems.getKey(view.getId());
}
public final GameEntityView getGameEntityView(final GameEntity e) {
@@ -360,13 +350,13 @@ public abstract class LocalGameView implements IGameView {
return null;
}
final PlayerView view;
if (players.containsKey(p.getId())) {
view = players.get(p.getId());
PlayerView view = MatchUtil.players.get(p.getId());
if (view != null) {
getPlayerView(p, view);
} else {
}
else {
view = new PlayerView(p.getLobbyPlayer(), p.getId());
players.put(p, view);
MatchUtil.players.put(p, view);
getPlayerView(p, view);
view.setOpponents(getPlayerViews(p.getOpponents()));
}
@@ -377,14 +367,14 @@ public abstract class LocalGameView implements IGameView {
if (p == null) {
return null;
}
return players.get(p.getId());
return MatchUtil.players.get(p.getId());
}
public Player getPlayer(final PlayerView p) {
if (p == null) {
return null;
}
return players.getKey(p.getId());
return MatchUtil.players.getKey(p.getId());
}
private void getPlayerView(final Player p, final PlayerView view) {
@@ -423,19 +413,19 @@ public abstract class LocalGameView implements IGameView {
final boolean isDisplayable = cUi == c;
final boolean mayShow = mayShowCard(c);
CardView view = cards.get(c.getId());
CardView view = MatchUtil.cards.get(c.getId());
final boolean isNewView;
if (view != null) {
// Update to ensure the Card reference in the cache
// is not an outdated Card.
if (view.getId() > 0) {
cards.updateKey(view.getId(), c);
MatchUtil.cards.updateKey(view.getId(), c);
}
isNewView = false;
} else if (isDisplayable && mayShow) {
view = new CardView(isDisplayable);
view.setId(c.getId());
cards.put(c, view);
MatchUtil.cards.put(c, view);
isNewView = true;
} else {
return CardView.EMPTY;
@@ -471,7 +461,7 @@ public abstract class LocalGameView implements IGameView {
return ViewUtil.transformIfNotNull(cardViews, new Function<CardView, CardView>() {
@Override
public CardView apply(final CardView input) {
return cards.getCurrentValue(input);
return MatchUtil.cards.getCurrentValue(input);
}
});
}
@@ -481,7 +471,7 @@ public abstract class LocalGameView implements IGameView {
return null;
}
final CardView view = cards.get(c.getId());
final CardView view = MatchUtil.cards.get(c.getId());
if (mayShowCard(c)) {
return view;
} else if (view.isUiDisplayable()) {
@@ -506,7 +496,7 @@ public abstract class LocalGameView implements IGameView {
if (c == null) {
return null;
}
return cards.getKey(c.getId());
return MatchUtil.cards.getKey(c.getId());
}
private final Function<CardView, Card> FN_GET_CARD = new Function<CardView, Card>() {
@@ -521,7 +511,6 @@ public abstract class LocalGameView implements IGameView {
}
private void writeCardToView(final Card c, final CardView view) {
synchronized (c) {
// First, write the values independent of other views.
ViewUtil.writeNonDependentCardViewProperties(c, view, mayShowCardFace(c));
// Next, write the values that depend on other views.
@@ -545,7 +534,6 @@ public abstract class LocalGameView implements IGameView {
view.setMustBlock(c.getMustBlockCards() == null ? Collections.<CardView>emptySet() : getCardViewsFast(c.getMustBlockCards()));
view.setPairedWith(getCardViewFast(c.getPairedWith()));
}
}
public SpellAbilityView getSpellAbilityView(final SpellAbility sa) {
if (sa == null) {
@@ -553,13 +541,13 @@ public abstract class LocalGameView implements IGameView {
}
final SpellAbilityView view;
if (spabs.containsKey(sa.getId())) {
view = spabs.get(sa.getId());
if (MatchUtil.spabs.containsKey(sa.getId())) {
view = MatchUtil.spabs.get(sa.getId());
writeSpellAbilityToView(sa, view);
} else {
view = new SpellAbilityView(sa.getId());
writeSpellAbilityToView(sa, view);
spabs.put(sa, view);
MatchUtil.spabs.put(sa, view);
}
return view;
}
@@ -582,7 +570,7 @@ public abstract class LocalGameView implements IGameView {
return getSpellAbility(spabView.getId());
}
public SpellAbility getSpellAbility(final int id) {
return id >= 0 ? spabs.getKey(id) : null;
return id >= 0 ? MatchUtil.spabs.getKey(id) : null;
}
private final Function<SpellAbilityView, SpellAbility> FN_GET_SPAB = new Function<SpellAbilityView, SpellAbility>() {