diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index b55f4ea8c37..59d47955831 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -62,7 +62,11 @@ public class GameView implements Serializable { private final int turn; private boolean special = false; private final boolean rollbackTurnsAllowed; + + // for debug only + // TODO: implement and support in admin tools private int totalErrorsCount; + private int totalEffectsCount; public GameView(GameState state, Game game, UUID createdForPlayerId, UUID watcherUserId) { Player createdForPlayer = null; @@ -209,6 +213,7 @@ public class GameView implements Serializable { } this.rollbackTurnsAllowed = game.getOptions().rollbackTurnsAllowed; this.totalErrorsCount = game.getTotalErrorsCount(); + this.totalEffectsCount = game.getTotalEffectsCount(); } private void checkPaid(UUID uuid, StackAbility stackAbility) { @@ -349,4 +354,8 @@ public class GameView implements Serializable { public int getTotalErrorsCount() { return this.totalErrorsCount; } + + public int getTotalEffectsCount() { + return this.totalEffectsCount; + } } diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index b6d4c23ae51..c9e1423485f 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -1001,10 +1001,10 @@ public class MageServerImpl implements MageServer { } public void handleException(Exception ex) throws MageException { - if (!ex.getMessage().equals("No message")) { - logger.fatal("", ex); + if (ex.getMessage() != null && !ex.getMessage().equals("No message")) { throw new MageException("Server error: " + ex.getMessage()); } + logger.error("unknown error", ex); // TODO: on logs spamming (e.g. connection problems) move it inside condition block above } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/load/LoadCallbackClient.java b/Mage.Tests/src/test/java/org/mage/test/load/LoadCallbackClient.java index 0e925d4c077..b0e79027150 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/LoadCallbackClient.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/LoadCallbackClient.java @@ -33,7 +33,7 @@ public class LoadCallbackClient implements CallbackClient { private final String logsPrefix; private final Boolean showLogsAsHtml; // original game logs in HTML, but it can be converted to txt for more readable console - private String globalProgress = ""; // progress [=20, +21, +17], AI game #9: --- + private String globalProgress = ""; // progress 33% [=20, +21, +17], AI game #9: --- public LoadCallbackClient(boolean joinGameChat, String logsPrefix, Boolean showLogsAsHtml) { this.joinGameChat = joinGameChat; diff --git a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java index 36d51f4bba9..d956f16d219 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java @@ -321,7 +321,7 @@ public class LoadTest { long randomSeed = RandomUtil.nextInt(); LoadTestGameResult gameResult = gameResults.createGame(0, "test game", randomSeed); TasksProgress tasksProgress = new TasksProgress(); - tasksProgress.update(1, true, 0); + tasksProgress.update(1, false, 0); playTwoAIGame("Single AI game", 1, tasksProgress, randomSeed, "WGUBR", TEST_AI_RANDOM_DECK_SETS, gameResult); printGameResults(gameResults); @@ -333,12 +333,13 @@ public class LoadTest { // play multiple AI games with CLIENT side code (catch every GameView changes from the server) int singleGameSID = 0; // set sid for same deck games, set 0 for random decks - int gamesAmount = 5; // games per run - boolean isRunParallel = true; // can generate too much logs in test run, so search server logs for possible errors + + int runTotalGames = 10; + int runMaxParallelGames = 5; // use 1 to run one by one (warning, it's limited by COMPUTER_MAX_THREADS_FOR_SIMULATIONS) ExecutorService executerService; - if (isRunParallel) { - executerService = Executors.newFixedThreadPool(gamesAmount, new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES)); + if (runMaxParallelGames > 1) { + executerService = Executors.newFixedThreadPool(runMaxParallelGames, new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES)); } else { executerService = Executors.newSingleThreadExecutor(new XmageThreadFactory(ThreadUtils.THREAD_PREFIX_TESTS_AI_VS_AI_GAMES)); } @@ -346,11 +347,11 @@ public class LoadTest { // save random seeds for repeated results (in decks generating) List seedsList = new ArrayList<>(); if (singleGameSID != 0) { - for (int i = 1; i <= gamesAmount; i++) { + for (int i = 1; i <= runTotalGames; i++) { seedsList.add(singleGameSID); } } else { - for (int i = 1; i <= gamesAmount; i++) { + for (int i = 1; i <= runTotalGames; i++) { seedsList.add(RandomUtil.nextInt()); } } @@ -360,7 +361,7 @@ public class LoadTest { TasksProgress tasksProgress = new TasksProgress(); for (int i = 0; i < seedsList.size(); i++) { int gameIndex = i; - tasksProgress.update(gameIndex + 1, true, 0); + tasksProgress.update(gameIndex + 1, false, 0); long randomSeed = seedsList.get(i); logger.info("Game " + (i + 1) + " of " + seedsList.size() + ", RANDOM seed: " + randomSeed); Future gameTask = executerService.submit(() -> { @@ -369,12 +370,12 @@ public class LoadTest { playTwoAIGame(gameName, gameIndex + 1, tasksProgress, randomSeed, TEST_AI_RANDOM_DECK_COLORS_FOR_AI_GAME, TEST_AI_RANDOM_DECK_SETS, gameResult); }); - if (!isRunParallel) { + if (runMaxParallelGames <= 1) { // run one by one gameTask.get(); } } - if (isRunParallel) { + if (runMaxParallelGames > 1) { // run parallel executerService.shutdown(); Assert.assertTrue(executerService.awaitTermination(1, TimeUnit.HOURS)); @@ -601,14 +602,18 @@ public class LoadTest { } private void updateInfo() { - // example: progress [=00, +01, +01, =12, =15, =01, +61] + // example: progress 70% [=00, +01, +01, =12, =15, =01, +61] + + int completed = this.finishes.values().stream().mapToInt(x -> x ? 1 : 0).sum(); + int completedPercent = this.finishes.size() == 0 ? 0 : completed * 100 / this.finishes.size(); + String res = this.finishes.keySet().stream() .map(taskNumber -> String.format("%s%02d", this.finishes.getOrDefault(taskNumber, false) ? "=" : "+", this.turns.getOrDefault(taskNumber, 0) )) .collect(Collectors.joining(", ")); - this.info = String.format("progress [%s]", res); + this.info = String.format("progress %d%% [%s]", completedPercent, res); } public String getInfo() { @@ -877,12 +882,16 @@ public class LoadTest { public int getTotalErrorsCount() { return finalGameView == null ? 0 : this.finalGameView.getTotalErrorsCount(); } + + public int getTotalEffectsCount() { + return finalGameView == null ? 0 : this.finalGameView.getTotalEffectsCount(); + } } private static class LoadTestGameResultsList extends HashMap { - private static final String tableFormatHeader = "|%-10s|%-15s|%-20s|%-10s|%-10s|%-10s|%-10s|%-15s|%-15s|%-10s|%n"; - private static final String tableFormatData = "|%-10s|%15s|%20s|%10s|%10s|%10s|%10s|%15s|%15s|%10s|%n"; + private static final String tableFormatHeader = "|%-10s|%-15s|%-20s|%-10s|%-10s|%-10s|%-10s|%-10s|%-15s|%-15s|%-10s|%n"; + private static final String tableFormatData = "|%-10s|%15s|%20s|%10s|%10s|%10s|%10s|%10s|%15s|%15s|%10s|%n"; public LoadTestGameResult createGame(int index, String name, long randomSeed) { if (this.containsKey(index)) { @@ -899,6 +908,7 @@ public class LoadTest { "name", "random sid", "errors", + "effects", "turn", "life p1", "life p2", @@ -920,6 +930,7 @@ public class LoadTest { gameResult.name, //"name", String.valueOf(gameResult.randomSeed), // "random sid", String.valueOf(gameResult.getTotalErrorsCount()), // "errors", + String.valueOf(gameResult.getTotalEffectsCount()), // "effects", String.valueOf(gameResult.getTurn()), //"turn", String.valueOf(gameResult.getLife1()), //"life p1", String.valueOf(gameResult.getLife2()), //"life p2", @@ -937,6 +948,7 @@ public class LoadTest { String.valueOf(this.size()), //"name", "total, secs: " + String.format("%.3f", (float) this.getTotalDurationMs() / 1000), // "random sid", String.valueOf(this.getTotalErrorsCount()), // errors + String.valueOf(this.getAvgEffectsCount()), // effects String.valueOf(this.getAvgTurn()), // turn String.valueOf(this.getAvgLife1()), // life p1 String.valueOf(this.getAvgLife2()), // life p2 @@ -952,6 +964,10 @@ public class LoadTest { return this.values().stream().mapToInt(LoadTestGameResult::getTotalErrorsCount).sum(); } + private int getAvgEffectsCount() { + return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getTotalEffectsCount).sum() / this.size(); + } + private int getAvgTurn() { return this.size() == 0 ? 0 : this.values().stream().mapToInt(LoadTestGameResult::getTurn).sum() / this.size(); } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 5ad74ac0fb1..294ad8831cb 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -1487,8 +1487,12 @@ public class ContinuousEffects implements Serializable { } } + public int getTotalEffectsCount() { + return allEffectsLists.stream().mapToInt(ContinuousEffectsList::size).sum(); + } + @Override public String toString() { - return "Effects: " + allEffectsLists.stream().mapToInt(ContinuousEffectsList::size).sum(); + return "Effects: " + getTotalEffectsCount(); } } diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index b005e482cf4..2df39b9016d 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -314,7 +314,9 @@ public interface Game extends MageItem, Serializable, Copyable { Player getLosingPlayer(); - int getTotalErrorsCount(); + int getTotalErrorsCount(); // debug only + + int getTotalEffectsCount(); // debug only //client event methods void addTableEventListener(Listener listener); diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 25792668fcb..2fcce83997d 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -3547,11 +3547,6 @@ public abstract class GameImpl implements Game { } - protected void removeCreaturesFromCombat() { - //20091005 - 511.3 - getCombat().endCombat(this); - } - @Override public ContinuousEffects getContinuousEffects() { return state.getContinuousEffects(); @@ -3694,6 +3689,11 @@ public abstract class GameImpl implements Game { return this.totalErrorsCount.get(); } + @Override + public int getTotalEffectsCount() { + return this.getContinuousEffects().getTotalEffectsCount(); + } + @Override public void cheat(UUID ownerId, Map commands) { if (commands != null) {