diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 81ee232f83c..995303191fa 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -705,7 +705,7 @@ public class HumanPlayer extends PlayerImpl { // it's a main phase if (!skippedAtLeastOnce || (!playerId.equals(game.getActivePlayerId()) - && !this.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases())) { + && !controllingPlayer.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases())) { skippedAtLeastOnce = true; if (passWithManaPoolCheck(game)) { return false; @@ -726,7 +726,7 @@ public class HumanPlayer extends PlayerImpl { // It's end of turn phase if (!skippedAtLeastOnce || (playerId.equals(game.getActivePlayerId()) - && !this.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases())) { + && !controllingPlayer.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases())) { skippedAtLeastOnce = true; if (passWithManaPoolCheck(game)) { return false; @@ -834,7 +834,7 @@ public class HumanPlayer extends PlayerImpl { return !controllingPlayer.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType()); } } catch (NullPointerException ex) { - String isNull = userData == null ? "null" : "not null"; + String isNull = controllingPlayer.getUserData() == null ? "null" : "not null"; logger.error("null pointer exception UserData = " + isNull); } return true; @@ -843,7 +843,7 @@ public class HumanPlayer extends PlayerImpl { @Override public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { String autoOrderRuleText = null; - boolean autoOrderUse = getUserData().isAutoOrderTrigger(); + boolean autoOrderUse = getControllingPlayersUserData(game).isAutoOrderTrigger(); while (!abort) { // try to set trigger auto order List abilitiesWithNoOrderSet = new ArrayList<>(); @@ -1045,7 +1045,7 @@ public class HumanPlayer extends PlayerImpl { while (!abort) { if (passedAllTurns || passedUntilEndStepBeforeMyTurn - || (!getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction() + || (!getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction() && (passedTurn || passedTurnSkipStack || passedUntilEndOfTurn @@ -1223,7 +1223,7 @@ public class HumanPlayer extends PlayerImpl { FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy(); filter.add(new ControllerIdPredicate(defendingPlayerId)); if (game.getBattlefield().count(filter, null, playerId, game) == 0 - && !getUserData().getUserSkipPrioritySteps().isStopOnDeclareBlockerIfNoneAvailable()) { + && !getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockerIfNoneAvailable()) { return; } while (!abort) { @@ -1420,7 +1420,7 @@ public class HumanPlayer extends PlayerImpl { protected void activateAbility(LinkedHashMap abilities, MageObject object, Game game) { updateGameStatePriority("activateAbility", game); if (abilities.size() == 1 - && suppressAbilityPicker(abilities.values().iterator().next())) { + && suppressAbilityPicker(abilities.values().iterator().next(), game)) { ActivatedAbility ability = abilities.values().iterator().next(); if (!ability.getTargets().isEmpty() || !(ability.getCosts().size() == 1 @@ -1452,8 +1452,8 @@ public class HumanPlayer extends PlayerImpl { } } - private boolean suppressAbilityPicker(ActivatedAbility ability) { - if (this.getUserData().isShowAbilityPickerForced()) { + private boolean suppressAbilityPicker(ActivatedAbility ability, Game game) { + if (getControllingPlayersUserData(game).isShowAbilityPickerForced()) { if (ability instanceof PlayLandAbility) { return true; } diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index c0bef58e387..ac5f818ee78 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -27,6 +27,13 @@ */ package mage.server; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.server.exceptions.UserNotFoundException; @@ -36,11 +43,6 @@ import mage.view.ChatMessage.MessageType; import mage.view.ChatMessage.SoundToPlay; import org.apache.log4j.Logger; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * @author BetaSteward_at_googlemail.com */ @@ -51,6 +53,7 @@ public enum ChatManager { private static final HashMap userMessages = new HashMap<>(); private final ConcurrentHashMap chatSessions = new ConcurrentHashMap<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); public UUID createChatSession(String info) { ChatSession chatSession = new ChatSession(info); @@ -68,6 +71,10 @@ public enum ChatManager { } + public void clearUserMessageStorage() { + userMessages.clear(); + } + public void leaveChat(UUID chatId, UUID userId) { ChatSession chatSession = chatSessions.get(chatId); if (chatSession != null && chatSession.hasUser(userId)) { @@ -81,7 +88,13 @@ public enum ChatManager { if (chatSession != null) { synchronized (chatSession) { if (chatSessions.containsKey(chatId)) { - chatSessions.remove(chatId); + final Lock w = lock.writeLock(); + w.lock(); + try { + chatSessions.remove(chatId); + } finally { + w.unlock(); + } logger.trace("Chat removed - chatId: " + chatId); } else { logger.trace("Chat to destroy does not exist - chatId: " + chatId); @@ -263,10 +276,11 @@ public enum ChatManager { * @param userId * @param message * @param color + * @throws mage.server.exceptions.UserNotFoundException */ public void broadcast(UUID userId, String message, MessageColor color) throws UserNotFoundException { UserManager.instance.getUser(userId).ifPresent(user -> { - chatSessions.values() + getChatSessions() .stream() .filter(chat -> chat.hasUser(userId)) .forEach(session -> session.broadcast(user.getName(), message, color, true, MessageType.TALK, null)); @@ -276,15 +290,15 @@ public enum ChatManager { public void sendReconnectMessage(UUID userId) { UserManager.instance.getUser(userId).ifPresent(user - -> chatSessions.values() - .stream() - .filter(chat -> chat.hasUser(userId)) - .forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null))); + -> getChatSessions() + .stream() + .filter(chat -> chat.hasUser(userId)) + .forEach(chatSession -> chatSession.broadcast(null, user.getName() + " has reconnected", MessageColor.BLUE, true, MessageType.STATUS, null))); } public void removeUser(UUID userId, DisconnectReason reason) { - for (ChatSession chatSession : chatSessions.values()) { + for (ChatSession chatSession : getChatSessions()) { if (chatSession.hasUser(userId)) { chatSession.kill(userId, reason); } @@ -292,7 +306,13 @@ public enum ChatManager { } public List getChatSessions() { - return new ArrayList<>(chatSessions.values()); + final Lock r = lock.readLock(); + r.lock(); + try { + return new ArrayList<>(chatSessions.values()); + } finally { + r.unlock(); + } } } diff --git a/Mage.Server/src/main/java/mage/server/ChatSession.java b/Mage.Server/src/main/java/mage/server/ChatSession.java index d75c43a14c1..2e92707a5e0 100644 --- a/Mage.Server/src/main/java/mage/server/ChatSession.java +++ b/Mage.Server/src/main/java/mage/server/ChatSession.java @@ -30,6 +30,9 @@ package mage.server; import java.text.DateFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import mage.interfaces.callback.ClientCallback; import mage.interfaces.callback.ClientCallbackMethod; import mage.view.ChatMessage; @@ -46,6 +49,8 @@ public class ChatSession { private static final Logger logger = Logger.getLogger(ChatSession.class); private static final DateFormat timeFormatter = DateFormat.getTimeInstance(DateFormat.SHORT); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final ConcurrentHashMap clients = new ConcurrentHashMap<>(); private final UUID chatId; private final Date createTime; @@ -61,7 +66,13 @@ public class ChatSession { UserManager.instance.getUser(userId).ifPresent(user -> { if (!clients.containsKey(userId)) { String userName = user.getName(); - clients.put(userId, userName); + final Lock w = lock.writeLock(); + w.lock(); + try { + clients.put(userId, userName); + } finally { + w.unlock(); + } broadcast(null, userName + " has joined (" + user.getClientVersion() + ')', MessageColor.BLUE, true, MessageType.STATUS, null); logger.trace(userName + " joined chat " + chatId); } @@ -77,8 +88,14 @@ public class ChatSession { } if (userId != null && clients.containsKey(userId)) { String userName = clients.get(userId); - if (reason != DisconnectReason.LostConnection) { // for lost connection the user will be reconnected or session expire so no removeUserFromAllTables of chat yet - clients.remove(userId); + if (reason != DisconnectReason.LostConnection) { // for lost connection the user will be reconnected or session expire so no removeUserFromAllTablesAndChat of chat yet + final Lock w = lock.writeLock(); + w.lock(); + try { + clients.remove(userId); + } finally { + w.unlock(); + } logger.debug(userName + '(' + reason.toString() + ')' + " removed from chatId " + chatId); } String message = reason.getMessage(); @@ -117,7 +134,15 @@ public class ChatSession { if (!message.isEmpty()) { Set clientsToRemove = new HashSet<>(); ClientCallback clientCallback = new ClientCallback(ClientCallbackMethod.CHATMESSAGE, chatId, new ChatMessage(userName, message, (withTime ? timeFormatter.format(new Date()) : ""), color, messageType, soundToPlay)); - for (UUID userId : clients.keySet()) { + List chatUserIds = new ArrayList<>(); + final Lock r = lock.readLock(); + r.lock(); + try { + chatUserIds.addAll(clients.keySet()); + } finally { + r.unlock(); + } + for (UUID userId : chatUserIds) { Optional user = UserManager.instance.getUser(userId); if (user.isPresent()) { user.get().fireCallback(clientCallback); @@ -125,7 +150,15 @@ public class ChatSession { clientsToRemove.add(userId); } } - clients.keySet().removeAll(clientsToRemove); + if (!clientsToRemove.isEmpty()) { + final Lock w = lock.readLock(); + w.lock(); + try { + clients.keySet().removeAll(clientsToRemove); + } finally { + w.unlock(); + } + } } } diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 96d2a10858d..1e5127dd9e8 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -356,7 +356,7 @@ public class Session { } else { logger.error("SESSION LOCK - kill: userId " + userId); } - UserManager.instance.removeUserFromAllTables(userId, reason); + UserManager.instance.removeUserFromAllTablesAndChat(userId, reason); } catch (InterruptedException ex) { logger.error("SESSION LOCK - kill: userId " + userId, ex); } finally { diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 71a5e9deb4d..000c51126cb 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -511,7 +511,7 @@ public class TableController { if (this.userId != null && this.userId.equals(userId) // tourn. sub tables have no creator user && (table.getState() == TableState.WAITING || table.getState() == TableState.READY_TO_START)) { - // table not started yet and user is the owner, removeUserFromAllTables the table + // table not started yet and user is the owner, removeUserFromAllTablesAndChat the table TableManager.instance.removeTable(table.getId()); } else { UUID playerId = userPlayerMap.get(userId); @@ -826,7 +826,7 @@ public class TableController { } user.showUserMessage("Match info", sb.toString()); } - // removeUserFromAllTables table from user - table manager holds table for display of finished matches + // removeUserFromAllTablesAndChat table from user - table manager holds table for display of finished matches if (!table.isTournamentSubTable()) { user.removeTable(entry.getValue()); } @@ -913,7 +913,7 @@ public class TableController { return false; } } else { - // check if table creator is still a valid user, if not removeUserFromAllTables table + // check if table creator is still a valid user, if not removeUserFromAllTablesAndChat table return UserManager.instance.getUser(userId).isPresent(); } } diff --git a/Mage.Server/src/main/java/mage/server/TableManager.java b/Mage.Server/src/main/java/mage/server/TableManager.java index f068bbc9049..d03e4872b14 100644 --- a/Mage.Server/src/main/java/mage/server/TableManager.java +++ b/Mage.Server/src/main/java/mage/server/TableManager.java @@ -78,6 +78,7 @@ public enum TableManager { TableManager() { expireExecutor.scheduleAtFixedRate(() -> { try { + ChatManager.instance.clearUserMessageStorage(); checkTableHealthState(); } catch (Exception ex) { logger.fatal("Check table health state job error:", ex); @@ -161,7 +162,7 @@ public enum TableManager { } } - // removeUserFromAllTables user from all tournament sub tables + // removeUserFromAllTablesAndChat user from all tournament sub tables public void userQuitTournamentSubTables(UUID userId) { for (TableController controller : controllers.values()) { if (controller.getTable() != null) { @@ -174,7 +175,7 @@ public enum TableManager { } } - // removeUserFromAllTables user from all sub tables of a tournament + // removeUserFromAllTablesAndChat user from all sub tables of a tournament public void userQuitTournamentSubTables(UUID tournamentId, UUID userId) { for (TableController controller : controllers.values()) { if (controller.getTable().isTournamentSubTable() && controller.getTable().getTournament().getId().equals(tournamentId)) { @@ -386,8 +387,8 @@ public enum TableManager { for (Table table : tableCopy) { try { if (table.getState() != TableState.FINISHED - && ((System.currentTimeMillis() - table.getStartTime().getTime()) / 1000) > 30) { // removeUserFromAllTables only if table started longer than 30 seconds ago - // removeUserFromAllTables tables and games not valid anymore + && ((System.currentTimeMillis() - table.getStartTime().getTime()) / 1000) > 30) { // removeUserFromAllTablesAndChat only if table started longer than 30 seconds ago + // removeUserFromAllTablesAndChat tables and games not valid anymore logger.debug(table.getId() + " [" + table.getName() + "] " + formatter.format(table.getStartTime() == null ? table.getCreateTime() : table.getCreateTime()) + " (" + table.getState().toString() + ") " + (table.isTournament() ? "- Tournament" : "")); getController(table.getId()).ifPresent(tableController -> { if ((table.isTournament() && !tableController.isTournamentStillValid()) diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index 1c937776a72..298914c94fd 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -29,6 +29,9 @@ package mage.server; import java.util.*; import java.util.concurrent.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import mage.server.User.UserState; import mage.server.record.UserStats; import mage.server.record.UserStatsRepository; @@ -54,6 +57,7 @@ public enum UserManager { private static final Logger LOGGER = Logger.getLogger(UserManager.class); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final ConcurrentHashMap users = new ConcurrentHashMap<>(); private static final ExecutorService USER_EXECUTOR = ThreadExecutor.instance.getCallExecutor(); @@ -69,7 +73,13 @@ public enum UserManager { return Optional.empty(); //user already exists } User user = new User(userName, host, authorizedUser); - users.put(user.getId(), user); + final Lock w = lock.writeLock(); + w.lock(); + try { + users.put(user.getId(), user); + } finally { + w.unlock(); + } return Optional.of(user); } @@ -83,17 +93,32 @@ public enum UserManager { } public Optional getUserByName(String userName) { - Optional u = users.values().stream().filter(user -> user.getName().equals(userName)) - .findFirst(); - if (u.isPresent()) { - return u; - } else { - return Optional.empty(); + final Lock r = lock.readLock(); + r.lock(); + try { + Optional u = users.values().stream().filter(user -> user.getName().equals(userName)) + .findFirst(); + if (u.isPresent()) { + return u; + } else { + return Optional.empty(); + } + } finally { + r.unlock(); } + } public Collection getUsers() { - return users.values(); + ArrayList userList = new ArrayList<>(); + final Lock r = lock.readLock(); + r.lock(); + try { + userList.addAll(users.values()); + } finally { + r.unlock(); + } + return userList; } public boolean connectToSession(String sessionId, UUID userId) { @@ -112,13 +137,10 @@ public enum UserManager { if (user.isPresent()) { user.get().setSessionId(""); if (reason == DisconnectReason.Disconnected) { - removeUserFromAllTables(userId, reason); + removeUserFromAllTablesAndChat(userId, reason); user.get().setUserState(UserState.Offline); } } - if (userId != null) { - ChatManager.instance.removeUser(userId, reason); - } } public boolean isAdmin(UUID userId) { @@ -131,7 +153,7 @@ public enum UserManager { return false; } - public void removeUserFromAllTables(final UUID userId, final DisconnectReason reason) { + public void removeUserFromAllTablesAndChat(final UUID userId, final DisconnectReason reason) { if (userId != null) { getUser(userId).ifPresent(user -> USER_EXECUTOR.execute( @@ -139,6 +161,7 @@ public enum UserManager { try { LOGGER.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId + " [" + user.getGameInfo() + ']'); user.removeUserFromAllTables(reason); + ChatManager.instance.removeUser(user.getId(), reason); LOGGER.debug("USER REMOVE END - " + user.getName()); } catch (Exception ex) { handleException(ex); @@ -173,7 +196,16 @@ public enum UserManager { Calendar calendarRemove = Calendar.getInstance(); calendarRemove.add(Calendar.MINUTE, -8); List toRemove = new ArrayList<>(); - for (User user : users.values()) { + logger.info("Start Check Expired"); + ArrayList userList = new ArrayList<>(); + final Lock r = lock.readLock(); + r.lock(); + try { + userList.addAll(users.values()); + } finally { + r.unlock(); + } + for (User user : userList) { try { if (user.getUserState() == UserState.Offline) { if (user.isExpired(calendarRemove.getTime())) { @@ -185,7 +217,7 @@ public enum UserManager { user.lostConnection(); disconnect(user.getId(), DisconnectReason.BecameInactive); } - removeUserFromAllTables(user.getId(), DisconnectReason.SessionExpired); + removeUserFromAllTablesAndChat(user.getId(), DisconnectReason.SessionExpired); user.setUserState(UserState.Offline); // Remove the user from all tournaments @@ -195,9 +227,17 @@ public enum UserManager { handleException(ex); } } - for (User user : toRemove) { - users.remove(user.getId()); + logger.info("Users to remove " + toRemove.size()); + final Lock w = lock.readLock(); + w.lock(); + try { + for (User user : toRemove) { + users.remove(user.getId()); + } + } finally { + w.unlock(); } + logger.info("End Check Expired"); } catch (Exception ex) { handleException(ex); } diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java index f405558091c..4a681020e4f 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -95,7 +95,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { } else if (matchList.size() < 50) { matchList.add(new MatchView(table)); } else { - // more since 50 matches finished since this match so removeUserFromAllTables it + // more since 50 matches finished since this match so removeUserFromAllTablesAndChat it if (table.isTournament()) { TournamentManager.instance.removeTournament(table.getTournament().getId()); } diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 412d99bb309..f89b12858ca 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -54,6 +54,11 @@ import mage.cards.CardsImpl; import mage.cards.SplitCard; import mage.cards.decks.Deck; import mage.constants.*; +import static mage.constants.Zone.BATTLEFIELD; +import static mage.constants.Zone.EXILED; +import static mage.constants.Zone.GRAVEYARD; +import static mage.constants.Zone.HAND; +import static mage.constants.Zone.LIBRARY; import mage.counters.Counter; import mage.counters.CounterType; import mage.counters.Counters; @@ -965,6 +970,10 @@ public abstract class PlayerImpl implements Player, Serializable { ability = chooseSpellAbilityForCast(ability, game, noMana); } //20091005 - 601.2a + if (ability.getSourceId() == null) { + logger.error("Ability without sourceId turn " + game.getTurnNum() + ". Ability: " + ability.getRule()); + return false; + } Card card = game.getCard(ability.getSourceId()); if (card != null) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId), ability)) { @@ -2931,15 +2940,27 @@ public abstract class PlayerImpl implements Player, Serializable { return this.userData; } + public UserData getControllingPlayersUserData(Game game) { + if (isGameUnderControl()) { + Player player = game.getPlayer(getTurnControlledBy()); + if (player.isHuman()) { + return player.getUserData(); + } + } + return this.userData; + } + @Override - public void setUserData(UserData userData) { + public void setUserData(UserData userData + ) { this.userData = userData; getManaPool().setAutoPayment(userData.isManaPoolAutomatic()); getManaPool().setAutoPaymentRestricted(userData.isManaPoolAutomaticRestricted()); } @Override - public void addAction(String action) { + public void addAction(String action + ) { // do nothing } @@ -2949,7 +2970,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setAllowBadMoves(boolean allowBadMoves) { + public void setAllowBadMoves(boolean allowBadMoves + ) { // do nothing } @@ -2959,17 +2981,21 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setCanPayLifeCost(boolean canPayLifeCost) { + public void setCanPayLifeCost(boolean canPayLifeCost + ) { this.canPayLifeCost = canPayLifeCost; } @Override - public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, UUID controllerId, Game game) { + public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, + UUID controllerId, Game game + ) { return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); } @Override - public void setCanPaySacrificeCostFilter(FilterPermanent filter) { + public void setCanPaySacrificeCostFilter(FilterPermanent filter + ) { this.sacrificeCostFilter = filter; } @@ -2984,7 +3010,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife) { + public void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife + ) { this.loseByZeroOrLessLife = loseByZeroOrLessLife; } @@ -2994,7 +3021,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard) { + public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard + ) { this.canPlayCardsFromGraveyard = playCardsFromGraveyard; } @@ -3021,12 +3049,14 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setStoredBookmark(int storedBookmark) { + public void setStoredBookmark(int storedBookmark + ) { this.storedBookmark = storedBookmark; } @Override - public synchronized void resetStoredBookmark(Game game) { + public synchronized void resetStoredBookmark(Game game + ) { if (this.storedBookmark != -1) { game.removeBookmark(this.storedBookmark); } @@ -3034,7 +3064,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean lookAtFaceDownCard(Card card, Game game) { + public boolean lookAtFaceDownCard(Card card, Game game + ) { if (game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, this.getId(), game)) { if (chooseUse(Outcome.Benefit, "Look at that card?", null, game)) { Cards cards = new CardsImpl(card); @@ -3046,7 +3077,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setPriorityTimeLeft(int timeLeft) { + public void setPriorityTimeLeft(int timeLeft + ) { priorityTimeLeft = timeLeft; } @@ -3071,7 +3103,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving) { + public void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving + ) { this.reachedNextTurnAfterLeaving = reachedNextTurnAfterLeaving; } @@ -3081,12 +3114,14 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean canJoinTable(Table table) { + public boolean canJoinTable(Table table + ) { return !table.userIsBanned(name); } @Override - public void addCommanderId(UUID commanderId) { + public void addCommanderId(UUID commanderId + ) { this.commandersIds.add(commanderId); } @@ -3096,12 +3131,17 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCards(Card card, Zone toZone, Ability source, Game game) { + public boolean moveCards(Card card, Zone toZone, + Ability source, Game game + ) { return moveCards(card, toZone, source, game, false, false, false, null); } @Override - public boolean moveCards(Card card, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects) { + public boolean moveCards(Card card, Zone toZone, + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + ) { Set cardList = new HashSet<>(); if (card != null) { cardList.add(card); @@ -3110,17 +3150,24 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCards(Cards cards, Zone toZone, Ability source, Game game) { + public boolean moveCards(Cards cards, Zone toZone, + Ability source, Game game + ) { return moveCards(cards.getCards(game), toZone, source, game); } @Override - public boolean moveCards(Set cards, Zone toZone, Ability source, Game game) { + public boolean moveCards(Set cards, Zone toZone, + Ability source, Game game + ) { return moveCards(cards, toZone, source, game, false, false, false, null); } @Override - public boolean moveCards(Set cards, Zone toZone, Ability source, Game game, boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects) { + public boolean moveCards(Set cards, Zone toZone, + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + ) { if (cards.isEmpty()) { return true; } @@ -3194,14 +3241,20 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) { + public boolean moveCardsToExile(Card card, Ability source, + Game game, boolean withName, UUID exileId, + String exileZoneName + ) { Set cards = new HashSet<>(); cards.add(card); return moveCardsToExile(cards, source, game, withName, exileId, exileZoneName); } @Override - public boolean moveCardsToExile(Set cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) { + public boolean moveCardsToExile(Set cards, Ability source, + Game game, boolean withName, UUID exileId, + String exileZoneName + ) { if (cards.isEmpty()) { return true; } @@ -3214,12 +3267,16 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game) { + public boolean moveCardToHandWithInfo(Card card, UUID sourceId, + Game game + ) { return this.moveCardToHandWithInfo(card, sourceId, game, true); } @Override - public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, boolean withName) { + public boolean moveCardToHandWithInfo(Card card, UUID sourceId, + Game game, boolean withName + ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); if (fromZone == Zone.BATTLEFIELD && !(card instanceof Permanent)) { @@ -3242,7 +3299,9 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, Game game, Zone fromZone) { + public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, + Game game, Zone fromZone + ) { UUID sourceId = source == null ? null : source.getSourceId(); Set movedCards = new LinkedHashSet<>(); while (!allCards.isEmpty()) { @@ -3309,7 +3368,9 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) { + public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, + Game game, Zone fromZone + ) { if (card == null) { return false; } @@ -3336,7 +3397,10 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) { + public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, + Game game, Zone fromZone, + boolean toTop, boolean withName + ) { if (card == null) { return false; } @@ -3368,7 +3432,11 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone, boolean withName) { + public boolean moveCardToExileWithInfo(Card card, UUID exileId, + String exileName, UUID sourceId, + Game game, Zone fromZone, + boolean withName + ) { if (card == null) { return false; } @@ -3398,7 +3466,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean hasOpponent(UUID playerToCheckId, Game game) { + public boolean hasOpponent(UUID playerToCheckId, Game game + ) { return !this.getId().equals(playerToCheckId) && game.isOpponent(this, playerToCheckId); } @@ -3443,7 +3512,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setJustActivatedType(AbilityType justActivatedType) { + public void setJustActivatedType(AbilityType justActivatedType + ) { this.justActivatedType = justActivatedType; } @@ -3453,7 +3523,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void addPermissionToShowHandCards(UUID watcherUserId) { + public void addPermissionToShowHandCards(UUID watcherUserId + ) { usersAllowedToSeeHandCards.add(watcherUserId); } @@ -3463,7 +3534,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean hasUserPermissionToSeeHand(UUID userId) { + public boolean hasUserPermissionToSeeHand(UUID userId + ) { return usersAllowedToSeeHandCards.contains(userId); } @@ -3473,7 +3545,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public void setMatchPlayer(MatchPlayer matchPlayer) { + public void setMatchPlayer(MatchPlayer matchPlayer + ) { this.matchPlayer = matchPlayer; } @@ -3488,7 +3561,9 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean scry(int value, Ability source, Game game) { + public boolean scry(int value, Ability source, + Game game + ) { game.informPlayers(getLogName() + " scries " + value); Cards cards = new CardsImpl(); cards.addAll(getLibrary().getTopCards(game, value)); @@ -3510,7 +3585,8 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean addTargets(Ability ability, Game game) { + public boolean addTargets(Ability ability, Game game + ) { // only used for TestPlayer to preSet Targets return true; }