diff --git a/build.xml b/build.xml index 2c06c9979..1fa1b87fb 100644 --- a/build.xml +++ b/build.xml @@ -182,7 +182,7 @@ diff --git a/splash.jpg b/build/splash.jpg similarity index 100% rename from splash.jpg rename to build/splash.jpg diff --git a/data/strings/FreeColMessages.properties b/data/strings/FreeColMessages.properties index 65c67b71b..7038bd6f6 100644 --- a/data/strings/FreeColMessages.properties +++ b/data/strings/FreeColMessages.properties @@ -217,6 +217,7 @@ cli.error.home.notDir=%string% is not a directory. cli.error.home.notExists=Directory %string% does not exist. cli.error.save=Can not read saved game %string%. cli.error.serverPort=%string% is not a valid port number. +cli.error.splash=Splash file %name% not found. cli.error.timeout=%string% is too short (less than %minimum%). cli.advantages=set the type of ADVANTAGES (%advantages%) @@ -246,6 +247,7 @@ cli.no-intro=skip the intro video cli.no-java-check=skip the java version check cli.no-memory-check=skip the memory check cli.no-sound=run FreeCol without sound +cli.no-splash=skip the splash screen cli.private=start a private server (not published to the metaserver) cli.seed=provide a SEED for the pseudo-random number generator cli.server-name=specify a custom NAME for the server diff --git a/doc/FreeCol.tex b/doc/FreeCol.tex index 9253c613b..744cb00e5 100644 --- a/doc/FreeCol.tex +++ b/doc/FreeCol.tex @@ -336,8 +336,8 @@ options: \item\verb$--version$ Display the version number. \item\verb$--default-locale LOCALE$ Specify a locale. \item\verb$--freecol-data DIR$ Specify the directory that contains -FreeCol's data files. In general, you will only need to use this if -you have installed a modified copy of FreeCol's data files. + FreeCol's data files. In general, you will only need to use this if + you have installed a modified copy of FreeCol's data files. \item\verb$--advantages ADVANTAGES$ Set the European nation advantages type, which must be one of \texttt{Selected} (each nation may choose an advantage), \texttt{Fixed} (the standard advantage types are @@ -352,21 +352,22 @@ you have installed a modified copy of FreeCol's data files. European colonial nations (normally the classic four: Dutch, English, French, Spanish). \item\verb$--font FONTSPEC$ Override the default font with a Java -font specifier (e.g. Arial-BOLD-12). + font specifier (e.g. Arial-BOLD-12). \item\verb$--full-screen$ Run FreeCol in full screen mode. \item\verb$--load-savegame SAVEGAME_FILE$ Load the given - savegame. This is particularly useful in combination with the client + savegame. This is particularly useful in combination with the client option \hyperlink{show savegame settings}{show savegame settings}. \item\verb$--log-file FILE$ Override the location of the log file. \item\verb$--name NAME$ Specify a player name. \item\verb$--no-intro$ Skip the introductory video. -\item\verb$--no-sound$ Run FreeCol without sound. Note that the game -does not yet contain any music, so the only sounds you will hear will -be special effects. +\item\verb$--no-sound$ Run FreeCol without sound. Note that the game + does not yet contain background music, so the only sounds you will + hear will be special effects. +\item\verb$--no-splash$ Skip the splash screen. \item\verb$--server PORT$ Start a stand-alone server on the specified -port. If you don't know what that means, you will not need the option. + port. \item\verb$--server-help$ Display a help screen for the more advanced -server options. + server options. \item\verb$--splash FILE$ Specify the location of the splash screen file. \item\verb$--timeout TIMEOUT$ Specifies the number of seconds the server should wait for a player to answer a question (e.g. demands @@ -378,20 +379,20 @@ server options. exist this option will be ignored. \item\verb$--user-config-directory DIRECTORY$ Use the given directory instead of your default FreeCol user configuration directory to load - client and custom options. You can use this in order to run the + client and custom options. You can use this in order to run the game from a USB stick\index{USB stick}, for example. Please note that specifying a client options file on the command line will override the options directory. If the specified directory does not exist this option will be ignored. \item\verb$--user-data-directory DIRECTORY$ Use the given directory instead of your default FreeCol user data directory to load and save - games, and user mods. You can use this in order to run the - game from a USB stick\index{USB stick}, for example. Please note + games, and user mods. You can use this in order to run the + game from a USB stick\index{USB stick}, for example. Please note that specifying a save game file on the command line will override the save game directory. If the specified directory does not exist FreeCol will exit. \item\verb$--windowed[[=]WIDTHxHEIGHT]$ Run FreeCol in windowed mode, - and optionally explicitly set the window width and height. If the + and optionally explicitly set the window width and height. If the size is not specified FreeCol will attempt to use as much space as possible without overlapping menu bars et al. Window size determination is not always correct for all combinations of diff --git a/src/net/sf/freecol/FreeCol.java b/src/net/sf/freecol/FreeCol.java index 5cf7e19dd..aef00ed60 100644 --- a/src/net/sf/freecol/FreeCol.java +++ b/src/net/sf/freecol/FreeCol.java @@ -22,16 +22,23 @@ package net.sf.freecol; import java.awt.Dimension; import java.io.File; import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; import java.io.IOException; import java.lang.Thread.UncaughtExceptionHandler; import java.net.InetAddress; +import java.net.JarURLConnection; import java.net.URL; import java.net.JarURLConnection; import java.util.Locale; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.zip.ZipEntry; import net.sf.freecol.client.ClientOptions; import net.sf.freecol.client.FreeColClient; @@ -125,7 +132,7 @@ public final class FreeCol { private static final String JAVA_VERSION_MIN = "1.7"; private static final int MEMORY_MIN = 128; // Mbytes private static final int PORT_DEFAULT = 3541; - private static final String SPLASH_FILE_DEFAULT = "splash.jpg"; + private static final String SPLASH_DEFAULT = "splash.jpg"; private static final String TC_DEFAULT = "freecol"; public static final int TIMEOUT_DEFAULT = 60; // 1 minute public static final int TIMEOUT_MIN = 10; // 10s @@ -174,8 +181,8 @@ public final class FreeCol { private static int serverPort = -1; private static String serverName = null; - /** Where the splash file lives. */ - private static String splashFilename = SPLASH_FILE_DEFAULT; + /** A stream to get the splash image from. */ + private static InputStream splashStream; /** The TotalConversion / ruleset in play, defaults to "freecol". */ private static String tc = null; @@ -202,13 +209,30 @@ public final class FreeCol { */ public static void main(String[] args) { freeColRevision = FREECOL_VERSION; + JarURLConnection juc; try { - String revision = readVersion(FreeCol.class); - if (revision != null) { - freeColRevision += " (Revision: " + revision + ")"; + juc = getJarURLConnection(FreeCol.class); + } catch (IOException ioe) { + juc = null; + System.err.println("Unable to open class jar: " + + ioe.getMessage()); + } + if (juc != null) { + try { + String revision = readVersion(juc); + if (revision != null) { + freeColRevision += " (Revision: " + revision + ")"; + } + } catch (Exception e) { + System.err.println("Unable to load Manifest: " + + e.getMessage()); + } + try { + splashStream = getDefaultSplashStream(juc); + } catch (Exception e) { + System.err.println("Unable to open default splash: " + + e.getMessage()); } - } catch (Exception e) { - System.err.println("Unable to load Manifest: " + e.getMessage()); } // Java bug #7075600 causes BR#2554. The workaround is to set @@ -316,18 +340,43 @@ public final class FreeCol { /** - * Extract the package version from the class. + * Get the JarURLConnection from a class. * - * @param c The Class to extract from. - * @return A value of the package version attribute. + * @return The JarURLConnection. */ - private static String readVersion(Class c) throws IOException { + private static JarURLConnection getJarURLConnection(Class c) throws IOException { String resourceName = "/" + c.getName().replace('.', '/') + ".class"; URL url = c.getResource(resourceName); - Manifest mf = ((JarURLConnection)url.openConnection()).getManifest(); - return mf.getMainAttributes().getValue("Package-Version"); + return (JarURLConnection)url.openConnection(); + } + + /** + * Extract the package version from the class. + * + * @param juc The JarURLConnection to extract from. + * @return A value of the package version attribute. + */ + private static String readVersion(JarURLConnection juc) throws IOException { + Manifest mf = juc.getManifest(); + return (mf == null) ? null + : mf.getMainAttributes().getValue("Package-Version"); } + /** + * Get a stream for the default splash file. + * + * Note: Not bothering to check for nulls as this is called in try + * block that ignores all exceptions. + * + * @param juc The JarURLConnection to extract from. + * @return A suitable InputStream, or null on error. + */ + private static InputStream getDefaultSplashStream(JarURLConnection juc) throws IOException { + JarFile jf = juc.getJarFile(); + ZipEntry ze = jf.getEntry(SPLASH_DEFAULT); + return jf.getInputStream(ze); + } + /** * Exit printing fatal error message. * @@ -517,6 +566,9 @@ public final class FreeCol { options.addOption(OptionBuilder.withLongOpt("no-sound") .withDescription(Messages.message("cli.no-sound")) .create()); + options.addOption(OptionBuilder.withLongOpt("no-splash") + .withDescription(Messages.message("cli.no-splash")) + .create()); options.addOption(OptionBuilder.withLongOpt("private") .withDescription(Messages.message("cli.private")) .create()); @@ -722,6 +774,9 @@ public final class FreeCol { if (line.hasOption("no-sound")) { sound = false; } + if (line.hasOption("no-splash")) { + splashStream = null; + } if (line.hasOption("private")) { publicServer = false; @@ -744,7 +799,14 @@ public final class FreeCol { } if (line.hasOption("splash")) { - splashFilename = line.getOptionValue("splash"); + String splash = line.getOptionValue("splash"); + try { + FileInputStream fis = new FileInputStream(splash); + splashStream = fis; + } catch (FileNotFoundException fnfe) { + gripe(StringTemplate.template("cli.error.splash") + .addName("%name%", splash)); + } } if (line.hasOption("tc")) { @@ -1312,7 +1374,7 @@ public final class FreeCol { // savegame was specified on command line } final FreeColClient freeColClient - = new FreeColClient(splashFilename, fontName, guiScale, headless); + = new FreeColClient(splashStream, fontName, guiScale, headless); freeColClient.startClient(windowSize, userMsg, sound, introVideo, savegame, spec); } diff --git a/src/net/sf/freecol/client/FreeColClient.java b/src/net/sf/freecol/client/FreeColClient.java index f1d6ace99..bd216212f 100644 --- a/src/net/sf/freecol/client/FreeColClient.java +++ b/src/net/sf/freecol/client/FreeColClient.java @@ -21,6 +21,7 @@ package net.sf.freecol.client; import java.awt.Dimension; import java.io.File; +import java.io.InputStream; import java.io.IOException; import java.util.Collections; import java.util.List; @@ -132,21 +133,21 @@ public final class FreeColClient { private final boolean headless; - public FreeColClient(final String splashFilename, + public FreeColClient(final InputStream splashStream, final String fontName) { - this(splashFilename, fontName, FreeCol.GUI_SCALE_DEFAULT, true); + this(splashStream, fontName, FreeCol.GUI_SCALE_DEFAULT, true); } /** * Creates a new FreeColClient. Creates the control * objects. * - * @param splashFilename The name of the splash image. + * @param splashStream A stream to read the splash image from. * @param fontName An optional override of the main font. * @param scale The scale factor for gui elements. * @param headless Run in headless mode. */ - public FreeColClient(final String splashFilename, final String fontName, + public FreeColClient(final InputStream splashStream, final String fontName, final float scale, boolean headless) { mapEditor = false; this.headless = headless @@ -161,7 +162,7 @@ public final class FreeColClient { // Get the splash screen up early on to show activity. gui = (this.headless) ? new GUI(this, scale) : new SwingGUI(this, scale); - gui.displaySplashScreen(splashFilename); + gui.displaySplashScreen(splashStream); // Look for base data directory. Failure is fatal. File baseDirectory = FreeColDirectories.getBaseDirectory(); diff --git a/src/net/sf/freecol/client/gui/GUI.java b/src/net/sf/freecol/client/gui/GUI.java index 265a17679..4432ccb0f 100644 --- a/src/net/sf/freecol/client/gui/GUI.java +++ b/src/net/sf/freecol/client/gui/GUI.java @@ -27,6 +27,7 @@ import java.awt.Rectangle; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -177,9 +178,9 @@ public class GUI { /** * Display the splash screen. * - * @param splashFilename The name of the file to find the image in. + * @param splashStream A stream to find the image in. */ - public void displaySplashScreen(final String splashFilename) { + public void displaySplashScreen(final InputStream splashStream) { } /** diff --git a/src/net/sf/freecol/client/gui/SwingGUI.java b/src/net/sf/freecol/client/gui/SwingGUI.java index e2423a592..d971df40a 100644 --- a/src/net/sf/freecol/client/gui/SwingGUI.java +++ b/src/net/sf/freecol/client/gui/SwingGUI.java @@ -30,21 +30,23 @@ import java.awt.Image; import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; -import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; +import java.io.InputStream; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; +import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JWindow; @@ -217,15 +219,14 @@ public class SwingGUI extends GUI { /** * Display the splash screen. * - * @param splashFilename The name of the file to find the image in. + * @param splashStream A stream to read the splash image from. */ @Override - public void displaySplashScreen(final String splashFilename) { + public void displaySplashScreen(final InputStream splashStream) { splash = null; - if (splashFilename == null) - return; + if (splashStream == null) return; try { - Image im = Toolkit.getDefaultToolkit().getImage(splashFilename); + BufferedImage im = ImageIO.read(splashStream); splash = new JWindow(graphicsDevice.getDefaultConfiguration()); splash.getContentPane().add(new JLabel(new ImageIcon(im))); splash.pack();