Cheats: added error dialog on wrong cheat command, added chat message about cheat try;

This commit is contained in:
Oleg Agafonov 2023-05-09 00:22:00 +04:00
parent 6882a9a49e
commit 5c705a92a3
3 changed files with 83 additions and 21 deletions

View file

@ -917,14 +917,21 @@ public class GameController implements GameCallback {
private void error(String message, Exception ex) { private void error(String message, Exception ex) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(message).append(ex.toString()); sb.append(message);
sb.append("\n");
sb.append("\n");
sb.append(ex);
sb.append("\nServer version: ").append(Main.getVersion().toString()); sb.append("\nServer version: ").append(Main.getVersion().toString());
sb.append('\n'); sb.append("\nStack trace:");
sb.append("\n");
for (StackTraceElement e : ex.getStackTrace()) { for (StackTraceElement e : ex.getStackTrace()) {
sb.append(e.toString()).append('\n'); sb.append(e.toString()).append("\n");
} }
String mes = sb.toString();
// send error for each player
for (final Entry<UUID, GameSessionPlayer> entry : getGameSessionsMap().entrySet()) { for (final Entry<UUID, GameSessionPlayer> entry : getGameSessionsMap().entrySet()) {
entry.getValue().gameError(sb.toString()); entry.getValue().gameError(mes);
} }
} }

View file

