mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
tests: fixed error on load tests end (related to #11572), improved logs, improved session lifecycle on load tests;
tests: added additional test for Mana Maze and deep copy (related to #11572); docs: added more info to network related code;
This commit is contained in:
parent
98a3d8b947
commit
b3c55555a1
12 changed files with 119 additions and 66 deletions
|
|
@ -1329,7 +1329,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
tOptions.getMatchOptions().setMatchBufferTime((MatchBufferTime) this.cbBufferTime.getSelectedItem());
|
tOptions.getMatchOptions().setMatchBufferTime((MatchBufferTime) this.cbBufferTime.getSelectedItem());
|
||||||
tOptions.getMatchOptions().setSkillLevel((SkillLevel) this.cbSkillLevel.getSelectedItem());
|
tOptions.getMatchOptions().setSkillLevel((SkillLevel) this.cbSkillLevel.getSelectedItem());
|
||||||
tOptions.getMatchOptions().setWinsNeeded((Integer) this.spnNumWins.getValue());
|
tOptions.getMatchOptions().setWinsNeeded((Integer) this.spnNumWins.getValue());
|
||||||
tOptions.getMatchOptions().setAttackOption(MultiplayerAttackOption.LEFT);
|
tOptions.getMatchOptions().setAttackOption(MultiplayerAttackOption.MULTIPLE);
|
||||||
tOptions.getMatchOptions().setRange(RangeOfInfluence.ALL);
|
tOptions.getMatchOptions().setRange(RangeOfInfluence.ALL);
|
||||||
tOptions.getMatchOptions().setRollbackTurnsAllowed(this.chkRollbackTurnsAllowed.isSelected());
|
tOptions.getMatchOptions().setRollbackTurnsAllowed(this.chkRollbackTurnsAllowed.isSelected());
|
||||||
tOptions.getMatchOptions().setRated(this.chkRated.isSelected());
|
tOptions.getMatchOptions().setRated(this.chkRated.isSelected());
|
||||||
|
|
|
||||||
|
|
@ -59,20 +59,20 @@ public class TableController {
|
||||||
|
|
||||||
public TableController(ManagerFactory managerFactory, UUID roomId, UUID userId, MatchOptions options) {
|
public TableController(ManagerFactory managerFactory, UUID roomId, UUID userId, MatchOptions options) {
|
||||||
this.managerFactory = managerFactory;
|
this.managerFactory = managerFactory;
|
||||||
timeoutExecutor = managerFactory.threadExecutor().getTimeoutExecutor();
|
this.timeoutExecutor = managerFactory.threadExecutor().getTimeoutExecutor();
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
match = GameFactory.instance.createMatch(options.getGameType(), options);
|
this.match = GameFactory.instance.createMatch(options.getGameType(), options);
|
||||||
if (userId != null) {
|
if (userId != null) {
|
||||||
Optional<User> user = managerFactory.userManager().getUser(userId);
|
Optional<User> user = managerFactory.userManager().getUser(userId);
|
||||||
// TODO: Handle if user == null
|
// TODO: Handle if user == null
|
||||||
controllerName = user.map(User::getName).orElse("undefined");
|
this.controllerName = user.map(User::getName).orElse("undefined");
|
||||||
} else {
|
} else {
|
||||||
controllerName = "System";
|
this.controllerName = "System";
|
||||||
}
|
}
|
||||||
table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getDeckType()),
|
this.table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.instance.createDeckValidator(options.getDeckType()),
|
||||||
options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), match, options.getBannedUsers(), options.isPlaneChase());
|
options.getPlayerTypes(), new TableRecorderImpl(managerFactory.userManager()), match, options.getBannedUsers(), options.isPlaneChase());
|
||||||
chatId = managerFactory.chatManager().createChatSession("Match Table " + table.getId());
|
this.chatId = managerFactory.chatManager().createChatSession("Match Table " + table.getId());
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
|
|
||||||
|
|
||||||
package mage.server.game;
|
package mage.server.game;
|
||||||
|
|
||||||
import mage.MageException;
|
import mage.MageException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface GameCallback {
|
public interface GameCallback {
|
||||||
|
|
||||||
void gameResult(String result) throws MageException;
|
void endGameWithResult(String result) throws MageException;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ public class GameController implements GameCallback {
|
||||||
logger.fatal("Send info about player not joined yet:", ex);
|
logger.fatal("Send info about player not joined yet:", ex);
|
||||||
}
|
}
|
||||||
}, GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS, GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS, TimeUnit.SECONDS);
|
}, GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS, GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS, TimeUnit.SECONDS);
|
||||||
checkStart();
|
checkJoinAndStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -316,7 +316,7 @@ public class GameController implements GameCallback {
|
||||||
user.get().addGame(playerId, gameSession);
|
user.get().addGame(playerId, gameSession);
|
||||||
logger.debug("Player " + player.getName() + ' ' + playerId + " has " + joinType + " gameId: " + game.getId());
|
logger.debug("Player " + player.getName() + ' ' + playerId + " has " + joinType + " gameId: " + game.getId());
|
||||||
managerFactory.chatManager().broadcast(chatId, "", game.getPlayer(playerId).getLogName() + " has " + joinType + " the game", MessageColor.ORANGE, true, game, MessageType.GAME, null);
|
managerFactory.chatManager().broadcast(chatId, "", game.getPlayer(playerId).getLogName() + " has " + joinType + " the game", MessageColor.ORANGE, true, game, MessageType.GAME, null);
|
||||||
checkStart();
|
checkJoinAndStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void startGame() {
|
private synchronized void startGame() {
|
||||||
|
|
@ -326,16 +326,19 @@ public class GameController implements GameCallback {
|
||||||
player.updateRange(game);
|
player.updateRange(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// send first info to users
|
||||||
for (GameSessionPlayer gameSessionPlayer : getGameSessions()) {
|
for (GameSessionPlayer gameSessionPlayer : getGameSessions()) {
|
||||||
gameSessionPlayer.init();
|
gameSessionPlayer.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// real game start
|
||||||
GameWorker worker = new GameWorker(game, choosingPlayerId, this);
|
GameWorker worker = new GameWorker(game, choosingPlayerId, this);
|
||||||
gameFuture = gameExecutor.submit(worker);
|
gameFuture = gameExecutor.submit(worker);
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException ignore) {
|
} catch (InterruptedException ignore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.getState().getChoosingPlayerId() != null) {
|
if (game.getState().getChoosingPlayerId() != null) {
|
||||||
// start timer to force player to choose starting player otherwise loosing by being idle
|
// start timer to force player to choose starting player otherwise loosing by being idle
|
||||||
setupTimeout(game.getState().getChoosingPlayerId());
|
setupTimeout(game.getState().getChoosingPlayerId());
|
||||||
|
|
@ -395,7 +398,7 @@ public class GameController implements GameCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkStart();
|
checkJoinAndStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<User> getUserByPlayerId(UUID playerId) {
|
private Optional<User> getUserByPlayerId(UUID playerId) {
|
||||||
|
|
@ -407,14 +410,14 @@ public class GameController implements GameCallback {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkStart() {
|
private void checkJoinAndStart() {
|
||||||
if (allJoined()) {
|
if (isAllJoined()) {
|
||||||
joinWaitingExecutor.shutdownNow();
|
joinWaitingExecutor.shutdownNow();
|
||||||
managerFactory.threadExecutor().getCallExecutor().execute(this::startGame);
|
managerFactory.threadExecutor().getCallExecutor().execute(this::startGame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean allJoined() {
|
private boolean isAllJoined() {
|
||||||
for (Player player : game.getPlayers().values()) {
|
for (Player player : game.getPlayers().values()) {
|
||||||
if (!player.hasLeft()) {
|
if (!player.hasLeft()) {
|
||||||
Optional<User> user = getUserByPlayerId(player.getId());
|
Optional<User> user = getUserByPlayerId(player.getId());
|
||||||
|
|
@ -480,7 +483,7 @@ public class GameController implements GameCallback {
|
||||||
public void quitMatch(UUID userId) {
|
public void quitMatch(UUID userId) {
|
||||||
UUID playerId = getPlayerId(userId);
|
UUID playerId = getPlayerId(userId);
|
||||||
if (playerId != null) {
|
if (playerId != null) {
|
||||||
if (allJoined()) {
|
if (isAllJoined()) {
|
||||||
GameSessionPlayer gameSessionPlayer = gameSessions.get(playerId);
|
GameSessionPlayer gameSessionPlayer = gameSessions.get(playerId);
|
||||||
if (gameSessionPlayer != null) {
|
if (gameSessionPlayer != null) {
|
||||||
gameSessionPlayer.quitGame();
|
gameSessionPlayer.quitGame();
|
||||||
|
|
@ -492,7 +495,7 @@ public class GameController implements GameCallback {
|
||||||
Player player = game.getPlayer(playerId);
|
Player player = game.getPlayer(playerId);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
player.leave();
|
player.leave();
|
||||||
checkStart(); // => So the game starts and gets an result or multiplayer game starts with active players
|
checkJoinAndStart(); // => So the game starts and gets an result or multiplayer game starts with active players
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -734,6 +737,7 @@ public class GameController implements GameCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endGame(final String message) throws MageException {
|
public void endGame(final String message) throws MageException {
|
||||||
|
// send end game message/dialog
|
||||||
for (final GameSessionPlayer gameSession : getGameSessions()) {
|
for (final GameSessionPlayer gameSession : getGameSessions()) {
|
||||||
gameSession.gameOver(message);
|
gameSession.gameOver(message);
|
||||||
gameSession.removeGame();
|
gameSession.removeGame();
|
||||||
|
|
@ -741,6 +745,8 @@ public class GameController implements GameCallback {
|
||||||
for (final GameSessionWatcher gameWatcher : getGameSessionWatchers()) {
|
for (final GameSessionWatcher gameWatcher : getGameSessionWatchers()) {
|
||||||
gameWatcher.gameOver(message);
|
gameWatcher.gameOver(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start next game or close finished table
|
||||||
managerFactory.tableManager().endGame(tableId);
|
managerFactory.tableManager().endGame(tableId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -944,7 +950,7 @@ public class GameController implements GameCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void gameResult(String result) {
|
public void endGameWithResult(String result) {
|
||||||
try {
|
try {
|
||||||
endGame(result);
|
endGame(result);
|
||||||
} catch (MageException ex) {
|
} catch (MageException ex) {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
|
|
||||||
package mage.server.game;
|
package mage.server.game;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
import mage.MageException;
|
import mage.MageException;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param <T>
|
* Game: main thread to process full game (one thread per game)
|
||||||
* @author BetaSteward_at_googlemail.com
|
*
|
||||||
|
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||||
*/
|
*/
|
||||||
public class GameWorker<T> implements Callable {
|
public class GameWorker implements Callable<Boolean> {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(GameWorker.class);
|
private static final Logger LOGGER = Logger.getLogger(GameWorker.class);
|
||||||
|
|
||||||
|
|
@ -27,25 +27,23 @@ public class GameWorker<T> implements Callable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call() {
|
public Boolean call() {
|
||||||
try {
|
try {
|
||||||
LOGGER.debug("GAME WORKER started gameId " + game.getId());
|
// play game
|
||||||
Thread.currentThread().setName("GAME " + game.getId());
|
Thread.currentThread().setName("GAME " + game.getId());
|
||||||
game.start(choosingPlayerId);
|
game.start(choosingPlayerId);
|
||||||
game.fireUpdatePlayersEvent();
|
|
||||||
gameController.gameResult(game.getWinner());
|
// save result and start next game or close finished table
|
||||||
game.cleanUp();
|
game.fireUpdatePlayersEvent(); // TODO: no needs in update event (gameController.endGameWithResult already send game end dialog)?
|
||||||
} catch (MageException ex) {
|
gameController.endGameWithResult(game.getWinner());
|
||||||
LOGGER.fatal("GameWorker mage error [" + game.getId() + "] " + ex, ex);
|
|
||||||
} catch (Exception e) {
|
// clear resources
|
||||||
LOGGER.fatal("GameWorker general exception [" + game.getId() + "] " + e.getMessage(), e);
|
game.cleanUp();// TODO: no needs in cleanup code (cards list are useless for memory optimization, game states are more important)?
|
||||||
if (e instanceof NullPointerException) {
|
} catch (MageException e) {
|
||||||
LOGGER.info(e.getStackTrace());
|
LOGGER.fatal("GameWorker mage error [" + game.getId() + " - " + game + "]: " + e, e);
|
||||||
}
|
} catch (Throwable e) {
|
||||||
} catch (Error err) {
|
LOGGER.fatal("GameWorker system error [" + game.getId() + " - " + game + "]: " + e, e);
|
||||||
LOGGER.fatal("GameWorker general error [" + game.getId() + "] " + err, err);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ public class ReplaySession implements GameCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
gameResult("stopped replay");
|
endGameWithResult("stopped replay");
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void next() {
|
public synchronized void next() {
|
||||||
|
|
@ -51,7 +51,7 @@ public class ReplaySession implements GameCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void gameResult(final String result) {
|
public void endGameWithResult(final String result) {
|
||||||
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
||||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_DONE, replay.getGame().getId(), result)));
|
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_DONE, replay.getGame().getId(), result)));
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ public class ReplaySession implements GameCallback {
|
||||||
|
|
||||||
private void updateGame(final GameState state, Game game) {
|
private void updateGame(final GameState state, Game game) {
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
gameResult("game ended");
|
endGameWithResult("game ended");
|
||||||
} else {
|
} else {
|
||||||
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
managerFactory.userManager().getUser(userId).ifPresent(user ->
|
||||||
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_UPDATE, replay.getGame().getId(), new GameView(state, game, null, null))));
|
user.fireCallback(new ClientCallback(ClientCallbackMethod.REPLAY_UPDATE, replay.getGame().getId(), new GameView(state, game, null, null))));
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,34 @@
|
||||||
package mage.server.managers;
|
package mage.server.managers;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server side threads to execute some code/tasks
|
||||||
|
*/
|
||||||
public interface ThreadExecutor {
|
public interface ThreadExecutor {
|
||||||
|
|
||||||
int getActiveThreads(ExecutorService executerService);
|
int getActiveThreads(ExecutorService executerService);
|
||||||
|
|
||||||
ExecutorService getCallExecutor();
|
/**
|
||||||
|
* Main game thread (one per game)
|
||||||
|
*/
|
||||||
ExecutorService getGameExecutor();
|
ExecutorService getGameExecutor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper threads to execute async commands for game and server related tasks (example: process income command from a client)
|
||||||
|
*/
|
||||||
|
ExecutorService getCallExecutor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper threads to execute async timers and time related tasks
|
||||||
|
*/
|
||||||
ScheduledExecutorService getTimeoutExecutor();
|
ScheduledExecutorService getTimeoutExecutor();
|
||||||
|
|
||||||
ScheduledExecutorService getTimeoutIdleExecutor();
|
ScheduledExecutorService getTimeoutIdleExecutor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper thread to execute inner server tasks
|
||||||
|
*/
|
||||||
ScheduledExecutorService getServerHealthExecutor();
|
ScheduledExecutorService getServerHealthExecutor();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,48 @@ package org.mage.test.cards.single.inv;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author JayDi85
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
|
@Ignore // TODO: enable after deep copy fix
|
||||||
public class ManaMazeTest extends CardTestPlayerBase {
|
public class ManaMazeTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore // TODO: enable after deep copy fix
|
public void test_DeepCopy_WithSelfReference() {
|
||||||
public void test_DeepCopyWithWatcherAndSelfReference() {
|
// stack overflow bug: https://github.com/magefree/mage/issues/11572
|
||||||
|
|
||||||
|
// list
|
||||||
|
List<String> sourceList = new ArrayList<>(Arrays.asList("val1", "val2", "val3"));
|
||||||
|
List<String> copyList = CardUtil.deepCopyObject(sourceList);
|
||||||
|
Assert.assertNotSame(sourceList, copyList);
|
||||||
|
Assert.assertEquals(sourceList.size(), copyList.size());
|
||||||
|
Assert.assertEquals(sourceList.toString(), copyList.toString());
|
||||||
|
|
||||||
|
// list with self ref
|
||||||
|
List<List<Object>> sourceObjectList = new ArrayList<>();
|
||||||
|
sourceObjectList.add(new ArrayList<>(Arrays.asList("val1", "val2", "val3")));
|
||||||
|
sourceObjectList.add(new ArrayList<>(Arrays.asList(sourceObjectList)));
|
||||||
|
List<List<Object>> copyObjectList = CardUtil.deepCopyObject(sourceObjectList);
|
||||||
|
Assert.assertNotSame(sourceObjectList, copyObjectList);
|
||||||
|
Assert.assertEquals(sourceObjectList.size(), copyObjectList.size());
|
||||||
|
Assert.assertEquals(sourceObjectList.get(0).size(), copyObjectList.get(0).size());
|
||||||
|
Assert.assertEquals(sourceObjectList.get(0).toString(), copyObjectList.get(0).toString());
|
||||||
|
Assert.assertEquals(sourceObjectList.get(1).size(), copyObjectList.get(1).size());
|
||||||
|
Assert.assertEquals(sourceObjectList.get(1).toString(), copyObjectList.get(1).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DeepCopy_WatcherWithSelfReference() {
|
||||||
// stack overflow bug: https://github.com/magefree/mage/issues/11572
|
// stack overflow bug: https://github.com/magefree/mage/issues/11572
|
||||||
// card's watcher can have spell's ref to itself, so deep copy must be able to process it
|
// card's watcher can have spell's ref to itself, so deep copy must be able to process it
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ public class LoadTest {
|
||||||
// playing until game over
|
// playing until game over
|
||||||
while (!player1.client.isGameOver() && !player2.client.isGameOver()) {
|
while (!player1.client.isGameOver() && !player2.client.isGameOver()) {
|
||||||
checkGame = monitor.getTable(tableId);
|
checkGame = monitor.getTable(tableId);
|
||||||
logger.warn(checkGame.get().getTableState());
|
logger.info(checkGame.get().getTableState());
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
|
@ -236,6 +236,7 @@ public class LoadTest {
|
||||||
// playing until game over
|
// playing until game over
|
||||||
gameResult.start();
|
gameResult.start();
|
||||||
boolean startToWatching = false;
|
boolean startToWatching = false;
|
||||||
|
Date lastActivity = new Date();
|
||||||
while (true) {
|
while (true) {
|
||||||
GameView gameView = monitor.client.getLastGameView();
|
GameView gameView = monitor.client.getLastGameView();
|
||||||
|
|
||||||
|
|
@ -243,8 +244,8 @@ public class LoadTest {
|
||||||
TableState state = (checkGame == null ? null : checkGame.getTableState());
|
TableState state = (checkGame == null ? null : checkGame.getTableState());
|
||||||
|
|
||||||
if (gameView != null && checkGame != null) {
|
if (gameView != null && checkGame != null) {
|
||||||
logger.warn(checkGame.getTableName() + ": ---");
|
logger.info(checkGame.getTableName() + ": ---");
|
||||||
logger.warn(String.format("%s: turn %d, step %s, state %s",
|
logger.info(String.format("%s: turn %d, step %s, state %s",
|
||||||
checkGame.getTableName(),
|
checkGame.getTableName(),
|
||||||
gameView.getTurn(),
|
gameView.getTurn(),
|
||||||
gameView.getStep().toString(),
|
gameView.getStep().toString(),
|
||||||
|
|
@ -279,6 +280,13 @@ public class LoadTest {
|
||||||
activeInfo
|
activeInfo
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
logger.info(checkGame.getTableName() + ": ---");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ping to keep active session
|
||||||
|
if ((new Date().getTime() - lastActivity.getTime()) / 1000 > 10) {
|
||||||
|
monitor.session.ping();
|
||||||
|
lastActivity = new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -287,6 +295,9 @@ public class LoadTest {
|
||||||
logger.error(e.getMessage(), e);
|
logger.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all done, can disconnect now
|
||||||
|
monitor.session.connectStop(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -3973,10 +3973,11 @@ public abstract class GameImpl implements Game {
|
||||||
Player activePayer = this.getPlayer(this.getActivePlayerId());
|
Player activePayer = this.getPlayer(this.getActivePlayerId());
|
||||||
StringBuilder sb = new StringBuilder()
|
StringBuilder sb = new StringBuilder()
|
||||||
.append(this.isSimulation() ? "!!!SIMULATION!!! " : "")
|
.append(this.isSimulation() ? "!!!SIMULATION!!! " : "")
|
||||||
.append(this.getGameType().toString())
|
.append("; ").append(this.getGameType().toString())
|
||||||
.append("; ").append(CardUtil.getTurnInfo(this))
|
.append("; ").append(CardUtil.getTurnInfo(this))
|
||||||
.append("; active: ").append((activePayer == null ? "none" : activePayer.getName()))
|
.append("; active: ").append((activePayer == null ? "none" : activePayer.getName()))
|
||||||
.append("; stack: ").append(this.getStack().toString());
|
.append("; stack: ").append(this.getStack().toString())
|
||||||
|
.append(this.getState().isGameOver() ? "; FINISHED: " + this.getWinner() : "");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.game.match;
|
package mage.game.match;
|
||||||
|
|
||||||
import mage.cards.decks.DeckCardInfo;
|
import mage.cards.decks.DeckCardInfo;
|
||||||
|
|
@ -20,8 +19,8 @@ import java.util.*;
|
||||||
public class MatchOptions implements Serializable {
|
public class MatchOptions implements Serializable {
|
||||||
|
|
||||||
protected String name;
|
protected String name;
|
||||||
protected MultiplayerAttackOption attackOption;
|
protected MultiplayerAttackOption attackOption = MultiplayerAttackOption.LEFT;
|
||||||
protected RangeOfInfluence range;
|
protected RangeOfInfluence range = RangeOfInfluence.ALL;
|
||||||
protected int winsNeeded;
|
protected int winsNeeded;
|
||||||
protected int freeMulligans;
|
protected int freeMulligans;
|
||||||
protected boolean customStartLifeEnabled;
|
protected boolean customStartLifeEnabled;
|
||||||
|
|
@ -35,7 +34,7 @@ public class MatchOptions implements Serializable {
|
||||||
protected boolean multiPlayer;
|
protected boolean multiPlayer;
|
||||||
protected int numSeats;
|
protected int numSeats;
|
||||||
protected String password;
|
protected String password;
|
||||||
protected SkillLevel skillLevel;
|
protected SkillLevel skillLevel = SkillLevel.CASUAL;
|
||||||
protected boolean rollbackTurnsAllowed;
|
protected boolean rollbackTurnsAllowed;
|
||||||
protected boolean spectatorsAllowed;
|
protected boolean spectatorsAllowed;
|
||||||
protected boolean planeChase;
|
protected boolean planeChase;
|
||||||
|
|
@ -49,8 +48,8 @@ public class MatchOptions implements Serializable {
|
||||||
protected MatchBufferTime matchBufferTime = MatchBufferTime.NONE; // additional/buffer time limit for each priority before real time ticking starts
|
protected MatchBufferTime matchBufferTime = MatchBufferTime.NONE; // additional/buffer time limit for each priority before real time ticking starts
|
||||||
protected MulliganType mulliganType = MulliganType.GAME_DEFAULT;
|
protected MulliganType mulliganType = MulliganType.GAME_DEFAULT;
|
||||||
|
|
||||||
protected Collection<DeckCardInfo> perPlayerEmblemCards;
|
protected Collection<DeckCardInfo> perPlayerEmblemCards = Collections.emptySet();
|
||||||
protected Collection<DeckCardInfo> globalEmblemCards;
|
protected Collection<DeckCardInfo> globalEmblemCards = Collections.emptySet();
|
||||||
|
|
||||||
public MatchOptions(String name, String gameType, boolean multiPlayer, int numSeats) {
|
public MatchOptions(String name, String gameType, boolean multiPlayer, int numSeats) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
@ -58,8 +57,6 @@ public class MatchOptions implements Serializable {
|
||||||
this.password = "";
|
this.password = "";
|
||||||
this.multiPlayer = multiPlayer;
|
this.multiPlayer = multiPlayer;
|
||||||
this.numSeats = numSeats;
|
this.numSeats = numSeats;
|
||||||
this.perPlayerEmblemCards = Collections.emptySet();
|
|
||||||
this.globalEmblemCards = Collections.emptySet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNumSeats(int numSeats) {
|
public void setNumSeats(int numSeats) {
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ Github issues page contain [popular problems and fixes](https://github.com/magef
|
||||||
* [Any: can't run client, could not open ...jvm.cfg](https://github.com/magefree/mage/issues/1272#issuecomment-529789018);
|
* [Any: can't run client, could not open ...jvm.cfg](https://github.com/magefree/mage/issues/1272#issuecomment-529789018);
|
||||||
* [Any: no texts or small buttons in launcher](https://github.com/magefree/mage/issues/4126);
|
* [Any: no texts or small buttons in launcher](https://github.com/magefree/mage/issues/4126);
|
||||||
* [Windows: ugly cards, buttons or other GUI drawing artifacts](https://github.com/magefree/mage/issues/4626#issuecomment-374640070);
|
* [Windows: ugly cards, buttons or other GUI drawing artifacts](https://github.com/magefree/mage/issues/4626#issuecomment-374640070);
|
||||||
* [MacOS: can't open launcher](https://www.reddit.com/r/XMage/comments/kf8l34/updated_java_on_osx_xmage_not_working/ggej8cq/)
|
* [MacOS: can't open launcher](https://www.reddit.com/r/XMage/comments/kf8l34/updated_java_on_osx_xmage_not_working/ggej8cq/);
|
||||||
* [MacOS: client freezes in GUI (on connect dialog, on new match)](https://github.com/magefree/mage/issues/4920#issuecomment-517944308);
|
* [MacOS: client freezes in GUI (on connect dialog, on new match)](https://github.com/magefree/mage/issues/4920#issuecomment-517944308);
|
||||||
* [Linux: run on non-standard OS or hardware like Raspberry Pi](https://github.com/magefree/mage/issues/11611#issuecomment-1879385151);
|
* [Linux: run on non-standard OS or hardware like Raspberry Pi](https://github.com/magefree/mage/issues/11611#issuecomment-1879385151);
|
||||||
* [Linux: ugly GUI and drawing artifacts](https://github.com/magefree/mage/issues/11611#issuecomment-1879396921);
|
* [Linux: ugly GUI and drawing artifacts](https://github.com/magefree/mage/issues/11611#issuecomment-1879396921);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue