From 1d60c2039b405b04460521036f4f7568ad133041 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov <jaydi85@gmail.com> Date: Wed, 18 Aug 2021 10:58:43 +0400 Subject: [PATCH] * Game: fixed priority lost on rollback (example: game skips to next step instead current step after a rollback error); * Game: added game logs on rollback error; --- Mage/src/main/java/mage/game/Game.java | 2 +- Mage/src/main/java/mage/game/GameImpl.java | 26 ++++++++++++++----- Mage/src/main/java/mage/players/Player.java | 6 +++-- .../main/java/mage/players/PlayerImpl.java | 3 ++- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 914a397dc4..e6e9ea934b 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -452,7 +452,7 @@ public interface Game extends MageItem, Serializable, Copyable<Game> { int bookmarkState(); - void restoreState(int bookmark, String context); + GameState restoreState(int bookmark, String context); void removeBookmark(int bookmark); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 4d1cb8e3bf..4af90431cc 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -846,9 +846,10 @@ public abstract class GameImpl implements Game { * * @param bookmark * @param context additional information for error message + * @return current restored state (if all fine) */ @Override - public void restoreState(int bookmark, String context) { + public GameState restoreState(int bookmark, String context) { if (!simulation && !this.hasEnded()) { // if player left or game is over no undo is possible - this could lead to wrong winner if (bookmark != 0) { if (!savedStates.contains(bookmark - 1)) { @@ -863,11 +864,12 @@ public abstract class GameImpl implements Game { if (restore != null) { state.restore(restore); playerList.setCurrent(state.getPlayerByOrderId()); + return state; } } } } - + return null; } @Override @@ -1469,7 +1471,7 @@ public abstract class GameImpl implements Game { public void playPriority(UUID activePlayerId, boolean resuming) { int errorContinueCounter = 0; infiniteLoopCounter = 0; - int bookmark = 0; + int rollbackBookmark = 0; clearAllBookmarks(); try { applyEffects(); @@ -1484,8 +1486,8 @@ public abstract class GameImpl implements Game { Player player; while (!isPaused() && !checkIfGameIsOver()) { try { - if (bookmark == 0) { - bookmark = bookmarkState(); + if (rollbackBookmark == 0) { + rollbackBookmark = bookmarkState(); } player = getPlayer(state.getPlayerList().get()); state.setPriorityPlayerId(player.getId()); @@ -1542,12 +1544,22 @@ public abstract class GameImpl implements Game { logger.fatal(ex.getStackTrace()); } this.fireErrorEvent("Game exception occurred: ", ex); - restoreState(bookmark, "Game exception: " + ex.getMessage()); - bookmark = 0; + + // rollback game to prev state + GameState restoredState = restoreState(rollbackBookmark, "Game exception: " + ex.getMessage()); + rollbackBookmark = 0; + if (errorContinueCounter > 15) { throw new MageException("Iterated player priority after game exception too often, game ends! Last error:\n " + ex.getMessage()); } + + if (restoredState != null) { + this.informPlayers(String.format("Auto-restored to %s due game error: %s", restoredState, ex.getMessage())); + } else { + logger.error("Can't auto-restore to prev state."); + } + Player activePlayer = this.getPlayer(getActivePlayerId()); if (activePlayer != null && !activePlayer.isTestsMode()) { errorContinueCounter++; diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 3481288ab5..08974e82a7 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -25,6 +25,7 @@ import mage.filter.FilterCard; import mage.filter.FilterMana; import mage.filter.FilterPermanent; import mage.game.Game; +import mage.game.GameState; import mage.game.Graveyard; import mage.game.Table; import mage.game.combat.CombatGroup; @@ -541,11 +542,12 @@ public interface Player extends MageItem, Copyable<Player> { void resetStoredBookmark(Game game); - default void restoreState(int bookmark, String text, Game game) { - game.restoreState(bookmark, text); + default GameState restoreState(int bookmark, String text, Game game) { + GameState state = game.restoreState(bookmark, text); if (getStoredBookmark() >= bookmark) { resetStoredBookmark(game); } + return state; } void revealCards(Ability source, Cards cards, Game game); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 7bcf3a53c2..fccfebad49 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -294,13 +294,14 @@ public abstract class PlayerImpl implements Player, Serializable { this.human = player.isHuman(); this.life = player.getLife(); + this.passed = player.isPassed(); + // Don't restore more global states. If restored they are probably cause for unintended draws (https://github.com/magefree/mage/issues/1205). // this.wins = player.hasWon(); // this.loses = player.hasLost(); // this.left = player.hasLeft(); // this.quit = player.hasQuit(); // Makes no sense to restore -// this.passed = player.isPassed(); // this.priorityTimeLeft = player.getPriorityTimeLeft(); // this.idleTimeout = player.hasIdleTimeout(); // this.timerTimeout = player.hasTimerTimeout();