@ -268,6 +268,7 @@ public final class SystemUtil {
Ability fakeSourceAbilityTemplate = new SimpleStaticAbility(Zone.OUTSIDE, new InfoEffect("adding testing cards")); Ability fakeSourceAbilityTemplate = new SimpleStaticAbility(Zone.OUTSIDE, new InfoEffect("adding testing cards"));
fakeSourceAbilityTemplate.setControllerId(feedbackPlayer.getId()); fakeSourceAbilityTemplate.setControllerId(feedbackPlayer.getId());
List<String> errorsList = new ArrayList<>();
try { try {
String fileName = fileSource; String fileName = fileSource;
if (fileName == null) { if (fileName == null) {
@ -276,7 +277,10 @@ public final class SystemUtil {
File f = new File(fileName); File f = new File(fileName);
if (!f.exists()) { if (!f.exists()) {
logger.warn("Couldn't find init file: " + fileName); String mes = String.format("Couldn't find init file: %s", f.getAbsolutePath());
logger.warn(mes);
errorsList.add(mes);
sendCheatCommandsFeedback(game, feedbackPlayer, errorsList);
return; return;
} }
@ -287,6 +291,7 @@ public final class SystemUtil {
// 2. ask user if many groups // 2. ask user if many groups
// 3. process system commands // 3. process system commands
// 4. run commands from selected group // 4. run commands from selected group
// 1. parse // 1. parse
List<CommandGroup> groups = new ArrayList<>(); List<CommandGroup> groups = new ArrayList<>();
@ -312,7 +317,9 @@ public final class SystemUtil {
currentGroup = new CommandGroup(groupName, true); currentGroup = new CommandGroup(groupName, true);
groups.add(currentGroup); groups.add(currentGroup);
} else { } else {
logger.warn("Special group [" + groupName + "] is not supported."); String mes = String.format("Special group is not supported: %s", groupName);
errorsList.add(mes);
logger.warn(mes);
} }
continue; continue;
} else { } else {
@ -368,7 +375,10 @@ public final class SystemUtil {
return; return;
} }
logger.info("Selected group [" + runGroup.name + "] with " + runGroup.commands.size() + " commands"); logger.info(String.format("Selected group [%s] with %d commands",
runGroup.name,
runGroup.commands.size()
));
// 3. system commands // 3. system commands
if (runGroup.isSpecialCommand) { if (runGroup.isSpecialCommand) {
@ -447,7 +457,14 @@ public final class SystemUtil {
game.firePriorityEvent(savedPriorityPlayer); game.firePriorityEvent(savedPriorityPlayer);
} }
break; break;
default:
String mes = String.format("Unknown system command: %s", runGroup.name);
errorsList.add(mes);
logger.error(mes);
break;
} }
sendCheatCommandsFeedback(game, feedbackPlayer, errorsList);
return; return;
} }
@ -464,11 +481,16 @@ public final class SystemUtil {
if (line.startsWith(COMMAND_REF_PREFIX)) { if (line.startsWith(COMMAND_REF_PREFIX)) {
CommandGroup other = otherGroupRefs.getOrDefault(line, null); CommandGroup other = otherGroupRefs.getOrDefault(line, null);
if (other != null && !other.isSpecialCommand) { if (other != null && !other.isSpecialCommand) {
logger.info("Replace ref group " + line + " by " + other.commands.size() + " commands"); logger.info(String.format("Replace ref group [%s] by %d child commands",
line,
other.commands.size()
));
runGroup.commands.remove(i); runGroup.commands.remove(i);
runGroup.commands.addAll(i, other.commands); runGroup.commands.addAll(i, other.commands);
} else { } else {
logger.error("Can't find ref group: " + line); String mes = String.format("Can't find ref group: %s", line);
errorsList.add(mes);
logger.error(mes);
} }
} }
} }
@ -478,13 +500,17 @@ public final class SystemUtil {
CardCommandData command = parseCardCommand(line); CardCommandData command = parseCardCommand(line);
if (!command.OK) { if (!command.OK) {
logger.warn(command.Error + ": " + line); String mes = String.format("%s: %s", command.Error, line);
errorsList.add(mes);
logger.warn(mes);
continue; continue;
} }
Optional<Player> playerOptional = findPlayer(game, command.player); Optional<Player> playerOptional = findPlayer(game, command.player);
if (!playerOptional.isPresent()) { if (!playerOptional.isPresent()) {
logger.warn("Unknown player: " + line); String mes = String.format("Unknown player: %s", line);
errorsList.add(mes);
logger.warn(mes);
continue; continue;
} }
Player player = playerOptional.get(); Player player = playerOptional.get();
@ -531,7 +557,11 @@ public final class SystemUtil {
// find card info // find card info
CardInfo cardInfo = CardLookup.instance.lookupCardInfo(command.cardName, command.cardSet).orElse(null); CardInfo cardInfo = CardLookup.instance.lookupCardInfo(command.cardName, command.cardSet).orElse(null);
if (cardInfo == null) { if (cardInfo == null) {
logger.warn("Unknown card for stack command [" + command.cardName + "]: " + line); String mes = String.format("Unknown card for stack command [%s]: %s",
command.cardName,
line);
errorsList.add(mes);
logger.warn(mes);
continue; continue;
} }
@ -576,7 +606,11 @@ public final class SystemUtil {
} else if ("sideboard".equalsIgnoreCase(command.zone)) { } else if ("sideboard".equalsIgnoreCase(command.zone)) {
gameZone = Zone.OUTSIDE; gameZone = Zone.OUTSIDE;
} else { } else {
logger.warn("Unknown zone [" + command.zone + "]: " + line); String mes = String.format("Unknown zone [%s]: %s",
command.zone,
line);
errorsList.add(mes);
logger.warn(mes);
continue; continue;
} }
@ -590,11 +624,13 @@ public final class SystemUtil {
} }
if (cards.isEmpty()) { if (cards.isEmpty()) {
logger.warn(String.format("Unknown card [%s%s]: %s", String mes = String.format("Unknown card [%s%s]: %s",
command.cardSet.isEmpty() ? "" : command.cardSet + "-", command.cardSet.isEmpty() ? "" : command.cardSet + "-",
command.cardName, command.cardName,
line line
)); );
errorsList.add(mes);
logger.warn(mes);
continue; continue;
} }
@ -615,7 +651,9 @@ public final class SystemUtil {
cardsToLoad.forEach(card -> gameCommander.addCommander(card, player)); cardsToLoad.forEach(card -> gameCommander.addCommander(card, player));
cardsToLoad.forEach(card -> gameCommander.initCommander(card, player)); cardsToLoad.forEach(card -> gameCommander.initCommander(card, player));
} else { } else {
logger.fatal("Commander card can be used in commander game only: " + command.cardName); String mes = String.format("Commander card can be used in commander game only: %s", command.cardName);
errorsList.add(mes);
logger.error(mes);
} }
} else if ("sideboard".equalsIgnoreCase(command.zone) && cardsToLoad.size() > 0) { } else if ("sideboard".equalsIgnoreCase(command.zone) && cardsToLoad.size() > 0) {
// put to sideboard // put to sideboard
@ -632,8 +670,24 @@ public final class SystemUtil {
} }
} }
} catch (Exception e) { } catch (Exception e) {
logger.fatal("", e); String mes = String.format("Catch critical error: %s", e.getMessage());
errorsList.add(mes);
logger.error(mes, e);
} }
sendCheatCommandsFeedback(game, feedbackPlayer, errorsList);
}
private static void sendCheatCommandsFeedback(Game game, Player feedbackPlayer, List<String> errorsList) {
// inform all players about wrong commands or other errors
// TODO: it's a workaround to show a dialog with error message (must be replaced by message dialog for feedback player)
if (errorsList.size() > 0) {
String mes = String.format("Player %s tried to apply cheat commands and catch %d errors:\n\n",
feedbackPlayer.getName(), errorsList.size());
mes += String.join("\n", errorsList);
mes += "\n";
game.fireErrorEvent("Cheat command errors", new IllegalArgumentException(mes));
}
game.informPlayers(String.format("%s: tried to apply cheat commands", feedbackPlayer.getLogName()));
} }
/** /**

View file

@ -1636,15 +1636,16 @@ public abstract class GameImpl implements Game {
String info = this.getStack().stream().map(MageObject::toString).collect(Collectors.joining("\n")); String info = this.getStack().stream().map(MageObject::toString).collect(Collectors.joining("\n"));
logger.info(String.format("\nStack before error %d: \n%s\n", this.getStack().size(), info)); logger.info(String.format("\nStack before error %d: \n%s\n", this.getStack().size(), info));
// rollback game to prev state // too many errors - end game
GameState restoredState = restoreState(rollbackBookmark, "Game exception: " + ex.getMessage());
rollbackBookmark = 0;
if (errorContinueCounter > 15) { if (errorContinueCounter > 15) {
throw new MageException("Iterated player priority after game exception too often, game ends! Last error:\n " throw new MageException("Iterated player priority after game exception too often, game ends! Last error:\n "
+ ex.getMessage()); + ex.getMessage());
} }
// rollback game to prev state
GameState restoredState = restoreState(rollbackBookmark, "Game exception: " + ex.getMessage());
rollbackBookmark = 0;
if (restoredState != null) { if (restoredState != null) {
this.informPlayers(String.format("Auto-restored to %s due game error: %s", restoredState, ex.getMessage())); this.informPlayers(String.format("Auto-restored to %s due game error: %s", restoredState, ex.getMessage()));
} else { } else {