package it.paspiz85.nanobot.logic; import it.paspiz85.nanobot.exception.BotConfigurationException; import it.paspiz85.nanobot.exception.BotException; import it.paspiz85.nanobot.platform.Platform; import it.paspiz85.nanobot.util.Utils; import java.util.function.BooleanSupplier; import java.util.logging.Level; import java.util.logging.Logger; /** * Bot main logic that loop between training and attacking. * * @author paspiz85 * */ public final class Looper { public static Looper instance() { return Utils.singleton(Looper.class, () -> new Looper()); } private final Logger logger = Logger.getLogger(getClass().getName()); private final Platform platform = Platform.instance(); private boolean running; private boolean waitingForDcChecker; private boolean reloading; private Looper() { } public boolean isReloading() { return reloading; } public boolean isRunning() { return running; } boolean isWaitingForDcChecker() { return waitingForDcChecker; } private void loop(final Context context) throws InterruptedException, BotException { Exception botException; // throw in case of timeout try { while (true) { if (Thread.interrupted()) { throw new InterruptedException(getClass().getName() + " is interrupted"); } context.handle(); } } catch (final InterruptedException e) { // either by dc checker if (context.isDisconnected()) { logger.log(Level.INFO, "Interrupted by DisconnectChecker"); context.setDisconnected(false); context.setWaitDone(false); return; // or by user } else { logger.log(Level.INFO, "Interrupted by User"); throw e; } } catch (final Exception e) { logger.log(Level.SEVERE, e.getMessage(), e); botException = e; if (e instanceof BotConfigurationException) { throw e; } } final long timeout = 10 * 60 * 1000; // wait for dc checker to wake me up synchronized (context) { while (!context.isWaitDone()) { final long tBefore = System.currentTimeMillis(); logger.log(Level.INFO, "Waiting for dc checker to wake me up..."); this.waitingForDcChecker = true; // if user interrupts here while it is waiting, make sure // waitingForDcChecker is set to false context.wait(timeout); if (System.currentTimeMillis() - tBefore > timeout) { throw new BotException("Timed Out", botException); } } context.setWaitDone(false); } this.waitingForDcChecker = false; logger.log(Level.INFO, "Woken up. Launching again..."); } public void setReloading(final boolean reloading) { this.reloading = reloading; } public void start(final BooleanSupplier autoAdjustResolution, final Runnable updateUI) throws Exception { try { logger.log(Level.INFO, "Starting..."); platform.init(autoAdjustResolution); final Context context = new Context(); logger.log(Level.FINE, "Starting disconnect detector..."); final Thread dcThread = new Thread(new DisconnectChecker(this, context, Thread.currentThread()), "DisconnectCheckerThread"); dcThread.setDaemon(true); dcThread.start(); StateIdle.instance().setLooper(this); try { running = true; logger.log(Level.FINE, "looper running"); updateUI.run(); while (running) { context.setState(StateIdle.instance()); loop(context); } } finally { running = false; logger.log(Level.FINE, "looper stopped"); updateUI.run(); dcThread.interrupt(); this.waitingForDcChecker = false; context.setWaitDone(false); } } catch (final InterruptedException e) { logger.log(Level.FINE, e.getMessage()); throw e; } catch (final BotException e) { logger.log(Level.WARNING, e.getMessage()); throw e; } catch (final Exception e) { logger.log(Level.SEVERE, "Got exception: " + e.getMessage(), e); throw e; } } public void stop() { running = false; } }