Added initial support for loading user skins.

- "Skins" directory is created in the root folder, and reads files directly from there (for now).  NOT ALL FILES ARE SUPPORTED.
- To change the path (e.g. to an installed skin), edit the path in the configuration file.

Other changes:
- Renamed some files: directories now begin with a capital letter (to match osu! naming), and '.osu_tmp' renamed to '.opsu_tmp'.
- Disabled mouse grabbing, as this does not seem to work properly for touchscreen devices. (partial revert of ab487c5)

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
Jeffrey Han 2014-07-02 01:53:42 -04:00
parent ab487c5e80
commit bcd0c23961
5 changed files with 68 additions and 32 deletions

7
.gitignore vendored
View File

@ -1,6 +1,7 @@
/.osu_tmp/ /.opsu_tmp/
/screenshot/ /Screenshots/
/songs/ /Skins/
/Songs/
/.opsu.log /.opsu.log
/.opsu.cfg /.opsu.cfg

View File

@ -40,6 +40,7 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.state.transition.FadeInTransition; import org.newdawn.slick.state.transition.FadeInTransition;
import org.newdawn.slick.state.transition.FadeOutTransition; import org.newdawn.slick.state.transition.FadeOutTransition;
import org.newdawn.slick.util.ClasspathLocation;
import org.newdawn.slick.util.DefaultLogSystem; import org.newdawn.slick.util.DefaultLogSystem;
import org.newdawn.slick.util.FileSystemLocation; import org.newdawn.slick.util.FileSystemLocation;
import org.newdawn.slick.util.Log; import org.newdawn.slick.util.Log;
@ -117,7 +118,11 @@ public class Opsu extends StateBasedGame {
// set path for lwjgl natives - NOT NEEDED if using JarSplice // set path for lwjgl natives - NOT NEEDED if using JarSplice
// System.setProperty("org.lwjgl.librarypath", new File("native").getAbsolutePath()); // System.setProperty("org.lwjgl.librarypath", new File("native").getAbsolutePath());
// set the resource path // set the resource paths
ResourceLoader.removeAllResourceLocations();
ResourceLoader.addResourceLocation(new FileSystemLocation(Options.getSkinDir()));
ResourceLoader.addResourceLocation(new ClasspathLocation());
ResourceLoader.addResourceLocation(new FileSystemLocation(new File(".")));
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/"))); ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
// start the game // start the game

View File

@ -131,21 +131,30 @@ public class Utils {
Log.error("Failed to set the cursor.", e); Log.error("Failed to set the cursor.", e);
} }
// load cursor images // load cursor images (TODO: cleanup)
boolean skinCursor = new File(Options.getSkinDir(), "cursor.png").isFile();
if (Options.isNewCursorEnabled()) { if (Options.isNewCursorEnabled()) {
// load new cursor type // load new cursor type
try { // if skin cursor exists but middle part does not, don't load default middle
if (skinCursor && !new File(Options.getSkinDir(), "cursormiddle.png").isFile())
;
else {
cursorMiddle = new Image("cursormiddle.png"); cursorMiddle = new Image("cursormiddle.png");
cursor = new Image("cursor.png"); cursor = new Image("cursor.png");
cursorTrail = new Image("cursortrail.png"); cursorTrail = new Image("cursortrail.png");
} catch (Exception e) {
// optional
} }
} }
if (cursorMiddle == null) { if (cursorMiddle == null) {
// load old cursor type // load old cursor type
cursor = new Image("cursor2.png"); // default is stored as *2.png, but load skin cursor if it exists
cursorTrail = new Image("cursortrail2.png"); if (skinCursor)
cursor = new Image("cursor.png");
else
cursor = new Image("cursor2.png");
if (new File(Options.getSkinDir(), "cursortrail.png").isFile())
cursorTrail = new Image("cursortrail.png");
else
cursorTrail = new Image("cursortrail2.png");
} }
// create fonts // create fonts

View File

