catch spell and activated ability errors and rollback state - show error dialog on client

This commit is contained in:
BetaSteward 2011-08-24 12:59:51 -04:00
parent b90ac39de7
commit 48d7afa375
7 changed files with 114 additions and 68 deletions

View file

@ -106,6 +106,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
private static Session session;
private ConnectDialog connectDialog;
private ErrorDialog errorDialog;
private static CallbackClient callbackClient;
private static Preferences prefs = Preferences.userNodeForPackage(MageFrame.class);
private JLabel title;
@ -188,6 +189,8 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
callbackClient = new CallbackClientImpl(this);
connectDialog = new ConnectDialog();
desktopPane.add(connectDialog, JLayeredPane.POPUP_LAYER);
errorDialog = new ErrorDialog();
desktopPane.add(errorDialog, JLayeredPane.POPUP_LAYER);
ui.addComponent(MageComponents.DESKTOP_PANE, desktopPane);
try {
@ -834,6 +837,21 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
}
}
public void showErrorDialog(final String title, final String message) {
if (SwingUtilities.isEventDispatchThread()) {
errorDialog.showDialog(title, message);
}
else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
errorDialog.showDialog(title, message);
}
});
}
}
public void showCollectionViewer() {
this.collectionViewerPane.setVisible(true);
setActive(collectionViewerPane);

View file

@ -141,10 +141,7 @@ public class CallbackClientImpl implements CallbackClient {
}
}
else if (callback.getMethod().equals("gameError")) {
GamePanel panel = frame.getGame(callback.getObjectId());
if (panel != null) {
panel.modalMessage((String) callback.getData());
}
frame.showErrorDialog("Game Error", (String) callback.getData());
}
else if (callback.getMethod().equals("gameAsk")) {
GameClientMessage message = (GameClientMessage) callback.getData();

View file

@ -60,12 +60,12 @@ import mage.game.events.TableEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.server.ChatManager;
import mage.server.Main;
import mage.server.UserManager;
import mage.server.util.SystemUtil;
import mage.server.util.Splitter;
import mage.server.util.ThreadExecutor;
import mage.sets.Sets;
import mage.sets.alarareborn.EnlistedWurm;
import mage.view.*;
import mage.view.ChatMessage.MessageColor;
import org.apache.log4j.Logger;
@ -506,8 +506,9 @@ public class GameController implements GameCallback {
}
private void error(String message) {
String msg = message + "\nServer version: " + Main.getVersion().toString();
for (final Entry<UUID, GameSession> entry: gameSessions.entrySet()) {
entry.getValue().gameError(message);
entry.getValue().gameError(msg);
}
}

View file

@ -68,13 +68,13 @@ public class KickerAbility extends StaticAbility<KickerAbility> {
// replace by card name or just plain "this"
message = message.replace("{this}", card == null ? "this" : card.getName());
if (player.chooseUse(getEffects().get(0).getOutcome(), message, game)) {
game.bookmarkState();
int bookmark = game.bookmarkState();
if (super.activate(game, noMana)) {
game.removeLastBookmark();
game.removeBookmark(bookmark);
kicked = true;
}
else {
game.restoreState();
game.restoreState(bookmark);
kicked = false;
}
return kicked;

View file

@ -42,7 +42,6 @@ import mage.MageItem;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.Modes;
import mage.abilities.TriggeredAbilities;
import mage.abilities.TriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
@ -158,9 +157,9 @@ public interface Game extends MageItem, Serializable {
//game transaction methods
public void saveState();
public void bookmarkState();
public void restoreState();
public void removeLastBookmark();
public int bookmarkState();
public void restoreState(int bookmark);
public void removeBookmark(int bookmark);
// game options
public void setGameOptions(GameOptions options);

View file

@ -73,6 +73,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
private static FilterAura filterAura = new FilterAura();
private static FilterEquipment filterEquipment = new FilterEquipment();
private static FilterFortification filterFortification = new FilterFortification();
private static Random rnd = new Random();
private transient Stack<Integer> savedStates = new Stack<Integer>();
private transient Object customData;
@ -296,28 +297,37 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
}
@Override
public void bookmarkState() {
public int bookmarkState() {
if (!simulation) {
saveState();
if (logger.isDebugEnabled())
logger.debug("Bookmarking state: " + gameStates.getSize());
savedStates.push(gameStates.getSize() - 1);
return savedStates.size();
}
return 0;
}
@Override
public void restoreState(int bookmark) {
if (!simulation) {
if (bookmark != 0) {
int stateNum = savedStates.get(bookmark - 1);
removeBookmark(bookmark);
GameState restore = gameStates.rollback(stateNum);
if (restore != null)
state.restore(restore);
}
}
}
@Override
public void restoreState() {
public void removeBookmark(int bookmark) {
if (!simulation) {
GameState restore = gameStates.rollback(savedStates.pop());
if (restore != null)
state.restore(restore);
}
}
@Override
public void removeLastBookmark() {
if (!simulation) {
savedStates.pop();
if (bookmark != 0) {
while (savedStates.size() > bookmark)
savedStates.pop();
}
}
}
@ -453,7 +463,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
protected UUID pickChoosingPlayer() {
UUID[] players = getPlayers().keySet().toArray(new UUID[0]);
UUID playerId = players[new Random().nextInt(players.length)];
UUID playerId = players[rnd.nextInt(players.length)];
fireInformEvent(state.getPlayer(playerId).getName() + " won the toss");
return playerId;
}
@ -502,37 +512,55 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override
public void playPriority(UUID activePlayerId) {
int bookmark = 0;
try {
while (!isGameOver()) {
state.getPlayers().resetPassed();
state.getPlayerList().setCurrent(activePlayerId);
Player player;
while (!isGameOver()) {
player = getPlayer(state.getPlayerList().get());
state.setPriorityPlayerId(player.getId());
while (!player.isPassed() && !player.hasLost() && !player.hasLeft() && !isGameOver()) {
checkStateAndTriggered();
if (isGameOver()) return;
// resetPassed should be called if player performs any action
player.priority(this);
if (isGameOver()) return;
applyEffects();
}
if (isGameOver()) return;
if (allPassed()) {
if (!state.getStack().isEmpty()) {
//20091005 - 115.4
state.getStack().resolve(this);
applyEffects();
state.getPlayers().resetPassed();
fireUpdatePlayersEvent();
state.getRevealed().reset();
break;
} else
return;
}
try {
if (bookmark == 0)
bookmark = bookmarkState();
player = getPlayer(state.getPlayerList().get());
state.setPriorityPlayerId(player.getId());
while (!player.isPassed() && !player.hasLost() && !player.hasLeft() && !isGameOver()) {
checkStateAndTriggered();
if (isGameOver()) return;
// resetPassed should be called if player performs any action
player.priority(this);
if (isGameOver()) return;
applyEffects();
}
if (isGameOver()) return;
if (allPassed()) {
if (!state.getStack().isEmpty()) {
//20091005 - 115.4
state.getStack().resolve(this);
applyEffects();
state.getPlayers().resetPassed();
fireUpdatePlayersEvent();
state.getRevealed().reset();
break;
} else {
removeBookmark(bookmark);
return;
}
}
}
catch (Exception ex) {
logger.fatal("Game exception ", ex);
this.fireErrorEvent("Game exception occurred: " + ex.getMessage() + " - " + ex.getStackTrace()[0]);
restoreState(bookmark);
bookmark = 0;
continue;
}
// removeBookmark(bookmark);
// bookmark = 0;
state.getPlayerList().getNext();
}
removeBookmark(bookmark);
bookmark = 0;
}
} catch (Exception ex) {
logger.fatal("Game exception ", ex);

View file

@ -73,6 +73,8 @@ import mage.watchers.common.BloodthirstWatcher;
public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable {
private static Random rnd = new Random();
protected boolean abort;
protected final UUID playerId;
protected String name;
@ -436,7 +438,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
Card card = game.getCard(ability.getSourceId());
if (card != null) {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId))) {
game.bookmarkState();
int bookmark = game.bookmarkState();
card.cast(game, game.getZone(card.getId()), ability, playerId);
removeFromHand(card, game);
Ability spellAbility = game.getStack().getSpell(ability.getId()).getSpellAbility();
@ -446,10 +448,10 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
}
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spellAbility.getId(), playerId));
game.fireInformEvent(name + " casts " + card.getName());
game.removeLastBookmark();
game.removeBookmark(bookmark);
return true;
}
game.restoreState();
game.restoreState(bookmark);
}
}
return false;
@ -459,45 +461,45 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
public boolean playLand(Card card, Game game) {
//20091005 - 305.1
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), playerId))) {
game.bookmarkState();
int bookmark = game.bookmarkState();
removeFromHand(card, game);
if (card.putOntoBattlefield(game, Zone.HAND, null, playerId)) {
landsPlayed++;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), playerId));
game.fireInformEvent(name + " plays " + card.getName());
game.removeLastBookmark();
game.removeBookmark(bookmark);
return true;
}
game.restoreState();
game.restoreState(bookmark);
}
return false;
}
protected boolean playManaAbility(ManaAbility ability, Game game) {
game.bookmarkState();
int bookmark = game.bookmarkState();
if (ability.activate(game, false)) {
ability.resolve(game);
game.removeLastBookmark();
game.removeBookmark(bookmark);
return true;
}
game.restoreState();
game.restoreState(bookmark);
return false;
}
protected boolean playAbility(ActivatedAbility ability, Game game) {
//20091005 - 602.2a
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATE_ABILITY, ability.getId(), ability.getSourceId(), playerId))) {
game.bookmarkState();
int bookmark = game.bookmarkState();
ability.newId();
game.getStack().push(new StackAbility(ability, playerId));
String message = ability.getActivatedMessage(game);
if (ability.activate(game, false)) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, ability.getId(), ability.getSourceId(), playerId));
game.fireInformEvent(name + message);
game.removeLastBookmark();
game.removeBookmark(bookmark);
return true;
}
game.restoreState();
game.restoreState(bookmark);
}
return false;
}
@ -505,16 +507,16 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
protected boolean specialAction(SpecialAction action, Game game) {
//20091005 - 114
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATE_ABILITY, action.getSourceId(), action.getId(), playerId))) {
game.bookmarkState();
int bookmark = game.bookmarkState();
if (action.activate(game, false)) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ACTIVATED_ABILITY, action.getSourceId(), action.getId(), playerId));
game.fireInformEvent(name + action.getActivatedMessage(game));
if (action.resolve(game)) {
game.removeLastBookmark();
game.removeBookmark(bookmark);
return true;
}
}
game.restoreState();
game.restoreState(bookmark);
}
return false;
}
@ -553,16 +555,16 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
@Override
public boolean triggerAbility(TriggeredAbility source, Game game) {
//20091005 - 603.3c, 603.3d
game.bookmarkState();
int bookmark = game.bookmarkState();
TriggeredAbility ability = (TriggeredAbility) source.copy();
if (ability.getTargets().canChoose(ability.getSourceId(), playerId, game)) {
game.getStack().push(new StackAbility(ability, playerId));
if (ability.activate(game, false)) {
game.removeLastBookmark();
game.removeBookmark(bookmark);
return true;
}
}
game.restoreState();
game.restoreState(bookmark);
return false;
}
@ -796,6 +798,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.inRange = player.getInRange();
this.landsPlayed = player.getLandsPlayed();
this.name = player.getName();
this.passed = player.isPassed();
}
@Override
@ -932,7 +935,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
*/
@Override
public boolean flipCoin(Game game) {
boolean result = new Random().nextBoolean();
boolean result = rnd.nextBoolean();
game.informPlayers("[Flip a coin] " + getName() + (result ? " won." : " lost."));
return result;
}