1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-06 01:04:10 -09:00

* 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;
This commit is contained in:
Oleg Agafonov 2021-08-18 10:58:43 +04:00
parent c8445c31a3
commit 1d60c2039b
4 changed files with 26 additions and 11 deletions
Mage/src/main/java/mage

View file

@ -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);

View file

@ -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++;

View file

@ -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);

View file

@ -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();