prevent crash on Android 11 and below

Completablefuture -> completeOnTimeout
This commit is contained in:
Anthony Calosa
2024-12-02 09:44:29 +08:00
parent 23d0868e0a
commit e8a6d4ce92
7 changed files with 29 additions and 6 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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")),

View File

@@ -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));