mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
prevent crash on Android 11 and below
Completablefuture -> completeOnTimeout
This commit is contained in:
@@ -79,6 +79,7 @@ public class AiAttackController {
|
||||
private int aiAggression = 0; // how aggressive the ai is attack will be depending on circumstances
|
||||
private final boolean nextTurn; // include creature that can only attack/block next turn
|
||||
private final int timeOut;
|
||||
private final boolean canUseTimeout;
|
||||
private List<CompletableFuture<Integer>> futures = new ArrayList<>();
|
||||
|
||||
/**
|
||||
@@ -98,6 +99,7 @@ public class AiAttackController {
|
||||
this.nextTurn = nextTurn;
|
||||
refreshCombatants(defendingOpponent);
|
||||
this.timeOut = ai.getGame().getAITimeout();
|
||||
this.canUseTimeout = ai.getGame().canUseTimeout();
|
||||
} // overloaded constructor to evaluate attackers that should attack next turn
|
||||
|
||||
public AiAttackController(final Player ai, Card attacker) {
|
||||
@@ -112,6 +114,7 @@ public class AiAttackController {
|
||||
}
|
||||
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
||||
this.timeOut = ai.getGame().getAITimeout();
|
||||
this.canUseTimeout = ai.getGame().canUseTimeout();
|
||||
} // overloaded constructor to evaluate single specified attacker
|
||||
|
||||
private void refreshCombatants(GameEntity defender) {
|
||||
@@ -967,10 +970,16 @@ public class AiAttackController {
|
||||
numForcedAttackers.incrementAndGet();
|
||||
}
|
||||
return 0;
|
||||
}).exceptionally(ex -> {
|
||||
ex.printStackTrace();
|
||||
return 0;
|
||||
}));
|
||||
}
|
||||
CompletableFuture<?>[] futuresArray = futures.toArray(new CompletableFuture<?>[0]);
|
||||
CompletableFuture.allOf(futuresArray).completeOnTimeout(null, timeOut, TimeUnit.SECONDS).join();
|
||||
if (canUseTimeout)
|
||||
CompletableFuture.allOf(futuresArray).completeOnTimeout(null, timeOut, TimeUnit.SECONDS).join();
|
||||
else
|
||||
CompletableFuture.allOf(futuresArray).join();
|
||||
futures.clear();
|
||||
if (attackersLeft.isEmpty()) {
|
||||
return aiAggression;
|
||||
|
||||
@@ -1684,7 +1684,10 @@ public class AiController {
|
||||
|
||||
// instead of computing all available concurrently just add a simple timeout depending on the user prefs
|
||||
try {
|
||||
return future.completeOnTimeout(null, game.getAITimeout(), TimeUnit.SECONDS).get();
|
||||
if (game.AI_CAN_USE_TIMEOUT)
|
||||
return future.completeOnTimeout(null, game.getAITimeout(), TimeUnit.SECONDS).get();
|
||||
else
|
||||
return future.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -216,6 +216,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.AI_CAN_USE_TIMEOUT = origGame.AI_CAN_USE_TIMEOUT;
|
||||
newGame.setAge(origGame.getAge());
|
||||
|
||||
// TODO countersAddedThisTurn
|
||||
|
||||
@@ -90,6 +90,7 @@ public class Game {
|
||||
|
||||
private final Zone stackZone = new Zone(ZoneType.Stack, this);
|
||||
public int AI_TIMEOUT = 5;
|
||||
public boolean AI_CAN_USE_TIMEOUT = true;
|
||||
|
||||
public boolean EXPERIMENTAL_RESTORE_SNAPSHOT = false;
|
||||
// While this is false here, its really set by the Match/Preferences
|
||||
@@ -1359,4 +1360,7 @@ public class Game {
|
||||
public int getAITimeout() {
|
||||
return AI_TIMEOUT;
|
||||
}
|
||||
public boolean canUseTimeout() {
|
||||
return AI_CAN_USE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public class SimulationTest {
|
||||
game.setAge(GameStage.Play);
|
||||
game.EXPERIMENTAL_RESTORE_SNAPSHOT = false;
|
||||
game.AI_TIMEOUT = FModel.getPreferences().getPrefInt(FPref.MATCH_AI_TIMEOUT);
|
||||
game.AI_CAN_USE_TIMEOUT = true; //Only Android is restricted according to API Level
|
||||
|
||||
return game;
|
||||
}
|
||||
|
||||
@@ -244,10 +244,12 @@ public class SettingsPage extends TabPage<SettingsScreen> {
|
||||
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);
|
||||
if (!GuiBase.isAndroid() || GuiBase.getAndroidAPILevel() > 30) {
|
||||
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")),
|
||||
|
||||
@@ -156,6 +156,9 @@ 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);
|
||||
// Android API 31 and above can use completeOnTimeout -> CompletableFuture:
|
||||
//https://developer.android.com/reference/java/util/concurrent/CompletableFuture#completeOnTimeout(T,%20long,%20java.util.concurrent.TimeUnit)
|
||||
game.AI_CAN_USE_TIMEOUT = !GuiBase.isAndroid() || GuiBase.getAndroidAPILevel() > 30;
|
||||
|
||||
StaticData.instance().setSourceImageForClone(FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user