/******************************************************************************* * Copyright (c) 2001, 2010 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 * * Contributors: * Flemming N. Larsen * - Initial implementation * Pavel Savara * - Xml Serialization, refactoring *******************************************************************************/ package net.sf.robocode.battle.snapshot; import net.sf.robocode.battle.peer.RobotPeer; import net.sf.robocode.peer.DebugProperty; import net.sf.robocode.peer.ExecCommands; import net.sf.robocode.serialization.IXmlSerializable; import net.sf.robocode.serialization.XmlReader; import net.sf.robocode.serialization.SerializableOptions; import net.sf.robocode.serialization.XmlWriter; import robocode.control.snapshot.IRobotSnapshot; import robocode.control.snapshot.IScoreSnapshot; import robocode.control.snapshot.RobotState; import java.awt.geom.Arc2D; import java.io.IOException; import java.io.Serializable; import java.util.List; /** * A snapshot of a robot at a specific time instant in a battle. * The snapshot contains a snapshot of the robot data at that specific time. * * @author Flemming N. Larsen (original) * @author Pavel Savara (contributor) * @since 1.6.1 */ public final class RobotSnapshot implements Serializable, IXmlSerializable, IRobotSnapshot { private static final long serialVersionUID = 2L; /** The name of the robot */ private String name; /** The short name of the robot */ private String shortName; /** Very short name of the robot */ private String veryShortName; /** Very short name of the team leader robot (might be null) */ private String teamName; /** The contestant index for the robot */ private int contestantIndex; /** The robot state */ private RobotState state; /** The energy level of the robot */ private double energy; /** The velocity of the robot */ private double velocity; /** The gun heat level of the robot */ private double gunHeat; /** The body heading in radians */ private double bodyHeading; /** The gun heading in radians */ private double gunHeading; /** The radar heading in radians */ private double radarHeading; /** The X position */ private double x; /** The Y position */ private double y; /** The ARGB color of the body */ private int bodyColor = ExecCommands.defaultBodyColor; /** The ARGB color of the gun */ private int gunColor = ExecCommands.defaultGunColor; /** The ARGB color of the radar */ private int radarColor = ExecCommands.defaultRadarColor; /** The ARGB color of the scan arc */ private int scanColor = ExecCommands.defaultScanColor; /** Flag specifying if this robot is a Droid */ private boolean isDroid; /** Flag specifying if this robot is a IPaintRobot or is invoking getGraphics() */ private boolean isPaintRobot; /** Flag specifying if painting is enabled for this robot */ private boolean isPaintEnabled; /** Flag specifying if RobocodeSG painting is enabled for this robot */ private boolean isSGPaintEnabled; /** Snapshot of the scan arc */ private SerializableArc scanArc; /** Snapshot of the object with queued calls for Graphics object */ private Object graphicsCalls; /** Snapshot of debug properties */ private DebugProperty[] debugProperties; /** Snapshot of the output print stream for this robot */ private String outputStreamSnapshot; /** Snapshot of score of the robot */ private IScoreSnapshot robotScoreSnapshot; /** * Creates a snapshot of a robot that must be filled out with data later. */ public RobotSnapshot() {} /** * Creates a snapshot of a robot. * * @param robot the robot to make a snapshot of. * @param readoutText {@code true} if the output text from the robot must be included in the snapshot; * {@code false} otherwise. */ public RobotSnapshot(RobotPeer robot, boolean readoutText) { name = robot.getName(); shortName = robot.getShortName(); veryShortName = robot.getVeryShortName(); teamName = robot.getTeamName(); contestantIndex = robot.getContestIndex(); state = robot.getState(); energy = robot.getEnergy(); velocity = robot.getVelocity(); gunHeat = robot.getGunHeat(); bodyHeading = robot.getBodyHeading(); gunHeading = robot.getGunHeading(); radarHeading = robot.getRadarHeading(); x = robot.getX(); y = robot.getY(); bodyColor = robot.getBodyColor(); gunColor = robot.getGunColor(); radarColor = robot.getRadarColor(); scanColor = robot.getScanColor(); isDroid = robot.isDroid(); isPaintRobot = robot.isPaintRobot() || robot.isTryingToPaint(); isPaintEnabled = robot.isPaintEnabled(); isSGPaintEnabled = robot.isSGPaintEnabled(); scanArc = robot.getScanArc() != null ? new SerializableArc((Arc2D.Double) robot.getScanArc()) : null; graphicsCalls = robot.getGraphicsCalls(); final List<DebugProperty> dp = robot.getDebugProperties(); debugProperties = dp != null ? dp.toArray(new DebugProperty[dp.size()]) : null; if (readoutText) { outputStreamSnapshot = robot.readOutText(); } robotScoreSnapshot = new ScoreSnapshot(robot.getName(), robot.getRobotStatistics()); } @Override public String toString() { return shortName + "(" + (int) energy + ") X" + (int) x + " Y" + (int) y + " " + state.toString(); } /** * {@inheritDoc} */ // Used to identify buttons public String getName() { return name; } /** * {@inheritDoc} */ // Used for text on buttons public String getShortName() { return shortName; } /** * {@inheritDoc} */ // Used for drawing the name of the robot on the battle view public String getVeryShortName() { return veryShortName; } /** * {@inheritDoc} */ public String getTeamName() { return teamName; } /** * {@inheritDoc} */ public int getContestantIndex() { return contestantIndex; } /** * {@inheritDoc} */ public RobotState getState() { return state; } /** * {@inheritDoc} */ public double getEnergy() { return energy; } /** * {@inheritDoc} */ public double getVelocity() { return velocity; } /** * {@inheritDoc} */ public double getBodyHeading() { return bodyHeading; } /** * {@inheritDoc} */ public double getGunHeading() { return gunHeading; } /** * {@inheritDoc} */ public double getRadarHeading() { return radarHeading; } /** * {@inheritDoc} */ public double getGunHeat() { return gunHeat; } /** * {@inheritDoc} */ public double getX() { return x; } /** * {@inheritDoc} */ public double getY() { return y; } /** * {@inheritDoc} */ public int getBodyColor() { return bodyColor; } /** * {@inheritDoc} */ public int getGunColor() { return gunColor; } /** * {@inheritDoc} */ public int getRadarColor() { return radarColor; } /** * {@inheritDoc} */ public int getScanColor() { return scanColor; } /** * {@inheritDoc} */ public boolean isDroid() { return isDroid; } /** * {@inheritDoc} */ public boolean isPaintRobot() { return isPaintRobot; } /** * {@inheritDoc} */ public boolean isPaintEnabled() { return isPaintEnabled; } /** * Sets the flag specifying if painting is enabled for the robot. * * @param isPaintEnabled {@code true} if painting must be enabled; * {@code false} otherwise. */ public void setPaintEnabled(boolean isPaintEnabled) { this.isPaintEnabled = isPaintEnabled; } /** * {@inheritDoc} */ public boolean isSGPaintEnabled() { return isSGPaintEnabled; } /** * {@inheritDoc} */ public DebugProperty[] getDebugProperties() { return debugProperties; } /** * {@inheritDoc} */ public String getOutputStreamSnapshot() { return outputStreamSnapshot; } /** * Sets the snapshot of the output print stream for this robot. * * @param outputStreamSnapshot new output print stream snapshot. */ public void setOutputStreamSnapshot(String outputStreamSnapshot) { this.outputStreamSnapshot = outputStreamSnapshot; } void stripDetails(SerializableOptions options) { if (options.skipDebug) { graphicsCalls = null; debugProperties = null; outputStreamSnapshot = null; isPaintEnabled = false; isSGPaintEnabled = false; } if (options.skipNames) { name = veryShortName; shortName = veryShortName; teamName = veryShortName; } } /** * {@inheritDoc} */ public IScoreSnapshot getScoreSnapshot() { return robotScoreSnapshot; } /** * Returns the scan arc snapshot for the robot. * * @return the scan arc snapshot for the robot. */ public Arc2D getScanArc() { return scanArc != null ? scanArc.create() : null; } /** * Returns the object with queued calls for Graphics object. * * @return the object with queued calls for Graphics object. */ public Object getGraphicsCalls() { return graphicsCalls; } /** * {@inheritDoc} */ public void writeXml(XmlWriter writer, SerializableOptions options) throws IOException { writer.startElement(options.shortAttributes ? "r" : "robot"); { writer.writeAttribute("id", contestantIndex); if (!options.skipNames) { writer.writeAttribute("vsName", veryShortName); } if (!options.skipExploded || state != RobotState.ACTIVE) { writer.writeAttribute(options.shortAttributes ? "s" : "state", state.toString()); } writer.writeAttribute(options.shortAttributes ? "e" : "energy", energy, options.trimPrecision); writer.writeAttribute("x", x, options.trimPrecision); writer.writeAttribute("y", y, options.trimPrecision); writer.writeAttribute(options.shortAttributes ? "b" : "bodyHeading", bodyHeading, options.trimPrecision); writer.writeAttribute(options.shortAttributes ? "g" : "gunHeading", gunHeading, options.trimPrecision); writer.writeAttribute(options.shortAttributes ? "r" : "radarHeading", radarHeading, options.trimPrecision); writer.writeAttribute(options.shortAttributes ? "h" : "gunHeat", gunHeat, options.trimPrecision); writer.writeAttribute(options.shortAttributes ? "v" : "velocity", velocity, options.trimPrecision); if (!options.skipNames) { writer.writeAttribute("teamName", teamName); writer.writeAttribute("name", name); writer.writeAttribute("sName", shortName); if (isDroid) { writer.writeAttribute("isDroid", true); } if (bodyColor != ExecCommands.defaultBodyColor) { writer.writeAttribute("bodyColor", Integer.toHexString(bodyColor).toUpperCase()); } if (gunColor != ExecCommands.defaultGunColor) { writer.writeAttribute("gunColor", Integer.toHexString(gunColor).toUpperCase()); } if (radarColor != ExecCommands.defaultRadarColor) { writer.writeAttribute("radarColor", Integer.toHexString(radarColor).toUpperCase()); } if (scanColor != ExecCommands.defaultScanColor) { writer.writeAttribute("scanColor", Integer.toHexString(scanColor).toUpperCase()); } } if (!options.skipVersion) { writer.writeAttribute("ver", serialVersionUID); } if (!options.skipDebug) { if (outputStreamSnapshot != null && outputStreamSnapshot.length() != 0) { writer.writeAttribute("out", outputStreamSnapshot); } if (debugProperties != null) { writer.startElement("debugProperties"); { for (DebugProperty prop : debugProperties) { prop.writeXml(writer, options); } } writer.endElement(); } } ((ScoreSnapshot) robotScoreSnapshot).writeXml(writer, options); } writer.endElement(); } /** * {@inheritDoc} */ public XmlReader.Element readXml(XmlReader reader) { return reader.expect("robot", new XmlReader.Element() { public IXmlSerializable read(XmlReader reader) { final RobotSnapshot snapshot = new RobotSnapshot(); reader.expect("name", new XmlReader.Attribute() { public void read(String value) { snapshot.name = value; } }); reader.expect("sName", new XmlReader.Attribute() { public void read(String value) { snapshot.shortName = value; } }); reader.expect("vsName", new XmlReader.Attribute() { public void read(String value) { snapshot.veryShortName = value; } }); reader.expect("teamName", new XmlReader.Attribute() { public void read(String value) { snapshot.teamName = value; } }); reader.expect("state", new XmlReader.Attribute() { public void read(String value) { snapshot.state = RobotState.valueOf(value); } }); reader.expect("isDroid", new XmlReader.Attribute() { public void read(String value) { snapshot.isDroid = Boolean.valueOf(value); } }); reader.expect("bodyColor", new XmlReader.Attribute() { public void read(String value) { snapshot.bodyColor = (Long.valueOf(value.toUpperCase(), 16).intValue()); } }); reader.expect("gunColor", new XmlReader.Attribute() { public void read(String value) { snapshot.gunColor = Long.valueOf(value.toUpperCase(), 16).intValue(); } }); reader.expect("radarColor", new XmlReader.Attribute() { public void read(String value) { snapshot.radarColor = Long.valueOf(value.toUpperCase(), 16).intValue(); } }); reader.expect("scanColor", new XmlReader.Attribute() { public void read(String value) { snapshot.scanColor = Long.valueOf(value.toUpperCase(), 16).intValue(); } }); reader.expect("energy", new XmlReader.Attribute() { public void read(String value) { snapshot.energy = Double.parseDouble(value); } }); reader.expect("velocity", new XmlReader.Attribute() { public void read(String value) { snapshot.velocity = Double.parseDouble(value); } }); reader.expect("gunHeat", new XmlReader.Attribute() { public void read(String value) { snapshot.gunHeat = Double.parseDouble(value); } }); reader.expect("bodyHeading", new XmlReader.Attribute() { public void read(String value) { snapshot.bodyHeading = Double.parseDouble(value); } }); reader.expect("gunHeading", new XmlReader.Attribute() { public void read(String value) { snapshot.gunHeading = Double.parseDouble(value); } }); reader.expect("radarHeading", new XmlReader.Attribute() { public void read(String value) { snapshot.radarHeading = Double.parseDouble(value); } }); reader.expect("x", new XmlReader.Attribute() { public void read(String value) { snapshot.x = Double.parseDouble(value); } }); reader.expect("y", new XmlReader.Attribute() { public void read(String value) { snapshot.y = Double.parseDouble(value); } }); reader.expect("out", new XmlReader.Attribute() { public void read(String value) { if (value != null && value.length() != 0) { snapshot.outputStreamSnapshot = value; } } }); final XmlReader.Element element = (new ScoreSnapshot()).readXml(reader); reader.expect("score", new XmlReader.Element() { public IXmlSerializable read(XmlReader reader) { snapshot.robotScoreSnapshot = (IScoreSnapshot) element.read(reader); return (ScoreSnapshot) snapshot.robotScoreSnapshot; } }); return snapshot; } }); } /** * Class used for serializing an Arc2D.double. * The purpose of this class is to overcome various serialization problems with Arc2D to cope with bug in Java 6: * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6522514">Bug ID: 6522514</a>. * * @author Pavel Savara */ private static class SerializableArc implements Serializable { private static final long serialVersionUID = 1L; public final double x; public final double y; public final double w; public final double h; public final double start; public final double extent; public final int type; public SerializableArc(Arc2D.Double arc) { x = arc.getX(); y = arc.getY(); w = arc.getWidth(); h = arc.getHeight(); start = arc.getAngleStart(); extent = arc.getAngleExtent(); type = arc.getArcType(); } public Arc2D create() { return new Arc2D.Double(x, y, w, h, start, extent, type); } } }