@ -652,8 +652,8 @@ public class Game extends BasicGameState {
if (osu == null || osu.objects == null) if (osu == null || osu.objects == null)
throw new RuntimeException("Running game with no OsuFile loaded."); throw new RuntimeException("Running game with no OsuFile loaded.");
// grab the mouse // grab the mouse (not working for touchscreen)
container.setMouseGrabbed(true); // container.setMouseGrabbed(true);
// restart the game // restart the game
if (restart != RESTART_FALSE) { if (restart != RESTART_FALSE) {
@ -728,11 +728,11 @@ public class Game extends BasicGameState {
} }
} }
@Override // @Override
public void leave(GameContainer container, StateBasedGame game) // public void leave(GameContainer container, StateBasedGame game)
throws SlickException { // throws SlickException {
container.setMouseGrabbed(false); // container.setMouseGrabbed(false);
} // }
/** /**
* Skips the beginning of a track. * Skips the beginning of a track.

View File

@ -51,25 +51,30 @@ public class Options extends BasicGameState {
/** /**
* Temporary folder for file conversions, auto-deleted upon successful exit. * Temporary folder for file conversions, auto-deleted upon successful exit.
*/ */
public static final File TMP_DIR = new File(".osu_tmp/"); public static final File TMP_DIR = new File(".opsu_tmp/");
/** /**
* Directory for screenshots (created when needed). * Directory for screenshots (created when needed).
*/ */
public static final File SCREENSHOT_DIR = new File("screenshot/"); public static final File SCREENSHOT_DIR = new File("Screenshots/");
/** /**
* File for logging errors. * File for logging errors.
*/ */
public static final File LOG_FILE = new File(".opsu.log"); public static final File LOG_FILE = new File(".opsu.log");
/**
* File for storing user options.
*/
private static final File OPTIONS_FILE = new File(".opsu.cfg");
/** /**
* Beatmap directories (where to search for files). * Beatmap directories (where to search for files).
*/ */
private static final String[] BEATMAP_DIRS = { private static final String[] BEATMAP_DIRS = {
"C:/Program Files (x86)/osu!/Songs/", "C:/Program Files (x86)/osu!/Songs/",
"C:/Program Files/osu!/Songs/", "C:/Program Files/osu!/Songs/",
"songs/" "Songs/"
}; };
/** /**
@ -78,9 +83,9 @@ public class Options extends BasicGameState {
private static File beatmapDir; private static File beatmapDir;
/** /**
* File for storing user options. * The current skin directory (for user skins).
*/ */
private static final String OPTIONS_FILE = ".opsu.cfg"; private static File skinDir;
/** /**
* Game mods. * Game mods.
@ -611,6 +616,7 @@ public class Options extends BasicGameState {
* Returns the current beatmap directory. * Returns the current beatmap directory.
* If invalid, this will attempt to search for the directory, * If invalid, this will attempt to search for the directory,
* and if nothing found, will create one. * and if nothing found, will create one.
* @return the beatmap directory
*/ */
public static File getBeatmapDir() { public static File getBeatmapDir() {
if (beatmapDir != null && beatmapDir.isDirectory()) if (beatmapDir != null && beatmapDir.isDirectory())
@ -626,19 +632,31 @@ public class Options extends BasicGameState {
return beatmapDir; return beatmapDir;
} }
/**
* Returns the current skin directory.
* If invalid, this will create a "Skins" folder in the root directory.
* @return the skin directory
*/
public static File getSkinDir() {
if (skinDir != null && skinDir.isDirectory())
return skinDir;
skinDir = new File("Skins/");
skinDir.mkdir();
return skinDir;
}
/** /**
* Reads user options from the options file, if it exists. * Reads user options from the options file, if it exists.
*/ */
public static void parseOptions() { public static void parseOptions() {
// if no config file, use default settings // if no config file, use default settings
File file = new File(OPTIONS_FILE); if (!OPTIONS_FILE.isFile()) {
if (!file.isFile()) {
saveOptions(); saveOptions();
return; return;
} }
try (BufferedReader in = new BufferedReader(new FileReader(file))) { try (BufferedReader in = new BufferedReader(new FileReader(OPTIONS_FILE))) {
String line; String line;
String name, value; String name, value;
int i; int i;
@ -655,6 +673,9 @@ public class Options extends BasicGameState {
case "BeatmapDirectory": case "BeatmapDirectory":
beatmapDir = new File(value); beatmapDir = new File(value);
break; break;
case "Skin":
skinDir = new File(value);
break;
case "ScreenResolution": case "ScreenResolution":
i = Integer.parseInt(value); i = Integer.parseInt(value);
if (i >= 0 && i < resolutions.length) if (i >= 0 && i < resolutions.length)
@ -708,7 +729,7 @@ public class Options extends BasicGameState {
} }
} }
} catch (IOException e) { } catch (IOException e) {
Log.error(String.format("Failed to read file '%s'.", OPTIONS_FILE), e); Log.error(String.format("Failed to read file '%s'.", OPTIONS_FILE.getAbsolutePath()), e);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Log.warn("Format error in options file.", e); Log.warn("Format error in options file.", e);
return; return;
@ -732,10 +753,10 @@ public class Options extends BasicGameState {
writer.newLine(); writer.newLine();
// options // options
if (beatmapDir != null) { writer.write(String.format("BeatmapDirectory = %s", getBeatmapDir().getAbsolutePath()));
writer.write(String.format("BeatmapDirectory = %s", beatmapDir.getAbsolutePath())); writer.newLine();
writer.newLine(); writer.write(String.format("Skin = %s", getSkinDir().getAbsolutePath()));
} writer.newLine();
writer.write(String.format("ScreenResolution = %d", resolutionIndex)); writer.write(String.format("ScreenResolution = %d", resolutionIndex));
writer.newLine(); writer.newLine();
// writer.write(String.format("Fullscreen = %b", fullscreen)); // writer.write(String.format("Fullscreen = %b", fullscreen));
@ -762,7 +783,7 @@ public class Options extends BasicGameState {
writer.newLine(); writer.newLine();
writer.close(); writer.close();
} catch (IOException e) { } catch (IOException e) {
Log.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE), e); Log.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath()), e);
} }
} }
} }