diff --git a/GameController.iml b/GameController.iml index cec46493..6e337433 100644 --- a/GameController.iml +++ b/GameController.iml @@ -8,7 +8,6 @@ - diff --git a/examples/c/RoboCupGameControlData.h b/examples/c/RoboCupGameControlData.h index 5e874719..489cba89 100644 --- a/examples/c/RoboCupGameControlData.h +++ b/examples/c/RoboCupGameControlData.h @@ -7,7 +7,7 @@ #define GAMECONTROLLER_RETURN_PORT 3939 #define GAMECONTROLLER_STRUCT_HEADER "RGme" -#define GAMECONTROLLER_STRUCT_VERSION 15 +#define GAMECONTROLLER_STRUCT_VERSION 16 #define MAX_NUM_PLAYERS 20 @@ -26,8 +26,8 @@ #define COMPETITION_PHASE_ROUNDROBIN 0 #define COMPETITION_PHASE_PLAYOFF 1 -#define COMPETITION_TYPE_NORMAL 0 -#define COMPETITION_TYPE_DYNAMIC_BALL_HANDLING 1 +#define COMPETITION_TYPE_NORMAL 0 +#define COMPETITION_TYPE_SHARED_AUTONOMY 1 #define GAME_PHASE_NORMAL 0 #define GAME_PHASE_PENALTYSHOOT 1 @@ -59,6 +59,7 @@ #define PENALTY_SPL_LOCAL_GAME_STUCK 8 #define PENALTY_SPL_ILLEGAL_POSITION_IN_SET 9 #define PENALTY_SPL_PLAYER_STANCE 10 +#define PENALTY_SPL_ILLEGAL_MOTION_IN_INITIAL 11 #define PENALTY_SUBSTITUTE 14 #define PENALTY_MANUAL 15 @@ -89,7 +90,7 @@ struct RoboCupGameControlData uint8_t packetNumber; // number incremented with each packet sent (with wraparound) uint8_t playersPerTeam; // the number of players on a team uint8_t competitionPhase; // phase of the competition (COMPETITION_PHASE_ROUNDROBIN, COMPETITION_PHASE_PLAYOFF) - uint8_t competitionType; // type of the competition (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_DYNAMIC_BALL_HANDLING) + uint8_t competitionType; // type of the competition (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_SHARED_AUTONOMY) uint8_t gamePhase; // phase of the game (GAME_PHASE_NORMAL, GAME_PHASE_PENALTYSHOOT, etc) uint8_t state; // state of the game (STATE_READY, STATE_PLAYING, etc) uint8_t setPlay; // active set play (SET_PLAY_NONE, SET_PLAY_GOAL_KICK, etc) diff --git a/examples/c/VisualRefereeChallenge.h b/examples/c/VisualRefereeChallenge.h deleted file mode 100644 index 230b3cc9..00000000 --- a/examples/c/VisualRefereeChallenge.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef VISUALREFEREECHALLENGE_H -#define VISUALREFEREECHALLENGE_H - -/* - * In the In-game Visual Referee Challenge, robots must communicate a detected gesture to the - * GameController. This is done via the same channel on which RoboCupGameControlReturnData is sent. - * Specifically, messages must be sent via UDP unicast directly to the GameController host on - * the port GAMECONTROLLER_RETURN_PORT (as given in RoboCupGameControlData.h) and using the - * structure RoboCupGameControlReturnData with the following properties: - * - header, playerNum and teamNum set as usual - * - version set to GAMECONTROLLER_RETURN_STRUCT_VRC_VERSION (defined below) - * - fallen set to one of the GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_* constants (defined below) - * - ballAge set to the time (in seconds) since the corresponding whistle was heard - * The other fields (pose and ball) are ignored. - */ - -#define GAMECONTROLLER_RETURN_STRUCT_VRC_VERSION 255 - -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_KICK_IN_BLUE_TEAM 1 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_KICK_IN_RED_TEAM 2 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_GOAL_KICK_BLUE_TEAM 3 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_GOAL_KICK_RED_TEAM 4 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_CORNER_KICK_BLUE_TEAM 5 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_CORNER_KICK_RED_TEAM 6 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_GOAL_BLUE_TEAM 7 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_GOAL_RED_TEAM 8 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_PUSHING_FREE_KICK_BLUE_TEAM 9 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_PUSHING_FREE_KICK_RED_TEAM 10 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_FULL_TIME 11 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_SUBSTITUTION_BLUE_TEAM 12 -#define GAMECONTROLLER_RETURN_STRUCT_VRC_GESTURE_SUBSTITUTION_RED_TEAM 13 - -#endif // VISUALREFEREECHALLENGE_H diff --git a/examples/python/robocup_game_control_data.py b/examples/python/robocup_game_control_data.py index 3d7bce7b..45ae53e4 100644 --- a/examples/python/robocup_game_control_data.py +++ b/examples/python/robocup_game_control_data.py @@ -32,7 +32,7 @@ GAMECONTROLLER_RETURN_PORT = 3939 GAMECONTROLLER_STRUCT_HEADER = b'RGme' -GAMECONTROLLER_STRUCT_VERSION = 15 +GAMECONTROLLER_STRUCT_VERSION = 16 MAX_NUM_PLAYERS = 20 @@ -52,7 +52,7 @@ COMPETITION_PHASE_PLAYOFF = 1 COMPETITION_TYPE_NORMAL = 0 -COMPETITION_TYPE_DYNAMIC_BALL_HANDLING = 1 +COMPETITION_TYPE_SHARED_AUTONOMY = 1 GAME_PHASE_NORMAL = 0 GAME_PHASE_PENALTYSHOOT = 1 @@ -84,6 +84,7 @@ PENALTY_SPL_LOCAL_GAME_STUCK = 8 PENALTY_SPL_ILLEGAL_POSITION_IN_SET = 9 PENALTY_SPL_PLAYER_STANCE = 10 +PENALTY_SPL_ILLEGAL_MOTION_IN_INITIAL = 11 PENALTY_SUBSTITUTE = 14 PENALTY_MANUAL = 15 @@ -111,7 +112,7 @@ 'packetNumber' / Byte, # number incremented with each packet sent (with wraparound) # noqa: E501 'playersPerTeam' / Byte, # the number of players on a team 'competitionPhase' / Byte, # phase of the competition (COMPETITION_PHASE_ROUNDROBIN, COMPETITION_PHASE_PLAYOFF) # noqa: E501 - 'competitionType' / Byte, # type of the competition (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_DYNAMIC_BALL_HANDLING) # noqa: E501 + 'competitionType' / Byte, # type of the competition (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_SHARED_AUTONOMY) # noqa: E501 'gamePhase' / Byte, # phase of the game (GAME_PHASE_NORMAL, GAME_PHASE_PENALTYSHOOT, etc) # noqa: E501 'state' / Byte, # state of the game (STATE_READY, STATE_PLAYING, etc) # noqa: E501 'setPlay' / Byte, # active set play (SET_PLAY_NONE, SET_PLAY_GOAL_KICK, etc) # noqa: E501 diff --git a/src/common/Log.java b/src/common/Log.java index f6c8c129..4aef9298 100644 --- a/src/common/Log.java +++ b/src/common/Log.java @@ -1,13 +1,9 @@ package common; -import data.AdvancedData; - import java.io.FileWriter; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.LinkedList; /** @@ -15,8 +11,6 @@ * * This class should be used to log into a log file. A new file will be created * every time the GameController is started. - * At the end of an actions the Log should be used to add a state into the - * timeline, that is provided by this class too. * * This class is a singleton! */ @@ -25,16 +19,10 @@ public class Log /** The instance of the singleton. */ private static final Log instance = new Log(); - /** The file to write into. */ - private FileWriter file; /** The error-file to write into. */ private FileWriter errorFile; /** The file to write into. */ private final String errorPath = "error.txt"; - /** The timeline. */ - private final LinkedList states = new LinkedList<>(); - /** If != null, the next log entry will use this message. */ - private String message = null; /** The format of timestamps. */ public static final SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyy.M.dd-kk.mm.ss"); @@ -44,195 +32,6 @@ public class Log */ private Log() {} - /** - * Must be called once at the very beginning to allow Log to work. - * - * @param path The path where the log-file should be created. - */ - public synchronized static void init(String path) - { - if (instance.file != null) { - throw new IllegalStateException("logger already initialized"); - } - try{ - instance.file = new FileWriter(path); - } catch (IOException e) { - error("cannot write to logfile "+path); - } - - // Write version number if application is GameController - try { - toFile((String)Class.forName("controller.GameController").getField("version").get(null)); - } catch (ClassNotFoundException - | NoSuchFieldException - | SecurityException - | IllegalArgumentException - | IllegalAccessException ex) { - } - } - - /** - * Simply writes a line, beginning with a timestamp, in the file. - * May be used to log something that should not be in the timeline. - * - * @param s The string to be written in the file. - */ - public static void toFile(String s) - { - try{ - instance.file.write(timestampFormat.format(new Date(System.currentTimeMillis()))+": "+s+"\n"); - instance.file.flush(); - } catch (IOException e) { - error("cannot write to logfile!"); - } - } - - /** - * Specify the message that will be used for the next log entry. It will - * replace the one that is specified during that log entry. This allows - * to replace rather generic messages by more specific ones if an - * action calls another action to perform its task. - * @param message The message that will be used for the next log entry. - */ - public static void setNextMessage(String message) - { - instance.message = message; - } - - /** - * Puts a copy of the given data into the timeline, attaching the message - * to it and writing it to the file using toFile method. - * This should be used at the very end of all actions that are meant to be - * in the timeline. - * - * @param data The current data that have just been changed and should - * go into the timeline. - * @param message A message describing what happened to the data. - */ - public static void state(AdvancedData data, String message) - { - AdvancedData state = (AdvancedData) data.clone(); - if (!instance.states.isEmpty()) { - state.timeSinceCurrentGameStateBegan = state.getTime() - instance.states.getLast().whenCurrentGameStateBegan; - state.timeSinceCurrentSetPlayBegan = state.getTime() - instance.states.getLast().whenCurrentSetPlayBegan; - } - if (instance.message == null) { - state.message = message; - } else { - state.message = instance.message; - toFile(state.message); - instance.message = null; - } - instance.states.add(state); - toFile(message); - } - - /** - * Changes the data used in all actions via the EventHandler to a data from - * the timeline. So this is the undo function. - * If a game state change is undone, the time when it was left is restored. - * Thereby, there whole remaining log is moved into the new timeframe. - * - * @param data The current data. Only used to determine whether - * a change of game state is reverted. - * @param states How far you want to go back, how many states. - * - * @return The message that was attached to the data you went back to. - */ - public static String goBack(AdvancedData data, int states) - { - if (states >= instance.states.size()) { - states = instance.states.size()-1; - } - long timeSinceCurrentGameStateBegan = 0; - long nextTimeSinceCurrentGameStateBegan = 0; - long timeSinceCurrentSetPlayBegan = 0; - - boolean gameStateChanged = false; - byte nextGameState = data.gameState; - for (int i=0; i eventHandlerClass = Class.forName("controller.EventHandler"); - eventHandlerClass.getField("data").set(eventHandlerClass.getMethod("getInstance").invoke(null), state); - } catch (ClassNotFoundException - | NoSuchFieldException - | SecurityException - | IllegalArgumentException - | IllegalAccessException - | NoSuchMethodException - | InvocationTargetException ex) { - } - return state.message; - } - - /** - * Gives you the messages attached to the latest data in the timeline. - * - * @param states Of how many datas back you want to have the messages. - * - * @return The messages attached to the data, beginning with the latest. - * The arrays length equals the states parameter. - */ - public static String[] getLast(int states) - { - String[] out = new String[states]; - for (int i=0; i= 0) { - out[i] = instance.states.get(instance.states.size()-1-i).message; - } else { - out[i] = ""; - } - } - return out; - } - /** * Writes a line, beginning with a timestamp, in the error-file and creates * a new one, if it does not yet exist. @@ -244,7 +43,7 @@ public static String[] getLast(int states) public static void error(String s) { System.err.println(s); - try{ + try { if (instance.errorFile == null) { instance.errorFile = new FileWriter(instance.errorPath); } @@ -264,6 +63,5 @@ public static void close() throws IOException { if (instance.errorFile != null) { instance.errorFile.close(); } - instance.file.close(); } } diff --git a/src/data/AdvancedData.java b/src/data/AdvancedData.java deleted file mode 100644 index 83189623..00000000 --- a/src/data/AdvancedData.java +++ /dev/null @@ -1,522 +0,0 @@ -package data; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Arrays; - -/** - * This class extends the GameControlData that is send to the robots. It - * contains all the additional information the GameController needs to represent - * a state of the game, for example time in millis. - * - * There are no synchronized get and set methods because in this architecture - * only actions in their perform method are allowed to write into this and they - * are all in the same thread. Look in the EventHandler for more information. - * - * @author Michel Bartsch - * @author Dennis Schürholz (bhuman@dennisschuerholz.de) - */ -public class AdvancedData extends GameControlData implements Cloneable { - - private static final long serialVersionUID = 2720243434306304319L; - - /** - * This message is set when the data is put into the timeline - */ - public String message = ""; - - /** - * How much time summed up before the current state? (ms) - */ - public long timeBeforeCurrentGameState; - - /** - * How much time summed up before the current stoppage of play? (ms) - */ - public long timeBeforeStoppageOfPlay; - - /** - * When was switched to the current state? (ms) - */ - public long whenCurrentGameStateBegan; - - /** - * When was the current set play activated? (ms) - */ - public long whenCurrentSetPlayBegan; - - /** - * How long ago started the current game state? (ms) Only set when written - * to log! - */ - public long timeSinceCurrentGameStateBegan; - - /** - * How long ago started the current set play? (ms) Only set when written - * to log and there is an active set play! - */ - public long timeSinceCurrentSetPlayBegan; - - /** - * When was each player penalized last (ms, 0 = never)? - */ - public final long[][] whenPenalized = new long[2][Rules.league.teamSize]; - - /** - * How often was each team penalized? - */ - public final int[] penaltyCount = new int[2]; - - /** - * How often was each team penalized at before the robot got penalized? - */ - public final int[][] robotPenaltyCount = new int[2][Rules.league.teamSize]; - - /** - * How many hardware penalties can each robot get until it is ejected? - */ - public final int[][] robotHardwarePenaltyBudget = new int[2][Rules.league.teamSize]; - - /** - * Which players are already ejected? - */ - public final boolean[][] ejected = new boolean[2][Rules.league.teamSize]; - - /** - * Did the team send too many messages so that its score is set to 0 forever? - */ - public final boolean[] sentIllegalMessages = {false, false}; - - /** - * If true, the referee set a timeout - */ - public final boolean refereeTimeout = false; - - /** - * If true, this team is currently taking a timeOut, 0:left side, 1:right - * side. - */ - public final boolean[] timeOutActive = {false, false}; - - /** - * TimeOut counters for each team, 0:left side, 1:right side. - */ - public boolean[] timeOutTaken = {false, false}; - - /** - * If true, left side has the kickoff. - */ - public boolean leftSideKickoff = true; - - /** - * If true, the testmode has been activated. - */ - public boolean testmode = false; - - /** - * If true, the clock has manually been paused in the testmode. - */ - public final boolean manPause = false; - - /** - * If true, the clock has manually been started in the testmode. - */ - public final boolean manPlay = false; - - /** - * When was the last manual intervention to the clock? - */ - public long manWhenClockChanged; - - /** - * Time offset resulting from manually stopping the clock. - */ - public long manTimeOffset; - - /** - * Time offset resulting from starting the clock when it should be stopped. - */ - public long manRemainingGameTimeOffset; - - /** - * Used to back up the game phase during a timeout. - */ - public final byte previousGamePhase = GAME_PHASE_NORMAL; - - /** - * The kicking team before the last goal. - */ - public final byte kickingTeamBeforeGoal = 0; - - public static final byte KICKOFF_HALF = 0; - public static final byte KICKOFF_TIMEOUT = 1; - public static final byte KICKOFF_GAMESTUCK = 2; - public static final byte KICKOFF_PENALTYSHOOT = 3; - public static final byte KICKOFF_GOAL = 4; - public byte kickOffReason = KICKOFF_HALF; - - /** - * Saves the selected penalty taker and keeper of both teams. First index is - * team-number, second index is taker (0) or keeper (1) - */ - public int[][] penaltyShootOutPlayers = new int[][]{{-1, -1}, {-1, -1}}; - - /** - * Creates a new AdvancedData. - */ - public AdvancedData() { - if (Rules.league.startWithPenalty) { - gamePhase = GAME_PHASE_PENALTYSHOOT; - kickOffReason = KICKOFF_PENALTYSHOOT; - } - for (int i = 0; i < 2; i++) { - for (int j = 0; j < team[i].player.length; j++) { - if (j >= Rules.league.robotsPlaying) { - team[i].player[j].penalty = PlayerInfo.PENALTY_SUBSTITUTE; - } - if (j < robotHardwarePenaltyBudget[i].length) { - robotHardwarePenaltyBudget[i][j] = Rules.league.allowedHardwarePenaltiesPerHalf; - } - } - } - } - - /** - * Generically clone this object. Everything referenced must be - * Serializable. - * - * @return A deep copy of this object. - */ - public Object clone() { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - new ObjectOutputStream(out).writeObject(this); - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - return new ObjectInputStream(in).readObject(); - } catch (ClassNotFoundException | IOException e) { - System.out.println(e.getClass().getName() + ": " + e.getMessage()); - } - return null; // Should never be reached - } - - /** - * Returns the side on which a team plays. The team should be playing via - * this GameController. - * - * @param teamNumber The unique teamNumber. - * - * @return The side of the team, 0:left side, 1:right side. - */ - public int getSide(short teamNumber) { - return teamNumber == team[0].teamNumber ? 0 : 1; - } - - /** - * Returns the current time. Can be stopped in test mode. - * - * @return The current time in ms. May become incompatible to the time - * delivered by System.currentTimeMillis(). - */ - public long getTime() { - return manPause ? manWhenClockChanged : System.currentTimeMillis() + manTimeOffset; - } - - /** - * Returns the number of seconds since a certain timestamp. - * - * @param millis The timestamp in ms. - * @return The number of seconds since the timestamp. - */ - public int getSecondsSince(long millis) { - return millis == 0 ? 100000 : (int) (getTime() - millis) / 1000; - } - - /** - * The number of seconds until a certain duration is over. The time already - * passed is specified as a timestamp when it began. - * - * @param millis The timestamp in ms. - * @param durationInSeconds The full duration in s. - * @return The number of seconds that still remain from the duration. Can be - * negative. - */ - public int getRemainingSeconds(long millis, int durationInSeconds) { - return durationInSeconds - getSecondsSince(millis); - } - - /** - * Update all durations in the GameControlData packet. - * - * @param real If true, secsRemaining and secondaryTime will contain the real times - * instead of the ones that are sent to the robots (to hide the fact that the playing - * state might have started). - */ - public void updateTimes(boolean real) { - secsRemaining = (short) getRemainingGameTime(real); - Integer subT = getSecondaryTime(real); - - if (subT == null) { - secondaryTime = 0; - } else { - secondaryTime = (short) (int) subT; - } - for (int side = 0; side < team.length; ++side) { - for (int number = 0; number < team[side].player.length; ++number) { - PlayerInfo player = team[side].player[number]; - player.secsTillUnpenalised = player.penalty == PlayerInfo.PENALTY_NONE - ? 0 : (byte) (number < ejected[side].length && ejected[side][number] ? 255 : Math.min(255, getRemainingPenaltyTime(side, number, real))); - } - } - } - - /** - * Add the time passed in the current game state to the time that already - * passed before. Is usually called during changes of the game state. - */ - public void addTimeInCurrentState() { - timeBeforeCurrentGameState += getTime() - whenCurrentGameStateBegan; - } - - /** - * Shifts the start times of penalties by the duration of the state - * (or the already elapsed penalty time, whichever is shorter) into the future. - * This is used to implement the rule that the penalty countdown pauses in Set. - */ - public void addTimeInCurrentStateToPenalties() { - for (int side = 0; side < team.length; side++) { - for (int number = 0; number < whenPenalized[side].length; number++) { - if (team[side].player[number].penalty != PlayerInfo.PENALTY_NONE && whenPenalized[side][number] != 0) { - whenPenalized[side][number] += getTime() - Math.max(whenCurrentGameStateBegan, whenPenalized[side][number]); - } - } - } - } - - /** - * Calculates the remaining game time in the current phase of the game. This - * is what the primary clock will show. - * - * @param real If true, the real time will be returned. If false, the first - * number of seconds in the playing state or after a goal will not be updated. - * @return The remaining number of seconds. - */ - public int getRemainingGameTime(boolean real) { - int duration = gamePhase == GAME_PHASE_TIMEOUT - ? (previousGamePhase == GAME_PHASE_NORMAL ? Rules.league.halfTime - : previousGamePhase == GAME_PHASE_OVERTIME ? Rules.league.overtimeTime - : Rules.league.penaltyShotTime) - : (gamePhase == GAME_PHASE_NORMAL) ? Rules.league.halfTime - : gamePhase == GAME_PHASE_OVERTIME ? Rules.league.overtimeTime - : Math.max(team[0].penaltyShot, team[1].penaltyShot) > Rules.league.numberOfPenaltyShots - ? Rules.league.penaltyShotTimeSuddenDeath - : Rules.league.penaltyShotTime; - int timePlayed = gameState == STATE_INITIAL // during timeouts - || ((gameState == STATE_READY || gameState == STATE_SET) - && (competitionPhase == COMPETITION_PHASE_PLAYOFF && Rules.league.playOffTimeStop - && (real || gamePhase != GAME_PHASE_NORMAL || gameState != STATE_READY || kickOffReason != KICKOFF_GOAL - || getSecondsSince(whenCurrentGameStateBegan) >= Rules.league.delayedSwitchAfterGoal) - || timeBeforeCurrentGameState == 0)) - || gameState == STATE_FINISHED - ? (int) ((timeBeforeCurrentGameState + manRemainingGameTimeOffset + (manPlay ? System.currentTimeMillis() - manWhenClockChanged : 0)) / 1000) - : real || (competitionPhase != COMPETITION_PHASE_PLAYOFF && timeBeforeCurrentGameState > 0) || gameState != STATE_PLAYING - || getSecondsSince(whenCurrentGameStateBegan) >= Rules.league.delayedSwitchToPlaying - ? getSecondsSince(whenCurrentGameStateBegan - timeBeforeCurrentGameState - manRemainingGameTimeOffset) - : (int) ((timeBeforeCurrentGameState - manRemainingGameTimeOffset) / 1000); - return duration - timePlayed; - } - - /** - * The method returns the remaining pause time. - * - * @return The remaining number of seconds of the game pause or null if - * there currently is no pause. - */ - public Integer getRemainingPauseTime() { - if (gamePhase == GAME_PHASE_NORMAL && competitionType != COMPETITION_TYPE_DYNAMIC_BALL_HANDLING - && (gameState == STATE_INITIAL && firstHalf != C_TRUE && !timeOutActive[0] && !timeOutActive[1] - || gameState == STATE_FINISHED && firstHalf == C_TRUE)) { - return getRemainingSeconds(whenCurrentGameStateBegan, Rules.league.pauseTime); - } else if (Rules.league.pausePenaltyShootOutTime != 0 && competitionPhase == COMPETITION_PHASE_PLAYOFF && team[0].score == team[1].score - && (gameState == STATE_INITIAL && gamePhase == GAME_PHASE_PENALTYSHOOT && !timeOutActive[0] && !timeOutActive[1] - || gameState == STATE_FINISHED && firstHalf != C_TRUE)) { - return getRemainingSeconds(whenCurrentGameStateBegan, Rules.league.pausePenaltyShootOutTime); - } else { - return null; - } - } - - /** - * Resets the penalize time of all players to 0. This does not unpenalize - * them. - */ - public void resetPenaltyTimes() { - for (long[] players : whenPenalized) { - Arrays.fill(players, 0); - } - } - - /** - * Resets all penalties. - */ - public void resetPenalties() { - for (int i = 0; i < team.length; ++i) { - for (int j = 0; j < Rules.league.teamSize; j++) { - if (team[i].player[j].penalty != PlayerInfo.PENALTY_SUBSTITUTE && !ejected[i][j]) { - team[i].player[j].penalty = PlayerInfo.PENALTY_NONE; - } - if (Rules.league.resetPenaltyCountOnHalftime) { - robotPenaltyCount[i][j] = 0; - } - robotHardwarePenaltyBudget[i][j] = Math.min(Rules.league.allowedHardwarePenaltiesPerHalf, - Rules.league.allowedHardwarePenaltiesPerGame - (Rules.league.allowedHardwarePenaltiesPerHalf - robotHardwarePenaltyBudget[i][j])); - } - if (Rules.league.resetPenaltyCountOnHalftime) { - penaltyCount[i] = 0; - } - } - resetPenaltyTimes(); - } - - /** - * Calculates the remaining time a certain robot has to stay penalized. - * - * @param side 0 or 1 depending on whether the robot's team is shown left or - * right. - * @param number The robot's number starting with 0. - * @param real If true, the real time will be returned. If false, the first - * number of seconds in the playing state the time that it was during set - * will be returned. - * @return The number of seconds the robot has to stay penalized. - */ - public int getRemainingPenaltyTime(int side, int number, boolean real) { - int penalty = team[side].player[number].penalty; - int penaltyTime = getPenaltyDuration(side, number); - if (penaltyTime == -1) { - return 0; - } - assert penalty != PlayerInfo.PENALTY_MANUAL && penalty != PlayerInfo.PENALTY_SUBSTITUTE; - long start = whenPenalized[side][number]; - if (start != 0 && (gameState == STATE_SET || (!real - && gameState == STATE_PLAYING - && getSecondsSince(whenCurrentGameStateBegan) < Rules.league.delayedSwitchToPlaying))) { - start += getTime() - Math.max(whenCurrentGameStateBegan, whenPenalized[side][number]); - } - return Math.max(0, getRemainingSeconds(start, penaltyTime)); - } - - /** - * Calculates the total duration of the current penalty of a robot. - * - * @param side 0 or 1 depending on whether the robot's team is shown left or - * right. - * @param number The robot's number starting with 0. - * @return The total duration in seconds of the current penalty of a robot. - */ - public int getPenaltyDuration(int side, int number) { - int penalty = team[side].player[number].penalty; - int penaltyTime = -1; - if (penalty != PlayerInfo.PENALTY_MANUAL && penalty != PlayerInfo.PENALTY_SUBSTITUTE) { - penaltyTime = Rules.league.penaltyTime[penalty] + Rules.league.penaltyIncreaseTime * robotPenaltyCount[side][number]; - } - assert penalty == PlayerInfo.PENALTY_MANUAL || penalty == PlayerInfo.PENALTY_SUBSTITUTE || penaltyTime != -1; - return penaltyTime; - } - - /** - * Calculates the Number of robots in play (not substitute) on one side - * - * @param side 0 or 1 depending on whether the team is shown left or right. - * @return The number of robots without substitute penalty on the side - */ - public int getNumberOfRobotsInPlay(int side) { - int count = 0; - for (int i = 0; i < team[side].player.length; i++) { - if (team[side].player[i].penalty != PlayerInfo.PENALTY_SUBSTITUTE) { - count++; - } - } - return count; - } - - /** - * Determines the secondary time. Although this is a GUI feature, the - * secondary time will also be encoded in the network packet. - * - * @param real If true, the real time will be returned. If false, the first - * number of seconds in the playing state or after a goal there will be no - * secondary time (otherwise the start of the game could be inferred by the - * decreasing secondary time until the ball is free / ready ends). - * @return The secondary time in seconds or null if there currently is none. - */ - public Integer getSecondaryTime(boolean real) { - if (!real && (gameState == STATE_PLAYING - && getSecondsSince(whenCurrentGameStateBegan) < Rules.league.delayedSwitchToPlaying - || gamePhase == GAME_PHASE_NORMAL && gameState == STATE_READY && kickOffReason == KICKOFF_GOAL - && getSecondsSince(whenCurrentGameStateBegan) < Rules.league.delayedSwitchAfterGoal)) { - return null; - } - int timeKickOffBlocked = getRemainingSeconds(whenCurrentGameStateBegan, Rules.league.kickoffTime); - if (gameState == STATE_INITIAL && (timeOutActive[0] || timeOutActive[1])) { - return getRemainingSeconds(whenCurrentGameStateBegan, Rules.league.timeOutTime); - } else if (gameState == STATE_INITIAL && (refereeTimeout)) { - return getRemainingSeconds(whenCurrentGameStateBegan, Rules.league.refereeTimeout); - } else if (gameState == STATE_READY) { - return getRemainingSeconds(whenCurrentGameStateBegan, setPlay == SET_PLAY_PENALTY_KICK ? Rules.league.penaltyKickReadyTime : Rules.league.readyTime); - } else if (gameState == STATE_PLAYING && gamePhase != GAME_PHASE_PENALTYSHOOT - && (setPlay == SET_PLAY_GOAL_KICK || setPlay == SET_PLAY_PUSHING_FREE_KICK - || setPlay == SET_PLAY_CORNER_KICK || setPlay == SET_PLAY_KICK_IN)) { - return getRemainingSeconds(whenCurrentSetPlayBegan, Rules.league.freeKickTime); - } else if (gameState == STATE_PLAYING && gamePhase != GAME_PHASE_PENALTYSHOOT - && setPlay == SET_PLAY_PENALTY_KICK) { - return getRemainingSeconds(whenCurrentGameStateBegan, Rules.league.penaltyShotTime); - } else if (gameState == STATE_PLAYING && kickOffReason != KICKOFF_PENALTYSHOOT - && timeKickOffBlocked >= 0) { - return timeKickOffBlocked; - } else { - return getRemainingPauseTime(); - } - } - - public void updatePenalties() { - if (gamePhase == GAME_PHASE_NORMAL && gameState == STATE_PLAYING - && getSecondsSince(whenCurrentGameStateBegan) >= Rules.league.delayedSwitchToPlaying - && Rules.league instanceof SPL) { - for (TeamInfo t : team) { - for (PlayerInfo p : t.player) { - if (p.penalty == PlayerInfo.PENALTY_SPL_ILLEGAL_MOTION_IN_SET) { - p.penalty = PlayerInfo.PENALTY_NONE; - } - } - } - } - } - - /** - * Adjusts all timestamps in this class which depend on the system clock - * for the current time. - * - * @param originalTime The time when the structure was saved. - */ - public void adjustTimestamps(long originalTime) { - final long timeUpdate = getTime() - originalTime; - if (whenCurrentGameStateBegan != 0) { - whenCurrentGameStateBegan += timeUpdate; - } - if (whenCurrentSetPlayBegan != 0) { - whenCurrentSetPlayBegan += timeUpdate; - } - for (int i = 0; i < whenPenalized.length; ++i) { - for (int j = 0; j < whenPenalized[i].length; ++j) { - if (whenPenalized[i][j] != 0) { - whenPenalized[i][j] += timeUpdate; - } - } - } - if (manWhenClockChanged != 0) { - manWhenClockChanged += timeUpdate; - } - } -} diff --git a/src/data/GameControlData.java b/src/data/GameControlData.java index da9201b7..72145724 100644 --- a/src/data/GameControlData.java +++ b/src/data/GameControlData.java @@ -22,7 +22,7 @@ public class GameControlData implements Serializable { public static final String GAMECONTROLLER_STRUCT_HEADER = "RGme"; public static final String GAMECONTROLLER_TRUEGAMEDATA_STRUCT_HEADER = "RGTD"; - public static final byte GAMECONTROLLER_STRUCT_VERSION = 15; + public static final byte GAMECONTROLLER_STRUCT_VERSION = 16; public static final byte TEAM_BLUE = 0; public static final byte TEAM_RED = 1; public static final byte TEAM_YELLOW = 2; @@ -38,7 +38,7 @@ public class GameControlData implements Serializable { public static final byte COMPETITION_PHASE_PLAYOFF = 1; public static final byte COMPETITION_TYPE_NORMAL = 0; - public static final byte COMPETITION_TYPE_DYNAMIC_BALL_HANDLING = 1; + public static final byte COMPETITION_TYPE_SHARED_AUTONOMY = 1; public static final byte GAME_PHASE_NORMAL = 0; public static final byte GAME_PHASE_PENALTYSHOOT = 1; @@ -101,7 +101,7 @@ public class GameControlData implements Serializable { public byte packetNumber = 0; public byte playersPerTeam = (byte) Rules.league.teamSize; // The number of players on a team public byte competitionPhase = COMPETITION_PHASE_ROUNDROBIN; // phase of the game (COMPETITION_PHASE_ROUNDROBIN, COMPETITION_PHASE_PLAYOFF) - public byte competitionType = COMPETITION_TYPE_NORMAL; // type of the game (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_DYNAMIC_BALL_HANDLING) + public byte competitionType = COMPETITION_TYPE_NORMAL; // type of the game (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_SHARED_AUTONOMY) public byte gamePhase = GAME_PHASE_NORMAL; // Extra state information - (GAME_PHASE_NORMAL, GAME_PHASE_PENALTYSHOOT, etc) public byte gameState = STATE_INITIAL; // state of the game (STATE_READY, STATE_PLAYING, etc) public byte setPlay = SET_PLAY_NONE; // active set play (SET_PLAY_NONE, SET_PLAY_GOAL_KICK, etc) @@ -128,52 +128,6 @@ public GameControlData() { * @return the corresponding byte-stream of the state of this object */ public ByteBuffer toByteArray() { - AdvancedData data = (AdvancedData) this; - ByteBuffer buffer = ByteBuffer.allocate(SIZE); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.put(GAMECONTROLLER_STRUCT_HEADER.getBytes(), 0, 4); - buffer.put(GAMECONTROLLER_STRUCT_VERSION); - buffer.put(packetNumber); - buffer.put(playersPerTeam); - buffer.put(competitionPhase); - buffer.put(competitionType); - buffer.put(gamePhase); - if (gameState == STATE_PLAYING - && data.getSecondsSince(data.whenCurrentGameStateBegan) < Rules.league.delayedSwitchToPlaying) { - buffer.put(STATE_SET); - } else if (gamePhase == GAME_PHASE_NORMAL && gameState == STATE_READY - && data.kickOffReason == AdvancedData.KICKOFF_GOAL - && data.getSecondsSince(data.whenCurrentGameStateBegan) < Rules.league.delayedSwitchAfterGoal) { - buffer.put(STATE_PLAYING); - } else { - buffer.put(gameState); - } - buffer.put(setPlay); - buffer.put(firstHalf); - if (gamePhase == GAME_PHASE_NORMAL && gameState == STATE_READY && data.kickOffReason == AdvancedData.KICKOFF_GOAL - && data.getSecondsSince(data.whenCurrentGameStateBegan) < Rules.league.delayedSwitchAfterGoal) { - buffer.put(data.kickingTeamBeforeGoal); - } else { - buffer.put(kickingTeam); - } - buffer.putShort(secsRemaining); - buffer.putShort(secondaryTime); - for (TeamInfo aTeam : team) { - buffer.put(aTeam.toByteArray(gamePhase == GAME_PHASE_NORMAL && gameState == STATE_READY - && data.kickOffReason == AdvancedData.KICKOFF_GOAL - && data.getSecondsSince(data.whenCurrentGameStateBegan) < Rules.league.delayedSwitchAfterGoal - && data.kickingTeam != aTeam.teamNumber)); - } - - return buffer; - } - - /** - * Returns the corresponding byte-stream of the real state of this object. - * - * @return the corresponding byte-stream of the real state of this object - */ - public ByteBuffer getTrueDataAsByteArray() { final ByteBuffer buffer = ByteBuffer.allocate(SIZE); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.put(GAMECONTROLLER_TRUEGAMEDATA_STRUCT_HEADER.getBytes(), 0, 4); @@ -190,7 +144,7 @@ public ByteBuffer getTrueDataAsByteArray() { buffer.putShort(secsRemaining); buffer.putShort(secondaryTime); for (TeamInfo aTeam : team) { - buffer.put(aTeam.toByteArray(false)); + buffer.put(aTeam.toByteArray()); } return buffer; @@ -254,8 +208,8 @@ public String toString() { case COMPETITION_TYPE_NORMAL: temp = "normal"; break; - case COMPETITION_TYPE_DYNAMIC_BALL_HANDLING: - temp = "dynamic ball handling"; + case COMPETITION_TYPE_SHARED_AUTONOMY: + temp = "shared autonomy"; break; default: temp = "undefined(" + competitionType + ")"; diff --git a/src/data/PlayerInfo.java b/src/data/PlayerInfo.java index e8df1b14..648c8c6a 100644 --- a/src/data/PlayerInfo.java +++ b/src/data/PlayerInfo.java @@ -30,6 +30,7 @@ public class PlayerInfo implements Serializable { public static final byte PENALTY_SPL_LOCAL_GAME_STUCK = 8; public static final byte PENALTY_SPL_ILLEGAL_POSITION_IN_SET = 9; public static final byte PENALTY_SPL_PLAYER_STANCE = 10; + public static final byte PENALTY_SPL_ILLEGAL_MOTION_IN_INITIAL = 11; public static final byte PENALTY_SUBSTITUTE = 14; public static final byte PENALTY_MANUAL = 15; @@ -94,6 +95,8 @@ public static String getPenaltyName(int penalty) { return "illegal position in set"; case PENALTY_SPL_PLAYER_STANCE: return "player stance"; + case PENALTY_SPL_ILLEGAL_MOTION_IN_INITIAL: + return "illegal motion in initial"; case PENALTY_SUBSTITUTE: return "substitute"; case PENALTY_MANUAL: diff --git a/src/data/Rules.java b/src/data/Rules.java index 49fae703..2a87fe39 100644 --- a/src/data/Rules.java +++ b/src/data/Rules.java @@ -13,9 +13,7 @@ public abstract class Rules /** Note all league's rules here to have them available. */ public static final Rules[] LEAGUES = { new SPL(), - new SPLPenaltyShootout(), - new SPL7v7(), - new SPLDynamicBallHandling() + new SPLPenaltyShootout() }; /** diff --git a/src/data/SPL7v7.java b/src/data/SPL7v7.java deleted file mode 100644 index b1258cb4..00000000 --- a/src/data/SPL7v7.java +++ /dev/null @@ -1,21 +0,0 @@ -package data; - -/** - * This class sets attributes given by the spl rules for 7 players. - * - * @author Arne Hasselbring - */ -public class SPL7v7 extends SPL -{ - SPL7v7() - { - /* The league's name these rules are for. */ - leagueName = "SPL 7v7"; - /* The league's directory name with its teams and icons. */ - leagueDirectory = "spl"; - /* How many robots are in a team. */ - teamSize = 7; - /* How many robots of each team may play at one time. */ - robotsPlaying = 7; - } -} diff --git a/src/data/SPLDynamicBallHandling.java b/src/data/SPLDynamicBallHandling.java deleted file mode 100644 index c85f62cc..00000000 --- a/src/data/SPLDynamicBallHandling.java +++ /dev/null @@ -1,27 +0,0 @@ -package data; - -/** - * This class sets attributes given by the spl rules, adapted for the dynamic ball handling challenge. - * - * @author Arne Hasselbring - */ -public class SPLDynamicBallHandling extends SPL -{ - SPLDynamicBallHandling() - { - /* The league's name these rules are for. */ - leagueName = "SPL Dynamic Ball Handling"; - /* The league's directory name with its teams and icons. */ - leagueDirectory = "spl"; - /* How many robots are in a team. */ - teamSize = 3; - /* How many robots of each team may play at one time. */ - robotsPlaying = 3; - /* Time in seconds one half is long. */ - halfTime = 4*60; - /* Time in seconds the ball is blocked after kickoff. */ - kickoffTime = -1; - /* The type of the competition (COMPETITION_TYPE_NORMAL, COMPETITION_TYPE_CHALLENGE_SHIELD, etc) */ - competitionType = GameControlData.COMPETITION_TYPE_DYNAMIC_BALL_HANDLING; - } -} diff --git a/src/data/SPLGORE.java b/src/data/SPLGORE.java deleted file mode 100644 index c05a65ce..00000000 --- a/src/data/SPLGORE.java +++ /dev/null @@ -1,23 +0,0 @@ -package data; - -/** - * This class sets attributes given by the spl rules, adapted for the German Open Replacement Event 2021. - * - * @author Arne Hasselbring - */ -public class SPLGORE extends SPL -{ - SPLGORE() - { - /* The league's name these rules are for. */ - leagueName = "SPL GORE"; - /* The league's directory name with its teams and icons. */ - leagueDirectory = "spl"; - /* How many robots are in a team. */ - teamSize = 5; // no substitute - /* Number of hardware penalties per half before the robot is ejected. */ - allowedHardwarePenaltiesPerHalf = 2; - /* Number of hardware penalties per game before the robot is ejected. */ - allowedHardwarePenaltiesPerGame = 3; - } -} diff --git a/src/data/TeamInfo.java b/src/data/TeamInfo.java index 6f15c7d4..c3c85d01 100644 --- a/src/data/TeamInfo.java +++ b/src/data/TeamInfo.java @@ -66,18 +66,16 @@ public TeamInfo() { /** * Packing this Java class to the C-structure to be send. * - * @param decreaseScore Whether the score should be decreased by one before sending. - * * @return Byte array representing the C-structure. */ - public byte[] toByteArray(boolean decreaseScore) { + public byte[] toByteArray() { ByteBuffer buffer = ByteBuffer.allocate(SIZE); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.put(teamNumber); buffer.put(fieldPlayerColor); buffer.put(goalkeeperColor); buffer.put(goalkeeper); - buffer.put(decreaseScore ? (byte) (score - 1) : score); + buffer.put(score); buffer.put(penaltyShot); buffer.putShort(singleShots); buffer.putShort(messageBudget); diff --git a/src/teamcomm/gui/View3DGSV.java b/src/teamcomm/gui/View3DGSV.java index c15ace37..0756902f 100644 --- a/src/teamcomm/gui/View3DGSV.java +++ b/src/teamcomm/gui/View3DGSV.java @@ -9,7 +9,6 @@ import com.jogamp.opengl.glu.GLUquadric; import com.jogamp.opengl.util.FPSAnimator; import com.jogamp.opengl.util.awt.TextRenderer; -import data.AdvancedData; import data.GameControlData; import data.Rules; import java.awt.BorderLayout; @@ -409,8 +408,8 @@ public void draw(final GL2 gl) { // Score textRenderers[RENDERER_SCORE].beginRendering(window.getWidth(), window.getHeight()); - drawText(textRenderers[RENDERER_SCORE], "" + data.team[1].score, window.getWidth() / 6 + 40 * window.getWidth() / 1920, window.getHeight() - 20 * window.getWidth() / 1920 - (textRendererSizes[RENDERER_SCORE] + (int) textRenderers[RENDERER_SCORE].getBounds("0").getHeight()) / 2, Rules.league.teamColor[data.team[1].fieldPlayerColor == AdvancedData.TEAM_WHITE ? AdvancedData.TEAM_BLACK : data.team[1].fieldPlayerColor]); - drawText(textRenderers[RENDERER_SCORE], "" + data.team[0].score, window.getWidth() - window.getWidth() / 6 - 40 * window.getWidth() / 1920 - (int) Math.max(textRenderers[RENDERER_SCORE].getBounds("" + data.team[0].score).getWidth(), ("" + data.team[0].score).length() * textRenderers[RENDERER_SCORE].getCharWidth('0')), window.getHeight() - 20 * window.getWidth() / 1920 - (textRendererSizes[RENDERER_SCORE] + (int) textRenderers[RENDERER_SCORE].getBounds("0").getHeight()) / 2, Rules.league.teamColor[data.team[0].fieldPlayerColor == AdvancedData.TEAM_WHITE ? AdvancedData.TEAM_BLACK : data.team[0].fieldPlayerColor]); + drawText(textRenderers[RENDERER_SCORE], "" + data.team[1].score, window.getWidth() / 6 + 40 * window.getWidth() / 1920, window.getHeight() - 20 * window.getWidth() / 1920 - (textRendererSizes[RENDERER_SCORE] + (int) textRenderers[RENDERER_SCORE].getBounds("0").getHeight()) / 2, Rules.league.teamColor[data.team[1].fieldPlayerColor == GameControlData.TEAM_WHITE ? GameControlData.TEAM_BLACK : data.team[1].fieldPlayerColor]); + drawText(textRenderers[RENDERER_SCORE], "" + data.team[0].score, window.getWidth() - window.getWidth() / 6 - 40 * window.getWidth() / 1920 - (int) Math.max(textRenderers[RENDERER_SCORE].getBounds("" + data.team[0].score).getWidth(), ("" + data.team[0].score).length() * textRenderers[RENDERER_SCORE].getCharWidth('0')), window.getHeight() - 20 * window.getWidth() / 1920 - (textRendererSizes[RENDERER_SCORE] + (int) textRenderers[RENDERER_SCORE].getBounds("0").getHeight()) / 2, Rules.league.teamColor[data.team[0].fieldPlayerColor == GameControlData.TEAM_WHITE ? GameControlData.TEAM_BLACK : data.team[0].fieldPlayerColor]); textRenderers[RENDERER_SCORE].endRendering(); // Penalty shots diff --git a/src/teamcomm/net/logging/LogYamlLoader.java b/src/teamcomm/net/logging/LogYamlLoader.java index 08fc63d9..18d006a5 100644 --- a/src/teamcomm/net/logging/LogYamlLoader.java +++ b/src/teamcomm/net/logging/LogYamlLoader.java @@ -77,7 +77,7 @@ public KindConstructor(final String kind) { private final List penalties = Arrays.asList( "noPenalty", "ballHolding", "playerPushing", "motionInSet", "fallenInactive", "illegalPosition", "leavingTheField", "pickedUp", "localGameStuck", "illegalPositionInSet", "playerStance", - "_11", "_12", "_13", "substitute"); // playingWithArmsHands = 1 + "motionInInitial", "_12", "_13", "substitute"); // playingWithArmsHands = 1 /** The current state of the GameController packet. */ private final GameControlData data = new GameControlData(); @@ -160,7 +160,7 @@ private void parse(final File file, final Deque queu // Create a new instance for the queue. final GameControlData copy = new GameControlData(); - copy.fromByteArray(ByteBuffer.wrap(data.getTrueDataAsByteArray().array())); + copy.fromByteArray(ByteBuffer.wrap(data.toByteArray().array())); message = copy; break; case "statusMessage": @@ -211,7 +211,7 @@ private void parseMetadata(final Map entry) { if (params.get("competition") instanceof Map) { @SuppressWarnings("unchecked") final Map competition = (Map) params.get("competition"); - data.competitionType = competition.get("challengeMode") == null ? COMPETITION_TYPE_NORMAL : COMPETITION_TYPE_DYNAMIC_BALL_HANDLING; + data.competitionType = competition.get("challengeMode") == null ? COMPETITION_TYPE_NORMAL : COMPETITION_TYPE_SHARED_AUTONOMY; data.playersPerTeam = (byte)(int)(Integer) competition.get("playersPerTeam"); } if (params.get("game") instanceof Map) {