package controller.net; import controller.EventHandler; import controller.action.ActionBoard; import data.GameControlReturnData; import data.PlayerInfo; import data.Rules; /** * @author Marcel Steinbeck, Michel Bartsch * * You can ask this class about the robots online-status. * * This class is a sigleton! */ public class RobotWatcher { /** The instance of the singleton. */ private static RobotWatcher instance = new RobotWatcher(); /** A timestamp when the last reply from each robot was received. */ private long [][] robotsLastAnswer = Rules.league.isCoachAvailable ? new long[2][Rules.league.teamSize+1] : new long[2][Rules.league.teamSize]; /** Last message reeived from each robot. * Look at GameControlReturnData for information about messages */ private int [][] robotsLastMessage = Rules.league.isCoachAvailable ? new int[2][Rules.league.teamSize+1] : new int[2][Rules.league.teamSize]; /** The calculated information about the online-status. */ private RobotOnlineStatus [][] status = Rules.league.isCoachAvailable ? new RobotOnlineStatus[2][Rules.league.teamSize+1] : new RobotOnlineStatus[2][Rules.league.teamSize]; /** What the constants name says. */ private final static int MILLIS_UNTIL_ROBOT_IS_OFFLINE = 4*1000; private final static int MILLIS_UNTIL_ROBOT_HAS_HIGH_LATANCY = 2*1000; /** * Creates a new RobotWatcher. */ private RobotWatcher() { for (int i = 0; i < 2; i++) { for (int j = 0; j < Rules.league.teamSize; j++) { robotsLastMessage[i][j] = PlayerInfo.PENALTY_NONE; status[i][j] = RobotOnlineStatus.UNKNOWN; } if (Rules.league.isCoachAvailable) { status[i][Rules.league.teamSize] = RobotOnlineStatus.UNKNOWN; } } } /** * Recieves robot´s answers to update corresponding timestamps and fire * actions caused manual on the robot. * * @param gameControlReturnData The robot`s answer. */ public static synchronized void update(GameControlReturnData gameControlReturnData) { int team, number; if (gameControlReturnData.team == EventHandler.getInstance().data.team[0].teamNumber) { team = 0; } else if (gameControlReturnData.team == EventHandler.getInstance().data.team[1].teamNumber) { team = 1; } else { return; } number = gameControlReturnData.player; if (number <= 0 || number > Rules.league.teamSize) { return; } instance.robotsLastAnswer[team][number-1] = System.currentTimeMillis(); if (instance.robotsLastMessage[team][number-1] != gameControlReturnData.message) { instance.robotsLastMessage[team][number-1] = gameControlReturnData.message; if ((gameControlReturnData.message == GameControlReturnData.GAMECONTROLLER_RETURN_MSG_MAN_PENALISE) && (EventHandler.getInstance().data.team[team].player[number-1].penalty == PlayerInfo.PENALTY_NONE)) { ActionBoard.manualPen[team][number-1].actionPerformed(null); } else if ((gameControlReturnData.message == GameControlReturnData.GAMECONTROLLER_RETURN_MSG_MAN_UNPENALISE) && (EventHandler.getInstance().data.team[team].player[number-1].penalty != PlayerInfo.PENALTY_NONE)) { ActionBoard.manualUnpen[team][number-1].actionPerformed(null); } } } /** * Calculates new online-status for each robot. * * @return The updated online-status of each robot. */ public static synchronized RobotOnlineStatus[][] updateRobotOnlineStatus() { long currentTime = System.currentTimeMillis(); int robotsOffline; for (int i=0; i<2; i++) { robotsOffline = 0; for (int j=0; j < instance.status[i].length; j++) { if (currentTime - instance.robotsLastAnswer[i][j] > MILLIS_UNTIL_ROBOT_IS_OFFLINE) { instance.status[i][j] = RobotOnlineStatus.OFFLINE; if (++robotsOffline >= Rules.league.teamSize + (Rules.league.isCoachAvailable ? 1 : 0)) { for (int k=0; k < Rules.league.teamSize; k++) { instance.status[i][k] = RobotOnlineStatus.UNKNOWN; } if (Rules.league.isCoachAvailable) { instance.status[i][Rules.league.teamSize] = RobotOnlineStatus.UNKNOWN; } } } else if (currentTime - instance.robotsLastAnswer[i][j] > MILLIS_UNTIL_ROBOT_HAS_HIGH_LATANCY) { instance.status[i][j] = RobotOnlineStatus.HIGH_LATENCY; } else { instance.status[i][j] = RobotOnlineStatus.ONLINE; } } } return instance.status; } public static synchronized void updateCoach(byte team) { instance.robotsLastAnswer[team][Rules.league.teamSize] = System.currentTimeMillis(); } }