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 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 boolean nextTurn; // include creature that can only attack/block next turn
|
||||||
private final int timeOut;
|
private final int timeOut;
|
||||||
|
private final boolean canUseTimeout;
|
||||||
private List<CompletableFuture<Integer>> futures = new ArrayList<>();
|
private List<CompletableFuture<Integer>> futures = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,6 +99,7 @@ public class AiAttackController {
|
|||||||
this.nextTurn = nextTurn;
|
this.nextTurn = nextTurn;
|
||||||
refreshCombatants(defendingOpponent);
|
refreshCombatants(defendingOpponent);
|
||||||
this.timeOut = ai.getGame().getAITimeout();
|
this.timeOut = ai.getGame().getAITimeout();
|
||||||
|
this.canUseTimeout = ai.getGame().canUseTimeout();
|
||||||
} // overloaded constructor to evaluate attackers that should attack next turn
|
} // overloaded constructor to evaluate attackers that should attack next turn
|
||||||
|
|
||||||
public AiAttackController(final Player ai, Card attacker) {
|
public AiAttackController(final Player ai, Card attacker) {
|
||||||
@@ -112,6 +114,7 @@ public class AiAttackController {
|
|||||||
}
|
}
|
||||||
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
this.blockers = getPossibleBlockers(oppList, this.attackers, this.nextTurn);
|
||||||
this.timeOut = ai.getGame().getAITimeout();
|
this.timeOut = ai.getGame().getAITimeout();
|
||||||
|
this.canUseTimeout = ai.getGame().canUseTimeout();
|
||||||
} // overloaded constructor to evaluate single specified attacker
|
} // overloaded constructor to evaluate single specified attacker
|
||||||
|
|
||||||
private void refreshCombatants(GameEntity defender) {
|
private void refreshCombatants(GameEntity defender) {
|
||||||
@@ -967,10 +970,16 @@ public class AiAttackController {
|
|||||||
numForcedAttackers.incrementAndGet();
|
numForcedAttackers.incrementAndGet();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}).exceptionally(ex -> {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return 0;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
CompletableFuture<?>[] futuresArray = futures.toArray(new CompletableFuture<?>[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();
|
futures.clear();
|
||||||
if (attackersLeft.isEmpty()) {
|
if (attackersLeft.isEmpty()) {
|
||||||
return aiAggression;
|
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
|
// instead of computing all available concurrently just add a simple timeout depending on the user prefs
|
||||||
try {
|
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) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ public class GameCopier {
|
|||||||
private void copyGameState(Game newGame, Player aiPlayer) {
|
private void copyGameState(Game newGame, Player aiPlayer) {
|
||||||
newGame.EXPERIMENTAL_RESTORE_SNAPSHOT = origGame.EXPERIMENTAL_RESTORE_SNAPSHOT;
|
newGame.EXPERIMENTAL_RESTORE_SNAPSHOT = origGame.EXPERIMENTAL_RESTORE_SNAPSHOT;
|
||||||
newGame.AI_TIMEOUT = origGame.AI_TIMEOUT;
|
newGame.AI_TIMEOUT = origGame.AI_TIMEOUT;
|
||||||
|
newGame.AI_CAN_USE_TIMEOUT = origGame.AI_CAN_USE_TIMEOUT;
|
||||||
newGame.setAge(origGame.getAge());
|
newGame.setAge(origGame.getAge());
|
||||||
|
|
||||||
// TODO countersAddedThisTurn
|
// TODO countersAddedThisTurn
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ public class Game {
|
|||||||
|
|
||||||
private final Zone stackZone = new Zone(ZoneType.Stack, this);
|
private final Zone stackZone = new Zone(ZoneType.Stack, this);
|
||||||
public int AI_TIMEOUT = 5;
|
public int AI_TIMEOUT = 5;
|
||||||
|
public boolean AI_CAN_USE_TIMEOUT = true;
|
||||||
|
|
||||||
public boolean EXPERIMENTAL_RESTORE_SNAPSHOT = false;
|
public boolean EXPERIMENTAL_RESTORE_SNAPSHOT = false;
|
||||||
// While this is false here, its really set by the Match/Preferences
|
// While this is false here, its really set by the Match/Preferences
|
||||||
@@ -1359,4 +1360,7 @@ public class Game {
|
|||||||
public int getAITimeout() {
|
public int getAITimeout() {
|
||||||
return AI_TIMEOUT;
|
return AI_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
public boolean canUseTimeout() {
|
||||||
|
return AI_CAN_USE_TIMEOUT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ public class SimulationTest {
|
|||||||
game.setAge(GameStage.Play);
|
game.setAge(GameStage.Play);
|
||||||
game.EXPERIMENTAL_RESTORE_SNAPSHOT = false;
|
game.EXPERIMENTAL_RESTORE_SNAPSHOT = false;
|
||||||
game.AI_TIMEOUT = FModel.getPreferences().getPrefInt(FPref.MATCH_AI_TIMEOUT);
|
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;
|
return game;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,10 +244,12 @@ public class SettingsPage extends TabPage<SettingsScreen> {
|
|||||||
Forge.getLocalizer().getMessage("cbExperimentalRestore"),
|
Forge.getLocalizer().getMessage("cbExperimentalRestore"),
|
||||||
Forge.getLocalizer().getMessage("nlExperimentalRestore")),
|
Forge.getLocalizer().getMessage("nlExperimentalRestore")),
|
||||||
1);
|
1);
|
||||||
lstSettings.addItem(new CustomSelectSetting(FPref.MATCH_AI_TIMEOUT, Forge.getLocalizer().getMessage("cbAITimeout"),
|
if (!GuiBase.isAndroid() || GuiBase.getAndroidAPILevel() > 30) {
|
||||||
Forge.getLocalizer().getMessage("nlAITimeout"),
|
lstSettings.addItem(new CustomSelectSetting(FPref.MATCH_AI_TIMEOUT, Forge.getLocalizer().getMessage("cbAITimeout"),
|
||||||
Lists.newArrayList("5", "10", "60", "120", "240", "300", "600")),
|
Forge.getLocalizer().getMessage("nlAITimeout"),
|
||||||
1);
|
Lists.newArrayList("5", "10", "60", "120", "240", "300", "600")),
|
||||||
|
1);
|
||||||
|
}
|
||||||
lstSettings.addItem(new BooleanSetting(FPref.FILTERED_HANDS,
|
lstSettings.addItem(new BooleanSetting(FPref.FILTERED_HANDS,
|
||||||
Forge.getLocalizer().getMessage("cbFilteredHands"),
|
Forge.getLocalizer().getMessage("cbFilteredHands"),
|
||||||
Forge.getLocalizer().getMessage("nlFilteredHands")),
|
Forge.getLocalizer().getMessage("nlFilteredHands")),
|
||||||
|
|||||||
@@ -156,6 +156,9 @@ public class HostedMatch {
|
|||||||
game = match.createGame();
|
game = match.createGame();
|
||||||
game.EXPERIMENTAL_RESTORE_SNAPSHOT = FModel.getPreferences().getPrefBoolean(FPref.MATCH_EXPERIMENTAL_RESTORE);
|
game.EXPERIMENTAL_RESTORE_SNAPSHOT = FModel.getPreferences().getPrefBoolean(FPref.MATCH_EXPERIMENTAL_RESTORE);
|
||||||
game.AI_TIMEOUT = FModel.getPreferences().getPrefInt(FPref.MATCH_AI_TIMEOUT);
|
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));
|
StaticData.instance().setSourceImageForClone(FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user