mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
catch spell and activated ability errors and rollback state - show error dialog on client
This commit is contained in:
parent
b90ac39de7
commit
48d7afa375
7 changed files with 114 additions and 68 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue