From b9530e307d87478a6da109eded646b8a1038c80b Mon Sep 17 00:00:00 2001 From: sprangg Date: Mon, 26 Sep 2022 00:33:16 +0300 Subject: [PATCH] Draft stability improvements (#9435) --- .../main/java/mage/client/SessionHandler.java | 4 ++ .../java/mage/client/draft/DraftPanel.java | 2 + .../main/java/mage/interfaces/MageServer.java | 2 + .../main/java/mage/remote/SessionImpl.java | 14 +++++ .../java/mage/remote/interfaces/GamePlay.java | 2 + .../main/java/mage/server/MageServerImpl.java | 10 ++++ .../mage/server/draft/DraftController.java | 4 ++ .../mage/server/draft/DraftManagerImpl.java | 5 ++ .../java/mage/server/draft/DraftSession.java | 4 ++ .../mage/server/managers/DraftManager.java | 2 + Mage/src/main/java/mage/game/draft/Draft.java | 1 + .../main/java/mage/game/draft/DraftImpl.java | 57 +++++++++++++++++-- .../java/mage/game/draft/DraftPlayer.java | 13 +++++ 13 files changed, 116 insertions(+), 4 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/SessionHandler.java b/Mage.Client/src/main/java/mage/client/SessionHandler.java index cf8d0731d9..4e0b20dad4 100644 --- a/Mage.Client/src/main/java/mage/client/SessionHandler.java +++ b/Mage.Client/src/main/java/mage/client/SessionHandler.java @@ -273,6 +273,10 @@ public final class SessionHandler { public static void sendCardMark(UUID draftId, UUID id) { session.sendCardMark(draftId, id); } + + public static void setBoosterLoaded(UUID draftId) { + session.setBoosterLoaded(draftId); + } public static Optional getRoomChatId(UUID roomId) { return session.getRoomChatId(roomId); diff --git a/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java b/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java index 241545a9ff..6bae8df419 100644 --- a/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java +++ b/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java @@ -303,6 +303,8 @@ if (timeout != 0) { countdown.start(); } + + SessionHandler.setBoosterLoaded(draftId); // confirm to the server that the booster has been loaded } private void loadCardsToPickedCardsArea(SimpleCardsView pickedCards) { diff --git a/Mage.Common/src/main/java/mage/interfaces/MageServer.java b/Mage.Common/src/main/java/mage/interfaces/MageServer.java index 059f21ce63..a80f1a4ed6 100644 --- a/Mage.Common/src/main/java/mage/interfaces/MageServer.java +++ b/Mage.Common/src/main/java/mage/interfaces/MageServer.java @@ -149,6 +149,8 @@ public interface MageServer { void sendCardMark(UUID draftId, String sessionId, UUID cardId) throws MageException; + void setBoosterLoaded(UUID draftId, String sessionId) throws MageException; + //challenge methods // void startChallenge(String sessionId, UUID roomId, UUID tableId, UUID challengeId) throws MageException; //replay methods diff --git a/Mage.Common/src/main/java/mage/remote/SessionImpl.java b/Mage.Common/src/main/java/mage/remote/SessionImpl.java index c8b3f7f1a3..05edd36263 100644 --- a/Mage.Common/src/main/java/mage/remote/SessionImpl.java +++ b/Mage.Common/src/main/java/mage/remote/SessionImpl.java @@ -987,6 +987,20 @@ public class SessionImpl implements Session { } return null; } + + @Override + public boolean setBoosterLoaded(UUID draftId) { + try { + if (isConnected()) { + server.setBoosterLoaded(draftId, sessionId); + } + } catch (MageException ex) { + handleMageException(ex); + } catch (Throwable t) { + handleThrowable(t); + } + return false; + } @Override public boolean joinChat(UUID chatId) { diff --git a/Mage.Common/src/main/java/mage/remote/interfaces/GamePlay.java b/Mage.Common/src/main/java/mage/remote/interfaces/GamePlay.java index 2104500116..930c932415 100644 --- a/Mage.Common/src/main/java/mage/remote/interfaces/GamePlay.java +++ b/Mage.Common/src/main/java/mage/remote/interfaces/GamePlay.java @@ -39,6 +39,8 @@ public interface GamePlay { boolean updateDeck(UUID tableId, DeckCardLists deck); + boolean setBoosterLoaded(UUID draftId); + DraftPickView sendCardPick(UUID draftId, UUID cardId, Set hiddenCards); DraftPickView sendCardMark(UUID draftId, UUID cardId); diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 19608585be..3e5ac7875e 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -736,6 +736,16 @@ public class MageServerImpl implements MageServer { }); }); } + + @Override + public void setBoosterLoaded(final UUID draftId, final String sessionId) throws MageException { + execute("setBoosterLoaded", sessionId, () -> { + managerFactory.sessionManager().getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); + managerFactory.draftManager().setBoosterLoaded(draftId, userId); + }); + }); + } @Override public void quitMatch(final UUID gameId, final String sessionId) throws MageException { diff --git a/Mage.Server/src/main/java/mage/server/draft/DraftController.java b/Mage.Server/src/main/java/mage/server/draft/DraftController.java index 18da1ae240..bf60355656 100644 --- a/Mage.Server/src/main/java/mage/server/draft/DraftController.java +++ b/Mage.Server/src/main/java/mage/server/draft/DraftController.java @@ -199,6 +199,10 @@ public class DraftController { public void sendCardMark(UUID userId, UUID cardId) { draftSessions.get(userPlayerMap.get(userId)).setMarkedCard(cardId); } + + public void setBoosterLoaded(UUID userId) { + draftSessions.get(userPlayerMap.get(userId)).setBoosterLoaded(); + } private synchronized void updateDraft() throws MageException { for (final Entry entry : draftSessions.entrySet()) { diff --git a/Mage.Server/src/main/java/mage/server/draft/DraftManagerImpl.java b/Mage.Server/src/main/java/mage/server/draft/DraftManagerImpl.java index 69127d4479..ffa104b61e 100644 --- a/Mage.Server/src/main/java/mage/server/draft/DraftManagerImpl.java +++ b/Mage.Server/src/main/java/mage/server/draft/DraftManagerImpl.java @@ -49,6 +49,11 @@ public class DraftManagerImpl implements DraftManager { public void sendCardMark(UUID draftId, UUID userId, UUID cardId) { draftControllers.get(draftId).sendCardMark(userId, cardId); } + + @Override + public void setBoosterLoaded(UUID draftId, UUID userId) { + draftControllers.get(draftId).setBoosterLoaded(userId); + } @Override public void removeSession(UUID userId) { diff --git a/Mage.Server/src/main/java/mage/server/draft/DraftSession.java b/Mage.Server/src/main/java/mage/server/draft/DraftSession.java index bea9c5b612..98f8ab3d86 100644 --- a/Mage.Server/src/main/java/mage/server/draft/DraftSession.java +++ b/Mage.Server/src/main/java/mage/server/draft/DraftSession.java @@ -144,5 +144,9 @@ public class DraftSession { public void setMarkedCard(UUID markedCard) { this.markedCard = markedCard; } + + public void setBoosterLoaded() { + draft.setBoosterLoaded(playerId); + } } diff --git a/Mage.Server/src/main/java/mage/server/managers/DraftManager.java b/Mage.Server/src/main/java/mage/server/managers/DraftManager.java index d9d17a9900..d3853dbb97 100644 --- a/Mage.Server/src/main/java/mage/server/managers/DraftManager.java +++ b/Mage.Server/src/main/java/mage/server/managers/DraftManager.java @@ -19,6 +19,8 @@ public interface DraftManager { DraftPickView sendCardPick(UUID draftId, UUID userId, UUID cardId, Set hiddenCards); void sendCardMark(UUID draftId, UUID userId, UUID cardId); + + void setBoosterLoaded(UUID draftId, UUID userId); void removeSession(UUID userId); diff --git a/Mage/src/main/java/mage/game/draft/Draft.java b/Mage/src/main/java/mage/game/draft/Draft.java index c935698047..11be28528b 100644 --- a/Mage/src/main/java/mage/game/draft/Draft.java +++ b/Mage/src/main/java/mage/game/draft/Draft.java @@ -30,6 +30,7 @@ public interface Draft extends MageItem, Serializable { int getBoosterNum(); int getCardNum(); boolean addPick(UUID playerId, UUID cardId, Set hiddenCards); + void setBoosterLoaded(UUID playerID); void start(); boolean isStarted(); void setStarted(); diff --git a/Mage/src/main/java/mage/game/draft/DraftImpl.java b/Mage/src/main/java/mage/game/draft/DraftImpl.java index 2cab35ab60..c1ee45112b 100644 --- a/Mage/src/main/java/mage/game/draft/DraftImpl.java +++ b/Mage/src/main/java/mage/game/draft/DraftImpl.java @@ -9,6 +9,11 @@ import mage.game.events.TableEvent.EventType; import mage.players.Player; import mage.players.PlayerList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + /** * * @author BetaSteward_at_googlemail.com @@ -25,12 +30,17 @@ public abstract class DraftImpl implements Draft { protected int boosterNum = 1; // starts with booster 1 protected int cardNum = 1; // starts with card number 1, increases by +1 after each picking protected TimingOption timing; + protected int boosterLoadingCounter; // number of times the boosters have been sent to players until all are confirmed to have received them + protected final int BOOSTER_LOADING_INTERVAL = 3; // interval in seconds protected boolean abort = false; protected boolean started = false; protected transient TableEventSource tableEventSource = new TableEventSource(); protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); + + protected ScheduledFuture boosterLoadingHandle; + protected final ScheduledExecutorService boosterLoadingExecutor = Executors.newSingleThreadScheduledExecutor(); public DraftImpl(DraftOptions options, List sets) { id = UUID.randomUUID(); @@ -209,9 +219,9 @@ public abstract class DraftImpl implements Draft { return false; } player.setPicking(); - player.getPlayer().pickCard(player.getBooster(), player.getDeck(), this); + player.setBoosterNotLoaded(); } - cardNum++; + setupBoosterLoadingHandle(); synchronized (this) { while (!donePicking()) { try { @@ -220,9 +230,42 @@ public abstract class DraftImpl implements Draft { } } } + cardNum++; return true; } - + + protected void setupBoosterLoadingHandle() { + cancelBoosterLoadingHandle(); + boosterLoadingCounter = 0; + boosterLoadingHandle = boosterLoadingExecutor.scheduleAtFixedRate(() -> { + try { + if (loadBoosters() == true) { + cancelBoosterLoadingHandle(); + } else { + boosterLoadingCounter++; + } + } catch (Exception ex) { + } + }, 0, BOOSTER_LOADING_INTERVAL, TimeUnit.SECONDS); + } + + protected void cancelBoosterLoadingHandle() { + if (boosterLoadingHandle != null) { + boosterLoadingHandle.cancel(true); + } + } + + protected boolean loadBoosters () { + boolean allBoostersLoaded = true; + for (DraftPlayer player : players.values()) { + if (player.isPicking() && !player.isBoosterLoaded()) { + allBoostersLoaded = false; + player.getPlayer().pickCard(player.getBooster(), player.getDeck(), this); + } + } + return allBoostersLoaded; + } + protected boolean donePicking() { if (isAbort()) { return true; @@ -263,7 +306,7 @@ public abstract class DraftImpl implements Draft { public void firePickCardEvent(UUID playerId) { DraftPlayer player = players.get(playerId); int cardNum = Math.min(15, this.cardNum); - int time = timing.getPickTimeout(cardNum); + int time = timing.getPickTimeout(cardNum) - boosterLoadingCounter * BOOSTER_LOADING_INTERVAL; playerQueryEventSource.pickCard(playerId, "Pick card", player.getBooster(), time); } @@ -284,6 +327,12 @@ public abstract class DraftImpl implements Draft { } return !player.isPicking(); } + + @Override + public void setBoosterLoaded(UUID playerId) { + DraftPlayer player = players.get(playerId); + player.setBoosterLoaded(); + } @Override public boolean isAbort() { diff --git a/Mage/src/main/java/mage/game/draft/DraftPlayer.java b/Mage/src/main/java/mage/game/draft/DraftPlayer.java index 134f21bbbd..a333d143a3 100644 --- a/Mage/src/main/java/mage/game/draft/DraftPlayer.java +++ b/Mage/src/main/java/mage/game/draft/DraftPlayer.java @@ -21,6 +21,7 @@ public class DraftPlayer { protected Deck deck; protected List booster; protected boolean picking; + protected boolean boosterLoaded; protected boolean joined = false; protected Set hiddenCards; @@ -97,5 +98,17 @@ public class DraftPlayer { public void setJoined() { this.joined = true; } + + public void setBoosterLoaded() { + boosterLoaded = true; + } + + public void setBoosterNotLoaded() { + boosterLoaded = false; + } + + public boolean isBoosterLoaded() { + return boosterLoaded; + } }