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/
/screenshot/
/songs/
/.opsu_tmp/
/Screenshots/
/Skins/
/Songs/
/.opsu.log
/.opsu.cfg

View File

@ -40,6 +40,7 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;
import org.newdawn.slick.state.transition.FadeInTransition;
import org.newdawn.slick.state.transition.FadeOutTransition;
import org.newdawn.slick.util.ClasspathLocation;
import org.newdawn.slick.util.DefaultLogSystem;
import org.newdawn.slick.util.FileSystemLocation;
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
// 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/")));
// start the game

View File

@ -131,21 +131,30 @@ public class Utils {
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()) {
// 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");
cursor = new Image("cursor.png");
cursorTrail = new Image("cursortrail.png");
} catch (Exception e) {
// optional
}
}
if (cursorMiddle == null) {
// load old cursor type
cursor = new Image("cursor2.png");
cursorTrail = new Image("cursortrail2.png");
// default is stored as *2.png, but load skin cursor if it exists
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

View File

@ -652,8 +652,8 @@ public class Game extends BasicGameState {
if (osu == null || osu.objects == null)
throw new RuntimeException("Running game with no OsuFile loaded.");
// grab the mouse
container.setMouseGrabbed(true);
// grab the mouse (not working for touchscreen)
// container.setMouseGrabbed(true);
// restart the game
if (restart != RESTART_FALSE) {
@ -728,11 +728,11 @@ public class Game extends BasicGameState {
}
}
@Override
public void leave(GameContainer container, StateBasedGame game)
throws SlickException {
container.setMouseGrabbed(false);
}
// @Override
// public void leave(GameContainer container, StateBasedGame game)
// throws SlickException {
// container.setMouseGrabbed(false);
// }
/**
* 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.
*/
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).
*/
public static final File SCREENSHOT_DIR = new File("screenshot/");
public static final File SCREENSHOT_DIR = new File("Screenshots/");
/**
* File for logging errors.
*/
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).
*/
private static final String[] BEATMAP_DIRS = {
"C:/Program Files (x86)/osu!/Songs/",
"C:/Program Files/osu!/Songs/",
"songs/"
"Songs/"
};
/**
@ -78,9 +83,9 @@ public class Options extends BasicGameState {
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.
@ -611,6 +616,7 @@ public class Options extends BasicGameState {
* Returns the current beatmap directory.
* If invalid, this will attempt to search for the directory,
* and if nothing found, will create one.
* @return the beatmap directory
*/
public static File getBeatmapDir() {
if (beatmapDir != null && beatmapDir.isDirectory())
@ -626,19 +632,31 @@ public class Options extends BasicGameState {
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.
*/
public static void parseOptions() {
// if no config file, use default settings
File file = new File(OPTIONS_FILE);
if (!file.isFile()) {
if (!OPTIONS_FILE.isFile()) {
saveOptions();
return;
}
try (BufferedReader in = new BufferedReader(new FileReader(file))) {
try (BufferedReader in = new BufferedReader(new FileReader(OPTIONS_FILE))) {
String line;
String name, value;
int i;
@ -655,6 +673,9 @@ public class Options extends BasicGameState {
case "BeatmapDirectory":
beatmapDir = new File(value);
break;
case "Skin":
skinDir = new File(value);
break;
case "ScreenResolution":
i = Integer.parseInt(value);
if (i >= 0 && i < resolutions.length)
@ -708,7 +729,7 @@ public class Options extends BasicGameState {
}
}
} 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) {
Log.warn("Format error in options file.", e);
return;
@ -732,10 +753,10 @@ public class Options extends BasicGameState {
writer.newLine();
// options
if (beatmapDir != null) {
writer.write(String.format("BeatmapDirectory = %s", beatmapDir.getAbsolutePath()));
writer.newLine();
}
writer.write(String.format("BeatmapDirectory = %s", getBeatmapDir().getAbsolutePath()));
writer.newLine();
writer.write(String.format("Skin = %s", getSkinDir().getAbsolutePath()));
writer.newLine();
writer.write(String.format("ScreenResolution = %d", resolutionIndex));
writer.newLine();
// writer.write(String.format("Fullscreen = %b", fullscreen));
@ -762,7 +783,7 @@ public class Options extends BasicGameState {
writer.newLine();
writer.close();
} 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);
}
}
}