AI: added detail logs on too long thinks (show battlefield/stack stats, abilities activation chain on AI freezes, part of #10154, #13766)

This commit is contained in:
Oleg Agafonov 2025-07-05 20:33:25 +04:00
parent 4eb988de92
commit 6384816489

View file

@ -30,7 +30,10 @@ import mage.players.Player;
import mage.target.Target; import mage.target.Target;
import mage.target.TargetAmount; import mage.target.TargetAmount;
import mage.target.TargetCard; import mage.target.TargetCard;
import mage.util.*; import mage.util.CardUtil;
import mage.util.RandomUtil;
import mage.util.ThreadUtils;
import mage.util.XmageThreadFactory;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.*; import java.util.*;
@ -451,7 +454,14 @@ public class ComputerPlayer6 extends ComputerPlayer {
} catch (TimeoutException | InterruptedException e) { } catch (TimeoutException | InterruptedException e) {
// AI thinks too long // AI thinks too long
// how-to fix: look at stack info - it can contain bad ability with infinite choose dialog // how-to fix: look at stack info - it can contain bad ability with infinite choose dialog
logger.warn("AI player thinks too long - " + getName() + " - " + root.game); logger.warn("");
logger.warn("AI player thinks too long (report it to github):");
logger.warn(" - player: " + getName());
logger.warn(" - battlefield size: " + root.game.getBattlefield().getAllPermanents().size());
logger.warn(" - stack: " + root.game.getStack());
logger.warn(" - game: " + root.game);
printFreezeNode(root);
logger.warn("");
task.cancel(true); task.cancel(true);
} catch (ExecutionException e) { } catch (ExecutionException e) {
// game error // game error
@ -471,6 +481,30 @@ public class ComputerPlayer6 extends ComputerPlayer {
return 0; return 0;
} }
private void printFreezeNode(SimulationNode2 root) {
// print simple tree - there are possible multiple child nodes, but ignore it - same for abilities
List<String> chain = new ArrayList<>();
SimulationNode2 node = root;
while (node != null) {
if (node.abilities != null && !node.abilities.isEmpty()) {
Ability ability = node.abilities.get(0);
String sourceInfo = CardUtil.getSourceIdName(node.game, ability);
chain.add(String.format("%s: %s",
(sourceInfo.isEmpty() ? "unknown" : sourceInfo),
ability
));
}
node = node.children == null || node.children.isEmpty() ? null : node.children.get(0);
}
logger.warn("Possible freeze chain:");
if (root != null && chain.isEmpty()) {
logger.warn(" - unknown use case"); // maybe can't finish any calc, maybe related to target options, I don't know
}
chain.forEach(s -> {
logger.warn(" - " + s);
});
}
protected int simulatePriority(SimulationNode2 node, Game game, int depth, int alpha, int beta) { protected int simulatePriority(SimulationNode2 node, Game game, int depth, int alpha, int beta) {
if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS && Thread.currentThread().isInterrupted()) { if (!COMPUTER_DISABLE_TIMEOUT_IN_GAME_SIMULATIONS && Thread.currentThread().isInterrupted()) {
logger.debug("AI game sim interrupted by timeout"); logger.debug("AI game sim interrupted by timeout");