Package net.sf.robocode.ui.battle

Source Code of net.sf.robocode.ui.battle.AwtBattleAdaptor$TimerTask

/**
* Copyright (c) 2001-2014 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*/
package net.sf.robocode.ui.battle;


import net.sf.robocode.battle.IBattleManager;
import net.sf.robocode.battle.events.BattleEventDispatcher;
import net.sf.robocode.battle.snapshot.RobotSnapshot;
import net.sf.robocode.io.Logger;
import robocode.control.events.*;
import robocode.control.snapshot.IRobotSnapshot;
import robocode.control.snapshot.ITurnSnapshot;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicInteger;


/**
* @author Pavel Savara (original)
*/
public final class AwtBattleAdaptor {
  private boolean isEnabled;
  private final IBattleManager battleManager;
  private final BattleEventDispatcher battleEventDispatcher = new BattleEventDispatcher();
  private final BattleObserver observer;
  private final Timer timerTask;

  private final AtomicReference<ITurnSnapshot> snapshot;
  private final AtomicBoolean isRunning;
  private final AtomicBoolean isPaused;
  private final AtomicInteger majorEvent;
  private final AtomicInteger lastMajorEvent;
  private ITurnSnapshot lastSnapshot;
  private StringBuilder[] outCache;

  public AwtBattleAdaptor(IBattleManager battleManager, int maxFps, boolean skipSameFrames) {
    this.battleManager = battleManager;
    snapshot = new AtomicReference<ITurnSnapshot>(null);

    this.skipSameFrames = skipSameFrames;
    timerTask = new Timer(1000 / maxFps, new TimerTask());
    isRunning = new AtomicBoolean(false);
    isPaused = new AtomicBoolean(false);
    majorEvent = new AtomicInteger(0);
    lastMajorEvent = new AtomicInteger(0);

    observer = new BattleObserver();
  }

  protected void finalize() throws Throwable {
    try {
      timerTask.stop();
      battleManager.removeListener(observer);
    } finally {
      super.finalize();
    }
  }

  public void subscribe(boolean isEnabled) {
    if (this.isEnabled && !isEnabled) {
      battleManager.removeListener(observer);
      timerTask.stop();
      isEnabled = false;
    } else if (!this.isEnabled && isEnabled) {
      battleManager.addListener(observer);
      isEnabled = true;
    }
  }

  public synchronized void addListener(IBattleListener listener) {
    battleEventDispatcher.addListener(listener);
  }

  public synchronized void removeListener(IBattleListener listener) {
    battleEventDispatcher.removeListener(listener);
  }

  public ITurnSnapshot getLastSnapshot() {
    return lastSnapshot;
  }

  // this is always dispatched on AWT thread
  private void awtOnTurnEnded(boolean forceRepaint, boolean readoutText) {
    try {
      ITurnSnapshot current = snapshot.get();

      if (current == null) { // !isRunning.get() ||
        // paint logo
        lastSnapshot = null;
        battleEventDispatcher.onTurnEnded(new TurnEndedEvent(null));
      } else {
        if (lastSnapshot != current || !skipSameFrames || forceRepaint) {
          lastSnapshot = current;

          IRobotSnapshot[] robots = null;

          if (readoutText) {
            synchronized (snapshot) {
              robots = lastSnapshot.getRobots();

              for (int i = 0; i < robots.length; i++) {
                RobotSnapshot robot = (RobotSnapshot) robots[i];

                final StringBuilder cache = outCache[i];

                if (cache.length() > 0) {
                  robot.setOutputStreamSnapshot(cache.toString());
                  outCache[i].setLength(0);
                }
              }
            }
          }

          battleEventDispatcher.onTurnEnded(new TurnEndedEvent(lastSnapshot));

          if (readoutText) {
            for (IRobotSnapshot robot : robots) {
              ((RobotSnapshot) robot).setOutputStreamSnapshot(null);
            }
          }

          calculateFPS();
        }
      }
    } catch (Throwable t) {
      Logger.logError(t);
    }
  }

  public int getFPS() {
    return fps;
  }

  // FPS (frames per second) calculation
  private int fps;
  private long measuredFrameCounter;
  private long measuredFrameStartTime;
  private final boolean skipSameFrames;

  private void calculateFPS() {
    // Calculate the current frames per second (FPS)

    if (measuredFrameCounter++ == 0) {
      measuredFrameStartTime = System.nanoTime();
    }

    long deltaTime = System.nanoTime() - measuredFrameStartTime;

    if (deltaTime / 1000000000 >= 1) {
      fps = (int) (measuredFrameCounter * 1000000000L / deltaTime);
      measuredFrameCounter = 0;
    }
  }

