Java tutorial
/* * WDLStats * Copyright (C) 2015 Chris K * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.wumbo.wdl.parser.events; import static com.google.common.base.Preconditions.*; import java.util.Map; import java.util.Optional; import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.collect.BiMap; import ca.wumbo.wdl.parser.CorruptStatFileException; import ca.wumbo.wdl.parser.Player; import ca.wumbo.wdl.parser.enums.EventType; /** * The stat event data. It is parsed in the constructor and is immutable. * * @author Chris */ public abstract class Event { /** * The activator player. */ protected Player activator; /** * The player (if any) who was the target. */ protected Optional<Player> target; /** * This gametic event. */ protected int gametic; /** * The gametic that is normalized to start from zero. */ protected int normalizedGametic; /** * The activator's X location. */ protected int activatorX; /** * The activator's Y location. */ protected int activatorY; /** * The activator's Z location. */ protected int activatorZ; /** * The target's X location. */ protected int targetX; /** * The target's Y location. */ protected int targetY; /** * The target's Z location. */ protected int targetZ; /** * The first varying argument. */ protected int arg0; /** * The second varying argument. */ protected int arg1; /** * The third varying argument. */ protected int arg2; /** * Creates an event from a line of text. * * @param tokens * The tokens. * * @param playerMap * The map of players to look up a player. * * @throws CorruptStatFileException * If the line cannot properly be parsed. * * @throws NullPointerException * If the argument is null. */ public Event(String[] tokens, Map<String, Player> playerMap) { checkNotNull(tokens); checkNotNull(playerMap); if (tokens.length != 13) throw new CorruptStatFileException("Invalid number of tokens for Event."); // Tokens[1] is the activator player name. if (playerMap.containsKey(tokens[1])) { activator = playerMap.get(tokens[1]); if (activator == null) { // Due to a bug in the logs, the target is the activator in enviro damage. if (isEnviroClassEvent()) { throw new IllegalStateException( "Player map contained a null key when looking for activator: " + tokens[1]); } } } // Tokens[2] is the target player name (may be empty). if (!playerMap.containsKey(tokens[2])) { target = Optional.empty(); } else { target = Optional.of(playerMap.get(tokens[2])); if (!target.isPresent()) throw new IllegalStateException( "Player map contained a null key when looking for target: " + tokens[1]); } // If its an enviromental damage, set the activator as the player. if (activator == null && isEnviroClassEvent()) { activator = playerMap.get(tokens[2]); if (activator == null) throw new CorruptStatFileException( "Environmental evemt did not have a target to copy from for an empty activator."); } // If the activator is still null, then we have a problem. if (activator == null) throw new CorruptStatFileException( "Unable to get player for activator." + tokens[0] + " ... " + tokens[1] + " | " + tokens[2]); try { gametic = Integer.parseInt(tokens[3]); activatorX = Integer.parseInt(tokens[4]); activatorY = Integer.parseInt(tokens[5]); activatorZ = Integer.parseInt(tokens[6]); targetX = Integer.parseInt(tokens[7]); targetY = Integer.parseInt(tokens[8]); targetZ = Integer.parseInt(tokens[9]); arg0 = Integer.parseInt(tokens[10]); arg1 = Integer.parseInt(tokens[11]); arg2 = Integer.parseInt(tokens[12]); } catch (NumberFormatException e) { throw new CorruptStatFileException("Error parsing token value from event tokens."); } if (gametic <= 0) { throw new CorruptStatFileException("Corrupt data: negative gametic."); } } /** * Checks if this is an environmental damage class or not. * * @return * True if it is, false if not. */ protected boolean isEnviroClassEvent() { EventType et = getEventType(); switch (et) { case ENVIROKILL: case ENVIROCARRIERKILL: case ENVIRODAMAGE: case ENVIRODAMAGEUNUSED: return true; default: break; } return false; } /** * Gets the event type. * * @return * The event type. */ public abstract EventType getEventType(); /** * Gets the activator player. * * @return * The activator player. */ public Player getActivator() { return activator; } /** * Gets the target, if any. The target may not be present in some event * cases (ex: environmental damage). * * @return * The target player, if any. */ public Optional<Player> getTarget() { return target; } /** * Gets the gametic for this event. * * @return * The gametic. */ public int getGametic() { return gametic; } /** * Gets the activator's X. * * @return * The activator's X. */ public int getActivatorX() { return activatorX; } /** * Gets the activator's Y. * * @return * The activator's Y. */ public int getActivatorY() { return activatorY; } /** * Gets the activator's Z. * * @return * The activator's Z. */ public int getActivatorZ() { return activatorZ; } /** * Gets the target's X. * * @return * The target's X. */ public int getTargetX() { return targetX; } /** * Gets the target's Y. * * @return * The target's Y. */ public int getTargetY() { return targetY; } /** * Gets the target's Z. * * @return * The target's Z. */ public int getTargetZ() { return targetZ; } /** * Gets the argument value. * * @return * The argument value. */ public int getArg0() { return arg0; } /** * Gets the argument value. * * @return * The argument value. */ public int getArg1() { return arg1; } /** * Gets the argument value. * * @return * The argument value. */ public int getArg2() { return arg2; } /** * Gets the numerical value of the event type. * * @return * The numerical value of the event type. */ public int getEventTypeNumber() { return getEventType().ordinal(); } /** * Uses the 'base' gametic for the round start. * * @param baseGametic * The gametic that the round starts at. * * @throws IllegalArgumentException * If the gametic is negative or greater than the current gametic. */ public void createNormalizedGametic(int baseGametic) { checkArgument(baseGametic >= 0); checkArgument(baseGametic <= gametic); normalizedGametic = gametic - baseGametic; } /** * Gets the normalized gametic (which starts from 0 based on the round * start). This must have been set with the method createNormalizedGametic * or else it will return 0. * * @return * The normalized gametic. */ public int getNormalizedGametic() { return normalizedGametic; } /** * Gets the insertion query statement for this event. * * @param database * The database this belongs to. This should not be empty. * * @param table * The table for this event. * * @param nameToPlayerIdMap * The name to player ID map. * @param eventLogId * * @return * A query statement that can be issued to the database. * * @throws NullPointerException * If any argument is null. * * @throws IllegalArgumentException * If any string or table has zero characters/elements, or the log id * is negative. * * @throws RuntimeException * If neither an activator nor target ID can be found (both parts * of the query for the ID's would be 'NULL'). */ public String getSqlInsertionQuery(String database, String table, BiMap<String, Integer> nameToPlayerIdMap, int eventLogId) { checkNotNull(database); checkNotNull(table); checkNotNull(nameToPlayerIdMap); checkArgument(database.length() > 0); checkArgument(table.length() > 0); checkArgument(nameToPlayerIdMap.size() > 0); checkArgument(eventLogId >= 0); String tblArgs = "fk_event_log_id, type, nfk_activator_player_id, nfk_target_player_id, " + "gametic, activator_x, activator_y, activator_z, " + "target_x, target_y, target_z, arg0, arg1, arg2"; String valueArgs = "%d, %d, %s, %s, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d"; String activatorIdOrNullSqlStr = activator != null && nameToPlayerIdMap.containsKey(activator.getName()) ? Integer.toString(nameToPlayerIdMap.get(activator.getName())) : "NULL"; String targetIdOrNullSqlStr = target.isPresent() && nameToPlayerIdMap.containsKey(target.get().getName()) ? Integer.toString(nameToPlayerIdMap.get(target.get().getName())) : "NULL"; // If both are null, something is critically wrong. if (activatorIdOrNullSqlStr.equals("NULL") && targetIdOrNullSqlStr.equals("NULL")) { throw new RuntimeException( "Both activator and target are 'NULL', malformed event or corrupt name to ID map."); } return String.format("INSERT INTO `%s`.`%s`(%s) VALUES(" + valueArgs + ")", database, table, tblArgs, eventLogId, getEventTypeNumber(), activatorIdOrNullSqlStr, targetIdOrNullSqlStr, getGametic(), getActivatorX(), getActivatorY(), getActivatorZ(), getTargetX(), getTargetY(), getTargetZ(), getArg0(), getArg1(), getArg2()); } /** * Creates a helper that allows inheriting classes to extend this and * return the values appended. * * @return * A starting of the helper object. */ public ToStringHelper eventToStringHelper() { return MoreObjects.toStringHelper(this).add("type", getEventType()).add("name", activator.getName()) .add("target", target.toString()).add("gametic", gametic).add("activatorX", activatorX) .add("activatorY", activatorY).add("activatorZ", activatorZ).add("targetX", targetX) .add("targetY", targetY).add("targetZ", targetZ).add("arg0", arg0).add("arg1", arg1) .add("arg2", arg2); } /** * {@inheritDoc} */ @Override public String toString() { return eventToStringHelper().toString(); } }