From 8dbb6486381ec344dca1dfa87bd16b03afee36fa Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Thu, 14 Nov 2024 22:06:23 +0800 Subject: [PATCH] add user setting for AI Timeout --- forge-ai/src/main/java/forge/ai/AiAttackController.java | 2 +- forge-ai/src/main/java/forge/ai/AiController.java | 2 +- .../src/main/java/forge/ai/simulation/GameCopier.java | 1 + forge-game/src/main/java/forge/game/Game.java | 1 + forge-game/src/main/java/forge/game/player/Player.java | 7 +++++++ .../forge/screens/home/settings/CSubmenuPreferences.java | 9 +++++++++ .../forge/screens/home/settings/VSubmenuPreferences.java | 8 ++++++++ .../test/java/forge/ai/simulation/SimulationTest.java | 1 + .../src/forge/screens/settings/SettingsPage.java | 4 ++++ forge-gui/res/languages/de-DE.properties | 4 +++- forge-gui/res/languages/en-US.properties | 4 +++- forge-gui/res/languages/es-ES.properties | 4 +++- forge-gui/res/languages/fr-FR.properties | 4 +++- forge-gui/res/languages/it-IT.properties | 4 +++- forge-gui/res/languages/ja-JP.properties | 4 +++- forge-gui/res/languages/pt-BR.properties | 4 +++- forge-gui/res/languages/zh-CN.properties | 4 +++- .../src/main/java/forge/gamemodes/match/HostedMatch.java | 1 + .../forge/localinstance/properties/ForgePreferences.java | 1 + 19 files changed, 59 insertions(+), 10 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiAttackController.java b/forge-ai/src/main/java/forge/ai/AiAttackController.java index d4975a41bd9..215ee85373b 100644 --- a/forge-ai/src/main/java/forge/ai/AiAttackController.java +++ b/forge-ai/src/main/java/forge/ai/AiAttackController.java @@ -967,7 +967,7 @@ public class AiAttackController { })); } CompletableFuture[] futuresArray = futures.toArray(new CompletableFuture[0]); - CompletableFuture.allOf(futuresArray).completeOnTimeout(null, 5, TimeUnit.SECONDS).join(); + CompletableFuture.allOf(futuresArray).completeOnTimeout(null, ai.getTimeout(), TimeUnit.SECONDS).join(); futures.clear(); if (attackersLeft.isEmpty()) { return aiAggression; diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index cb8e12abeaa..682f95fc9cb 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -1667,7 +1667,7 @@ public class AiController { } //timeout 5 seconds? even the AI don't acquire all, there should be SA to cast if valid CompletableFuture[] futuresArray = futures.toArray(new CompletableFuture[0]); - CompletableFuture.allOf(futuresArray).completeOnTimeout(null, 5, TimeUnit.SECONDS).join(); + CompletableFuture.allOf(futuresArray).completeOnTimeout(null, player.getTimeout(), TimeUnit.SECONDS).join(); futures.clear(); if (!spells.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index 2629cf44d0b..592e73974a3 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -215,6 +215,7 @@ public class GameCopier { private void copyGameState(Game newGame, Player aiPlayer) { newGame.EXPERIMENTAL_RESTORE_SNAPSHOT = origGame.EXPERIMENTAL_RESTORE_SNAPSHOT; + newGame.AI_TIMEOUT = origGame.AI_TIMEOUT; newGame.setAge(origGame.getAge()); // TODO countersAddedThisTurn diff --git a/forge-game/src/main/java/forge/game/Game.java b/forge-game/src/main/java/forge/game/Game.java index ad3115a6802..578bc472d69 100644 --- a/forge-game/src/main/java/forge/game/Game.java +++ b/forge-game/src/main/java/forge/game/Game.java @@ -90,6 +90,7 @@ public class Game { private final GameLog gameLog = new GameLog(); private final Zone stackZone = new Zone(ZoneType.Stack, this); + public int AI_TIMEOUT = 5; public boolean EXPERIMENTAL_RESTORE_SNAPSHOT = false; // While this is false here, its really set by the Match/Preferences diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 9d690cf4a62..052701ce32e 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -131,6 +131,8 @@ public class Player extends GameEntity implements Comparable { private boolean revolt = false; private int descended = 0; + // AI Timeout + private int aiTimeout = 5; private List sacrificedThisTurn = new ArrayList<>(); private List discardedThisTurn = new ArrayList<>(); @@ -209,6 +211,7 @@ public class Player extends GameEntity implements Comparable { super(id0); game = game0; + aiTimeout = game.AI_TIMEOUT; for (final ZoneType z : Player.ALL_ZONES) { final PlayerZone toPut = z == ZoneType.Battlefield ? new PlayerZoneBattlefield(z, this) : new PlayerZone(z, this); zones.put(z, toPut); @@ -267,6 +270,10 @@ public class Player extends GameEntity implements Comparable { teamNumber = iTeam; } + public final int getTimeout() { + return aiTimeout; + } + public boolean isArchenemy() { return getZone(ZoneType.SchemeDeck).size() > 0; //Only the archenemy has schemes. } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java index 9f68326c97e..eb574fbe1aa 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java @@ -209,6 +209,7 @@ public enum CSubmenuPreferences implements ICDoc { initializeMulliganRuleComboBox(); initializeAiProfilesComboBox(); initializeAiSideboardingModeComboBox(); + initializeAiTimeoutComboBox(); initializeSoundSetsComboBox(); initializeMusicSetsComboBox(); initializeStackAdditionsComboBox(); @@ -415,6 +416,14 @@ public enum CSubmenuPreferences implements ICDoc { comboBox.addActionListener(actionEvent -> AiProfileUtil.setAiSideboardingMode(AiProfileUtil.AISideboardingMode.normalizedValueOf(comboBox.getSelectedItem()))); } + private void initializeAiTimeoutComboBox() { + final FPref userSetting = FPref.MATCH_AI_TIMEOUT; + final FComboBoxPanel panel = this.view.getAiTimeoutComboBox(); + final FComboBox comboBox = createComboBox(new String[] {"5", "10", "60", "120", "240", "300", "600"}, userSetting); + final String selectedItem = this.prefs.getPref(userSetting); + panel.setComboBox(comboBox, selectedItem); + } + private void initializeSoundSetsComboBox() { final FPref userSetting = FPref.UI_CURRENT_SOUND_SET; final FComboBoxPanel panel = this.view.getSoundSetsComboBoxPanel(); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java index 0eabbbe9f97..c00f04fba40 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java @@ -135,6 +135,7 @@ public enum VSubmenuPreferences implements IVSubmenu { private final FComboBoxPanel cbpMusicSets = new FComboBoxPanel<>(localizer.getMessage("cbpMusicSets")+":"); private final FComboBoxPanel cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":"); private final FComboBoxPanel cbpAiSideboardingMode = new FComboBoxPanel<>(localizer.getMessage("cbpAiSideboardingMode")+":"); + private final FComboBoxPanel cbpAiTimeout = new FComboBoxPanel<>(localizer.getMessage("cbAITimeout")+":"); private final FComboBoxPanel cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":"); private final FComboBoxPanel cbpLandPlayed = new FComboBoxPanel<>(localizer.getMessage("cbpLandPlayed")+":"); private final FComboBoxPanel cbpDisplayCurrentCardColors = new FComboBoxPanel<>(localizer.getMessage("cbpDisplayCurrentCardColors")+":"); @@ -245,6 +246,9 @@ public enum VSubmenuPreferences implements IVSubmenu { pnlPrefs.add(cbExperimentalRestore, titleConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlExperimentalRestore")), descriptionConstraints); + pnlPrefs.add(cbpAiTimeout, titleConstraints); + pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAITimeout")), descriptionConstraints); + pnlPrefs.add(cbFilteredHands, titleConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlFilteredHands")), descriptionConstraints); @@ -790,6 +794,10 @@ public enum VSubmenuPreferences implements IVSubmenu { return cbpAiSideboardingMode; } + public FComboBoxPanel getAiTimeoutComboBox() { + return cbpAiTimeout; + } + public FComboBoxPanel getCbpStackAdditionsComboBoxPanel() { return cbpStackAdditions; } diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/SimulationTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/SimulationTest.java index 8f8e41cc47a..a4d9ecf6b9f 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/SimulationTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/SimulationTest.java @@ -47,6 +47,7 @@ public class SimulationTest { Game game = new Game(players, rules, match); game.setAge(GameStage.Play); game.EXPERIMENTAL_RESTORE_SNAPSHOT = false; + game.AI_TIMEOUT = FModel.getPreferences().getPrefInt(FPref.MATCH_AI_TIMEOUT); return game; } diff --git a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java index 9e22c5a42da..ca1252e12c4 100644 --- a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java @@ -244,6 +244,10 @@ public class SettingsPage extends TabPage { Forge.getLocalizer().getMessage("cbExperimentalRestore"), Forge.getLocalizer().getMessage("nlExperimentalRestore")), 1); + lstSettings.addItem(new CustomSelectSetting(FPref.MATCH_AI_TIMEOUT, Forge.getLocalizer().getMessage("cbAITimeout"), + Forge.getLocalizer().getMessage("nlAITimeout"), + Lists.newArrayList("5", "10", "60", "120", "240", "300", "600")), + 1); lstSettings.addItem(new BooleanSetting(FPref.FILTERED_HANDS, Forge.getLocalizer().getMessage("cbFilteredHands"), Forge.getLocalizer().getMessage("nlFilteredHands")), diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 8c25397534c..b77ef340e59 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -3475,4 +3475,6 @@ lblDefaultCollection=Standardsammlungen lblSellable=Verkaufbar lblAutoSellable=Autoverkauf lblNonSellable=Kein Verkauf -lblPromptAutoSell=Aufforderung zum Autoverkauf \ No newline at end of file +lblPromptAutoSell=Aufforderung zum Autoverkauf +cbAITimeout=AI Time-out +nlAITimeout=Zeitüberschreitung in Sekunden für AI, wenn die zu spielenden Zauber berechnet und Angreifer deklariert werden \ No newline at end of file diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index b611eb84be0..9d611ff73ac 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -3194,4 +3194,6 @@ lblDefaultCollection=Default Collections lblSellable=Sellable lblAutoSellable=Auto-Sell lblNonSellable=No-Sell -lblPromptAutoSell=Prompt for auto sell \ No newline at end of file +lblPromptAutoSell=Prompt for auto sell +cbAITimeout=AI Timeout +nlAITimeout=Time-out in seconds for AI when computing for spells to play and declaring attackers \ No newline at end of file diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 9573eaa3344..81a99c21cbc 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -3482,4 +3482,6 @@ lblDefaultCollection=Colecciones predeterminadas lblSellable=Vendible lblAutoSellable=Venta automática lblNonSellable=Sin venta -lblPromptAutoSell=Solicitar venta automática \ No newline at end of file +lblPromptAutoSell=Solicitar venta automática +cbAITimeout=AI Se acabó el tiempo +nlAITimeout=Tiempo de espera en segundos para AI al calcular los hechizos a jugar y declarar atacantes \ No newline at end of file diff --git a/forge-gui/res/languages/fr-FR.properties b/forge-gui/res/languages/fr-FR.properties index 3a9b25b542c..f375ab44ef8 100644 --- a/forge-gui/res/languages/fr-FR.properties +++ b/forge-gui/res/languages/fr-FR.properties @@ -3483,4 +3483,6 @@ lblDefaultCollection=Collections par défaut lblSellable=Vendable lblAutoSellable=Vente automatique lblNonSellable=Pas de vente -lblPromptAutoSell=Invite pour la vente automatique \ No newline at end of file +lblPromptAutoSell=Invite pour la vente automatique +cbAITimeout=AI Temps mort +nlAITimeout=Délai d'attente en secondes pour AI lors du calcul des sorts à jouer et de la déclaration des attaquants \ No newline at end of file diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index ed47fe40c9e..5358f2c8e2c 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -3481,4 +3481,6 @@ lblDefaultCollection=Raccolte predefinite lblSellable=Vendibile lblAutoSellable=Vendita automatica lblNonSellable=Nessuna vendita -lblPromptAutoSell=Richiesta di vendita auto \ No newline at end of file +lblPromptAutoSell=Richiesta di vendita auto +cbAITimeout=AI Tempo scaduto +nlAITimeout=Timeout in secondi per AI durante il calcolo degli incantesimi da giocare e la dichiarazione degli attaccanti \ No newline at end of file diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index cd058a26fbd..4c16cee0701 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -3477,4 +3477,6 @@ lblDefaultCollection=デフォルトのコレクション lblSellable=販売可能 lblAutoSellable=自動販売 lblNonSellable=売りません -lblPromptAutoSell=自動車販売のプロンプト \ No newline at end of file +lblPromptAutoSell=自動車販売のプロンプト +cbAITimeout=AI タイムアウト +nlAITimeout=プレイする呪文を計算し、攻撃者を宣言するときの AI のタイムアウト (秒単位) \ No newline at end of file diff --git a/forge-gui/res/languages/pt-BR.properties b/forge-gui/res/languages/pt-BR.properties index 5793b6361cb..2e6b7175277 100644 --- a/forge-gui/res/languages/pt-BR.properties +++ b/forge-gui/res/languages/pt-BR.properties @@ -3567,4 +3567,6 @@ lblDefaultCollection=Coleções padrão lblSellable=Vendável lblAutoSellable=Venda automática lblNonSellable=Não vender -lblPromptAutoSell=Solicitação de venda automática \ No newline at end of file +lblPromptAutoSell=Solicitação de venda automática +cbAITimeout=AI Tempo esgotado +nlAITimeout=Tempo limite em segundos para AI ao calcular feitiços para jogar e declarar atacantes \ No newline at end of file diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 5ec33090c38..e2ccfe336f1 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -3468,4 +3468,6 @@ lblDefaultCollection=默认集合 lblSellable=可出售 lblAutoSellable=自动销售 lblNonSellable=不卖 -lblPromptAutoSell=提示汽车出售 \ No newline at end of file +lblPromptAutoSell=提示汽车出售 +cbAITimeout=AI 暂停 +nlAITimeout=计算要播放的咒语并宣布攻击者时,AI 超时(以秒为单位) \ No newline at end of file diff --git a/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java b/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java index 0b709967128..fc04e5afecb 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/HostedMatch.java @@ -155,6 +155,7 @@ public class HostedMatch { game = match.createGame(); game.EXPERIMENTAL_RESTORE_SNAPSHOT = FModel.getPreferences().getPrefBoolean(FPref.MATCH_EXPERIMENTAL_RESTORE); + game.AI_TIMEOUT = FModel.getPreferences().getPrefInt(FPref.MATCH_AI_TIMEOUT); StaticData.instance().setSourceImageForClone(FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE)); diff --git a/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java index 7898f206ff4..cd7c92340d5 100644 --- a/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/localinstance/properties/ForgePreferences.java @@ -205,6 +205,7 @@ public class ForgePreferences extends PreferencesStore { MATCH_AI_SIDEBOARDING_MODE("Human For AI"), MATCH_EXPERIMENTAL_RESTORE("false"), + MATCH_AI_TIMEOUT("5"), ENFORCE_DECK_LEGALITY ("true"), PERFORMANCE_MODE ("false"), FILTERED_HANDS ("false"),