  private class TimerTask implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      awtOnTurnEnded(false, true);
    }
  }


  // BattleObserver methods are always called by battle thread
  // but everything inside invokeLater {} block in on AWT thread
  private class BattleObserver extends BattleAdaptor {

    @Override
    public void onTurnEnded(final TurnEndedEvent event) {
      if (lastMajorEvent.get() == majorEvent.get()) {
        // snapshot is updated out of order, but always within the same major event
        snapshot.set(event.getTurnSnapshot());
      }

      final IRobotSnapshot[] robots = event.getTurnSnapshot().getRobots();

      for (int i = 0; i < robots.length; i++) {
        RobotSnapshot robot = (RobotSnapshot) robots[i];
        final int r = i;
        final String text = robot.getOutputStreamSnapshot();

        if (text != null && text.length() != 0) {
          robot.setOutputStreamSnapshot(null);
          EventQueue.invokeLater(new Runnable() {
            public void run() {
              synchronized (snapshot) {
                outCache[r].append(text);
              }
            }
          });
        }
      }
      if (isPaused.get()) {
        EventQueue.invokeLater(new Runnable() {
          public void run() {
            awtOnTurnEnded(false, true);
          }
        });
      }
    }

    @Override
    public void onRoundStarted(final RoundStartedEvent event) {
      if (lastMajorEvent.get() == majorEvent.get()) {
        snapshot.set(event.getStartSnapshot());
      }
      majorEvent.incrementAndGet();
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          awtOnTurnEnded(true, false);
          battleEventDispatcher.onRoundStarted(event);
          lastMajorEvent.incrementAndGet();
        }
      });
    }

    @Override
    public void onBattleStarted(final BattleStartedEvent event) {
      majorEvent.incrementAndGet();
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          isRunning.set(true);
          isPaused.set(false);
          synchronized (snapshot) {
            outCache = new StringBuilder[event.getRobotsCount()];
            for (int i = 0; i < event.getRobotsCount(); i++) {
              outCache[i] = new StringBuilder(1024);
            }
          }
          snapshot.set(null);
          battleEventDispatcher.onBattleStarted(event);
          lastMajorEvent.incrementAndGet();
          awtOnTurnEnded(true, false);
          timerTask.start();
        }
      });
    }

    @Override
    public void onBattleFinished(final BattleFinishedEvent event) {
      majorEvent.incrementAndGet();
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          isRunning.set(false);
          isPaused.set(false);
          timerTask.stop();
          // flush text cache
          awtOnTurnEnded(true, true);

          battleEventDispatcher.onBattleFinished(event);
          lastMajorEvent.incrementAndGet();
          snapshot.set(null);

          // paint logo
          awtOnTurnEnded(true, true);
        }
      });
    }

    @Override
    public void onBattleCompleted(final BattleCompletedEvent event) {
      majorEvent.incrementAndGet();
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          battleEventDispatcher.onBattleCompleted(event);
          lastMajorEvent.incrementAndGet();
          awtOnTurnEnded(true, true);
        }
      });
    }

    @Override
    public void onRoundEnded(final RoundEndedEvent event) {
      majorEvent.incrementAndGet();
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          battleEventDispatcher.onRoundEnded(event);
          lastMajorEvent.incrementAndGet();
          awtOnTurnEnded(true, true);
        }
      });
    }

    @Override
    public void onBattlePaused(final BattlePausedEvent event) {
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          timerTask.stop();
          battleEventDispatcher.onBattlePaused(event);
          awtOnTurnEnded(true, true);
          isPaused.set(true);
        }
      });
    }

    @Override
    public void onBattleResumed(final BattleResumedEvent event) {
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          battleEventDispatcher.onBattleResumed(event);
          if (isRunning.get()) {
            timerTask.start();
            isPaused.set(false);
          }
        }
      });
    }

    @Override
    public void onBattleMessage(final BattleMessageEvent event) {
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          battleEventDispatcher.onBattleMessage(event);
        }
      });
    }

    @Override
    public void onBattleError(final BattleErrorEvent event) {
      EventQueue.invokeLater(new Runnable() {
        public void run() {
          battleEventDispatcher.onBattleError(event);
        }
      });
    }
  }
}
TOP

Related Classes of net.sf.robocode.ui.battle.AwtBattleAdaptor$TimerTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.