Follow-up to #126.

- Fix the XDG directory flag that got removed with JarSplice. To enable XDG directories, set the 'Use-XDG' property in either build file to 'true'.
- Always re-build jars in the Gradle script (disable "up to date" for the task).
- Delete JarSplicePlus.jar since it's no longer being used.

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2015-08-27 14:14:04 -05:00
parent fdf8e3caf3
commit b54886a379
9 changed files with 132 additions and 83 deletions

View File

@ -40,22 +40,19 @@ the song menu.
## Building ## Building
opsu! is distributed as both a Maven and Gradle project. opsu! is distributed as both a Maven and Gradle project.
### Maven
Maven builds are built to the `target` directory.
* To run the project, execute the Maven goal `compile`.
* To create a single executable JAR file, execute the Maven goal `package -Djar`.
This will compile a jar to `target/opsu-${version}.jar` with the libraries,
resources and natives packed inside the jar.
### Gradle ### Gradle
Gradle builds are built to the `build` directory. Gradle builds are built to the `build` directory.
* To run the project, execute the Gradle task `run`. * To run the project, execute the Gradle task `run`.
* To create a single executable JAR file, execute the Gradle task * To create a single executable JAR file, execute the Gradle task `build`.
`build`. This will compile a jar to `build/libs/opsu-${version}.jar` with This will compile a jar to `build/libs/opsu-${version}.jar` with the libraries,
the libraries, resources and natives packed inside the jar. resources and natives packed inside the jar.
### Maven
Maven builds are built to the `target` directory.
* To run the project, execute the Maven goal `compile exec:exec`.
* To create a single executable JAR file, execute the Maven goal
`install -Djar`. This will link the LWJGL native libraries using a
[modified version](https://github.com/itdelatrisu/JarSplicePlus) of
[JarSplice](http://ninjacave.com/jarsplice), which is included in the
`tools` directory in both its original and modified forms. The resulting
file will be located in `target/opsu-${version}-runnable.jar`.
## Credits ## Credits
This software was created by Jeffrey Han This software was created by Jeffrey Han

View File

@ -12,6 +12,8 @@ version = '0.10.1'
mainClassName = 'itdelatrisu.opsu.Opsu' mainClassName = 'itdelatrisu.opsu.Opsu'
buildDir = new File(rootProject.projectDir, "build/") buildDir = new File(rootProject.projectDir, "build/")
def useXDG = 'false'
sourceCompatibility = 1.7 sourceCompatibility = 1.7
targetCompatibility = 1.7 targetCompatibility = 1.7
@ -43,8 +45,6 @@ dependencies {
compile 'org.apache.commons:commons-compress:1.9' compile 'org.apache.commons:commons-compress:1.9'
compile 'org.tukaani:xz:1.5' compile 'org.tukaani:xz:1.5'
compile 'com.github.jponge:lzma-java:1.3' compile 'com.github.jponge:lzma-java:1.3'
} }
def nativePlatforms = ['windows', 'linux', 'osx'] def nativePlatforms = ['windows', 'linux', 'osx']
@ -84,7 +84,8 @@ jar {
manifest { manifest {
attributes 'Implementation-Title': 'opsu!', attributes 'Implementation-Title': 'opsu!',
'Implementation-Version': version, 'Implementation-Version': version,
'Main-Class': mainClassName 'Main-Class': mainClassName,
'Use-XDG': useXDG
} }
duplicatesStrategy = DuplicatesStrategy.EXCLUDE duplicatesStrategy = DuplicatesStrategy.EXCLUDE
@ -92,6 +93,8 @@ jar {
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
exclude '**/Thumbs.db' exclude '**/Thumbs.db'
outputs.upToDateWhen { false }
} }
run { run {

View File

@ -9,6 +9,7 @@
<timestamp>${maven.build.timestamp}</timestamp> <timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format> <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
<mainClassName>itdelatrisu.opsu.Opsu</mainClassName> <mainClassName>itdelatrisu.opsu.Opsu</mainClassName>
<useXDG>false</useXDG>
</properties> </properties>
<build> <build>
<sourceDirectory>src</sourceDirectory> <sourceDirectory>src</sourceDirectory>
@ -107,7 +108,10 @@
</filters> </filters>
<transformers> <transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${mainClassName}</mainClass> <manifestEntries>
<Main-Class>${mainClassName}</Main-Class>
<Use-XDG>${useXDG}</Use-XDG>
</manifestEntries>
</transformer> </transformer>
</transformers> </transformers>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>

View File

@ -23,9 +23,6 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.CodeSource;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
@ -47,41 +44,32 @@ public class NativeLoader {
if (!NATIVE_DIR.exists()) if (!NATIVE_DIR.exists())
NATIVE_DIR.mkdir(); NATIVE_DIR.mkdir();
CodeSource src = NativeLoader.class.getProtectionDomain().getCodeSource(); JarFile jarFile = Utils.getJarFile();
if (src != null) { if (jarFile == null)
URI jar = null; return;
try {
jar = src.getLocation().toURI(); Enumeration<JarEntry> entries = jarFile.entries();
} catch (URISyntaxException e) { while (entries.hasMoreElements()) {
e.printStackTrace(); JarEntry e = entries.nextElement();
return; if (e == null)
break;
File f = new File(NATIVE_DIR, e.getName());
if (isNativeFile(e.getName()) && !e.isDirectory() && e.getName().indexOf('/') == -1 && !f.exists()) {
InputStream in = jarFile.getInputStream(jarFile.getEntry(e.getName()));
OutputStream out = new FileOutputStream(f);
byte[] buffer = new byte[65536];
int bufferSize;
while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1)
out.write(buffer, 0, bufferSize);
in.close();
out.close();
} }
JarFile jarFile = new JarFile(new File(jar), false);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry e = entries.nextElement();
if (e == null)
break;
File f = new File(NATIVE_DIR, e.getName());
if (isNativeFile(e.getName()) && !e.isDirectory() && e.getName().indexOf('/') == -1 && !f.exists()) {
InputStream in = jarFile.getInputStream(jarFile.getEntry(e.getName()));
OutputStream out = new FileOutputStream(f);
byte[] buffer = new byte[65536];
int bufferSize;
while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1)
out.write(buffer, 0, bufferSize);
in.close();
out.close();
}
}
jarFile.close();
} }
jarFile.close();
} }
/** /**

View File

@ -18,12 +18,16 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController; import java.io.File;
import itdelatrisu.opsu.db.DBController; import java.io.FileNotFoundException;
import itdelatrisu.opsu.downloads.DownloadList; import java.io.FileOutputStream;
import itdelatrisu.opsu.downloads.Updater; import java.io.IOException;
import itdelatrisu.opsu.states.*; import java.io.PrintStream;
import itdelatrisu.opsu.ui.UI; import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import org.newdawn.slick.Color; import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer; import org.newdawn.slick.GameContainer;
import org.newdawn.slick.SlickException; import org.newdawn.slick.SlickException;
@ -35,11 +39,20 @@ import org.newdawn.slick.util.FileSystemLocation;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
import java.io.*; import itdelatrisu.opsu.audio.MusicController;
import java.lang.reflect.Field; import itdelatrisu.opsu.db.DBController;
import java.net.InetAddress; import itdelatrisu.opsu.downloads.DownloadList;
import java.net.ServerSocket; import itdelatrisu.opsu.downloads.Updater;
import java.net.UnknownHostException; import itdelatrisu.opsu.states.ButtonMenu;
import itdelatrisu.opsu.states.DownloadsMenu;
import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.states.GamePauseMenu;
import itdelatrisu.opsu.states.GameRanking;
import itdelatrisu.opsu.states.MainMenu;
import itdelatrisu.opsu.states.OptionsMenu;
import itdelatrisu.opsu.states.SongMenu;
import itdelatrisu.opsu.states.Splash;
import itdelatrisu.opsu.ui.UI;
/** /**
* Main class. * Main class.
@ -143,7 +156,6 @@ public class Opsu extends StateBasedGame {
Log.warn("Failed to set 'sys_paths' field.", e); Log.warn("Failed to set 'sys_paths' field.", e);
} }
// set the resource paths // set the resource paths
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/"))); ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));

View File

@ -18,13 +18,6 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.skins.Skin;
import itdelatrisu.opsu.skins.SkinLoader;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
@ -38,6 +31,9 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import org.newdawn.slick.GameContainer; import org.newdawn.slick.GameContainer;
@ -48,10 +44,20 @@ import org.newdawn.slick.util.FileSystemLocation;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader; import org.newdawn.slick.util.ResourceLoader;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.skins.Skin;
import itdelatrisu.opsu.skins.SkinLoader;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI;
/** /**
* Handles all user options. * Handles all user options.
*/ */
public class Options { public class Options {
/** Whether to use XDG directories. */
private static final boolean USE_XDG = checkXDGFlag();
/** The config directory. */ /** The config directory. */
private static final File CONFIG_DIR = getXDGBaseDir("XDG_CONFIG_HOME", ".config"); private static final File CONFIG_DIR = getXDGBaseDir("XDG_CONFIG_HOME", ".config");
@ -120,15 +126,35 @@ public class Options {
/** Port binding. */ /** Port binding. */
private static int port = 49250; private static int port = 49250;
/**
* Returns whether the XDG flag in the manifest (if any) is set to "true".
* @return true if XDG directories are enabled, false otherwise
*/
private static boolean checkXDGFlag() {
JarFile jarFile = Utils.getJarFile();
if (jarFile == null)
return false;
try {
Manifest manifest = jarFile.getManifest();
if (manifest == null)
return false;
Attributes attributes = manifest.getMainAttributes();
String value = attributes.getValue("Use-XDG");
return (value != null && value.equalsIgnoreCase("true"));
} catch (IOException e) {
return false;
}
}
/** /**
* Returns the directory based on the XDG base directory specification for * Returns the directory based on the XDG base directory specification for
* Unix-like operating systems, only if the system property "XDG" has been defined. * Unix-like operating systems, only if the "XDG" flag is enabled.
* @param env the environment variable to check (XDG_*_*) * @param env the environment variable to check (XDG_*_*)
* @param fallback the fallback directory relative to ~home * @param fallback the fallback directory relative to ~home
* @return the XDG base directory, or the working directory if unavailable * @return the XDG base directory, or the working directory if unavailable
*/ */
private static File getXDGBaseDir(String env, String fallback) { private static File getXDGBaseDir(String env, String fallback) {
if (System.getProperty("XDG") == null) if (!USE_XDG)
return new File("./"); return new File("./");
String OS = System.getProperty("os.name").toLowerCase(); String OS = System.getProperty("os.name").toLowerCase();

View File

@ -18,15 +18,6 @@
package itdelatrisu.opsu; package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.DownloadNode;
import itdelatrisu.opsu.replay.PlaybackSpeed;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -48,6 +39,7 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Scanner; import java.util.Scanner;
import java.util.jar.JarFile;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -66,6 +58,15 @@ import org.newdawn.slick.util.Log;
import com.sun.jna.platform.FileUtils; import com.sun.jna.platform.FileUtils;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.DownloadNode;
import itdelatrisu.opsu.replay.PlaybackSpeed;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI;
/** /**
* Contains miscellaneous utilities. * Contains miscellaneous utilities.
*/ */
@ -564,8 +565,25 @@ public class Utils {
return Opsu.class.getResource(String.format("%s.class", Opsu.class.getSimpleName())).toString().startsWith("jar:"); return Opsu.class.getResource(String.format("%s.class", Opsu.class.getSimpleName())).toString().startsWith("jar:");
} }
/**
* Returns the JarFile for the application.
* @return the JAR file, or null if it could not be determined
*/
public static JarFile getJarFile() {
if (!isJarRunning())
return null;
try {
return new JarFile(new File(Opsu.class.getProtectionDomain().getCodeSource().getLocation().toURI()), false);
} catch (URISyntaxException | IOException e) {
Log.error("Could not determine the JAR file.", e);
return null;
}
}
/** /**
* Returns the directory where the application is being run. * Returns the directory where the application is being run.
* @return the directory, or null if it could not be determined
*/ */
public static File getRunningDirectory() { public static File getRunningDirectory() {
try { try {

View File

@ -150,6 +150,7 @@ public abstract class Curve {
* @param i the control point index * @param i the control point index
*/ */
public float getY(int i) { return (i == 0) ? y : sliderY[i - 1]; } public float getY(int i) { return (i == 0) ? y : sliderY[i - 1]; }
/** /**
* Discards the slider cache (only used for mmsliders). * Discards the slider cache (only used for mmsliders).
*/ */

Binary file not shown.