Improve AI timeout detection (#8723)

This commit is contained in:
tool4ever
2025-09-16 20:04:00 +02:00
committed by GitHub
parent 6cf2f20cdc
commit 72139b523c
2 changed files with 13 additions and 1 deletions

View File

@@ -97,6 +97,7 @@ public class AiController {
private int lastAttackAggression; private int lastAttackAggression;
private boolean useLivingEnd; private boolean useLivingEnd;
private List<SpellAbility> skipped; private List<SpellAbility> skipped;
private boolean timeoutReached;
public AiController(final Player computerPlayer, final Game game0) { public AiController(final Player computerPlayer, final Game game0) {
player = computerPlayer; player = computerPlayer;
@@ -1664,6 +1665,9 @@ public class AiController {
Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); Sentry.captureMessage(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
} }
// in case of infinite loop reset below would not be reached
timeoutReached = false;
FutureTask<SpellAbility> future = new FutureTask<>(() -> { FutureTask<SpellAbility> future = new FutureTask<>(() -> {
//avoid ComputerUtil.aiLifeInDanger in loops as it slows down a lot.. call this outside loops will generally be fast... //avoid ComputerUtil.aiLifeInDanger in loops as it slows down a lot.. call this outside loops will generally be fast...
boolean isLifeInDanger = useLivingEnd && ComputerUtil.aiLifeInDanger(player, true, 0); boolean isLifeInDanger = useLivingEnd && ComputerUtil.aiLifeInDanger(player, true, 0);
@@ -1673,6 +1677,11 @@ public class AiController {
continue; continue;
} }
if (timeoutReached) {
timeoutReached = false;
break;
}
if (sa.getHostCard().hasKeyword(Keyword.STORM) if (sa.getHostCard().hasKeyword(Keyword.STORM)
&& sa.getApi() != ApiType.Counter // AI would suck at trying to deliberately proc a Storm counterspell && sa.getApi() != ApiType.Counter // AI would suck at trying to deliberately proc a Storm counterspell
&& player.getZone(ZoneType.Hand).contains( && player.getZone(ZoneType.Hand).contains(
@@ -1752,7 +1761,10 @@ public class AiController {
t.stop(); t.stop();
} catch (UnsupportedOperationException ex) { } catch (UnsupportedOperationException ex) {
// Android and Java 20 dropped support to stop so sadly thread will keep running // Android and Java 20 dropped support to stop so sadly thread will keep running
timeoutReached = true;
future.cancel(true); future.cancel(true);
// TODO wait a few more seconds to try and exit at a safe point before letting the engine continue
// TODO mark some as skipped to increase chance to find something playable next priority
} }
return null; return null;
} }

View File

@@ -1474,7 +1474,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
if (ZoneType.Exile.equals(destination) && sa.hasParam("WithCountersType")) { if (ZoneType.Exile.equals(destination) && sa.hasParam("WithCountersType")) {
CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); CounterType cType = CounterType.getType(sa.getParam("WithCountersType"));
int cAmount = AbilityUtils.calculateAmount(sa.getOriginalHost(), sa.getParamOrDefault("WithCountersAmount", "1"), sa); int cAmount = AbilityUtils.calculateAmount(source, sa.getParamOrDefault("WithCountersAmount", "1"), sa);
GameEntityCounterTable table = new GameEntityCounterTable(); GameEntityCounterTable table = new GameEntityCounterTable();
movedCard.addCounter(cType, cAmount, player, table); movedCard.addCounter(cType, cAmount, player, table);
table.replaceCounterEffect(game, sa, true); table.replaceCounterEffect(game, sa, true);