Merge branch 'master' into replaystuff

# Conflicts:
#	src/itdelatrisu/opsu/states/Game.java
This commit is contained in:
yugecin
2017-12-16 16:35:11 +01:00
131 changed files with 2595 additions and 3598 deletions

View File

@@ -24,7 +24,6 @@ import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.objects.curves.Curve;
import itdelatrisu.opsu.replay.Replay;
import itdelatrisu.opsu.replay.ReplayFrame;
@@ -42,25 +41,17 @@ import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.utils.SlickUtil;
import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Holds game data and renders all related elements.
*/
public class GameData {
@Inject
private Configuration config;
@Inject
private InstanceContainer instanceContainer;
/** Delta multiplier for steady HP drain. */
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;
@@ -354,17 +345,10 @@ public class GameData {
/** Whether this object is used for gameplay (true) or score viewing (false). */
private boolean isGameplay;
/** Container dimensions. */
private int width, height;
/**
* Constructor for gameplay.
* @param width container width
* @param height container height
*/
public GameData(int width, int height) {
this.width = width;
this.height = height;
public GameData() {
this.isGameplay = true;
clear();
@@ -375,12 +359,8 @@ public class GameData {
* This will initialize all parameters and images needed for the
* {@link #drawRankingElements(Graphics, Beatmap)} method.
* @param s the ScoreData object
* @param width container width
* @param height container height
*/
public GameData(ScoreData s, int width, int height) {
this.width = width;
this.height = height;
public GameData(ScoreData s) {
this.isGameplay = false;
this.scoreData = s;
@@ -395,8 +375,9 @@ public class GameData {
hitResultCount[HIT_300K] = 0;
hitResultCount[HIT_100K] = s.katu;
hitResultCount[HIT_MISS] = s.miss;
this.replay = (s.replayString == null) ? null :
instanceContainer.injectFields(new Replay(new File(config.replayDir, String.format("%s.osr", s.replayString))));
if (s.replayString != null) {
this.replay = new Replay(new File(config.replayDir, s.replayString + ".osr"));
}
loadImages();
}
@@ -622,6 +603,8 @@ public class GameData {
*/
@SuppressWarnings("deprecation")
public void drawGameElements(Graphics g, boolean breakPeriod, boolean firstObject, float alpha) {
int width = displayContainer.width;
int height = displayContainer.height;
boolean relaxAutoPilot = (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
int margin = (int) (width * 0.008f);
float uiScale = GameImage.getUIscale();
@@ -813,6 +796,9 @@ public class GameData {
* @param beatmap the beatmap
*/
public void drawRankingElements(Graphics g, Beatmap beatmap) {
int width = displayContainer.width;
int height = displayContainer.height;
// TODO Version 2 skins
float rankingHeight = 75;
float scoreTextScale = 1.0f;
@@ -925,7 +911,7 @@ public class GameData {
if (hitResult.hitResultType == HitObjectType.SPINNER && hitResult.result != HIT_MISS) {
Image spinnerOsu = GameImage.SPINNER_OSU.getImage();
spinnerOsu.setAlpha(hitResult.alpha);
spinnerOsu.drawCentered(width / 2, height / 4);
spinnerOsu.drawCentered(displayContainer.width / 2, displayContainer.height / 4);
spinnerOsu.setAlpha(1f);
} else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS &&
// hit lighting
@@ -1199,7 +1185,7 @@ public class GameData {
// combo burst
if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) {
int leftX = 0;
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
int rightX = displayContainer.width - comboBurstImages[comboBurstIndex].getWidth();
if (comboBurstX < leftX) {
comboBurstX += (delta / 2f) * GameImage.getUIscale();
if (comboBurstX > leftX)
@@ -1260,7 +1246,7 @@ public class GameData {
}
comboBurstAlpha = 0.8f;
if ((comboBurstIndex % 2) == 0) {
comboBurstX = width;
comboBurstX = displayContainer.width;
} else {
comboBurstX = comboBurstImages[0].getWidth() * -1;
}
@@ -1603,7 +1589,7 @@ public class GameData {
replay = new Replay();
replay.mode = Beatmap.MODE_OSU;
replay.version = Updater.get().getBuildDate();
replay.version = updater.getBuildDate();
replay.beatmapHash = (beatmap == null) ? "" : beatmap.md5Hash;
replay.playerName = ""; // TODO
replay.replayHash = Long.toString(System.currentTimeMillis()); // TODO

View File

@@ -18,6 +18,7 @@
package itdelatrisu.opsu;
import itdelatrisu.opsu.ui.Colors;
import itdelatrisu.opsu.ui.Fonts;
import java.io.File;
@@ -30,8 +31,7 @@ import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.utils.SlickUtil;
@@ -249,6 +249,16 @@ public enum GameImage {
CONTROL_SLIDER_BALL ("control-sliderball", "png", false, false),
CONTROL_CHECK_ON ("control-check-on", "png", false, false),
CONTROL_CHECK_OFF ("control-check-off", "png", false, false),
MENU_NAV_AUDIO ("menu-nav-audio", "png", false, false),
MENU_NAV_CUSTOM ("menu-nav-custom", "png", false, false),
MENU_NAV_GAMEPLAY ("menu-nav-gameplay", "png", false, false),
MENU_NAV_GENERAL ("menu-nav-general", "png", false, false),
MENU_NAV_GRAPHICS ("menu-nav-graphics", "png", false, false),
MENU_NAV_INPUT ("menu-nav-input", "png", false, false),
MENU_NAV_SKIN ("menu-nav-skin", "png", false, false),
MENU_NAV_ADVANCED ("menu-nav-advanced", "png", false, false),
MENU_NAV_DANCE ("menu-nav-dance", "png", false, false),
MENU_NAV_PIPPI ("menu-nav-pippi", "png", false, false),
VOLUME ("volume-bg", "png", false, false) {
@Override
protected Image process_sub(Image img, int w, int h) {
@@ -733,7 +743,7 @@ public enum GameImage {
String err = String.format("Could not find default image '%s'.", filename);
Log.warn(err);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
}
/**
@@ -776,31 +786,33 @@ public enum GameImage {
* @return an array of the loaded images, or null if not found
*/
private Image[] loadImageArray(File dir) {
if (filenameFormat != null) {
for (String suffix : getSuffixes()) {
List<Image> list = new ArrayList<Image>();
int i = 0;
while (true) {
// look for next image
String filenameFormatted = String.format(filenameFormat + suffix, i++);
String name = getImageFileName(filenameFormatted, dir, type, true);
if (name == null)
break;
if (filenameFormat == null) {
return null;
}
for (String suffix : getSuffixes()) {
List<Image> list = new ArrayList<Image>();
int i = 0;
while (true) {
// look for next image
String filenameFormatted = String.format(filenameFormat + suffix, i++);
String name = getImageFileName(filenameFormatted, dir, type, true);
if (name == null)
break;
// add image to list
try {
Image img = new Image(name);
if (suffix.equals(HD_SUFFIX))
img = img.getScaledCopy(0.5f);
list.add(img);
} catch (SlickException e) {
EventBus.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", name), BubbleNotificationEvent.COMMONCOLOR_RED));
break;
}
// add image to list
try {
Image img = new Image(name);
if (suffix.equals(HD_SUFFIX))
img = img.getScaledCopy(0.5f);
list.add(img);
} catch (SlickException e) {
BubNotifListener.EVENT.make().onBubNotif(
String.format("Failed to set image '%s'.", name), Colors.BUB_RED);
break;
}
if (!list.isEmpty())
return list.toArray(new Image[list.size()]);
}
if (!list.isEmpty())
return list.toArray(new Image[list.size()]);
}
return null;
}
@@ -813,15 +825,17 @@ public enum GameImage {
private Image loadImageSingle(File dir) {
for (String suffix : getSuffixes()) {
String name = getImageFileName(filename + suffix, dir, type, true);
if (name != null) {
try {
Image img = new Image(name);
if (suffix.equals(HD_SUFFIX))
img = img.getScaledCopy(0.5f);
return img;
} catch (SlickException e) {
EventBus.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", filename), BubbleNotificationEvent.COMMONCOLOR_RED));
}
if (name == null) {
continue;
}
try {
Image img = new Image(name);
if (suffix.equals(HD_SUFFIX))
img = img.getScaledCopy(0.5f);
return img;
} catch (SlickException e) {
BubNotifListener.EVENT.make().onBubNotif(
String.format("Failed to set image '%s'.", filename), Colors.BUB_RED);
}
}
return null;
@@ -865,7 +879,8 @@ public enum GameImage {
skinImages = null;
}
} catch (SlickException e) {
ErrorHandler.error(String.format("Failed to destroy beatmap skin images for '%s'.", this.name()), e).show();
String msg = String.format("Failed to destroy beatmap skin images for '%s'.", this.name());
ErrorHandler.explode(msg, e, ErrorHandler.DEFAULT_OPTIONS);
}
}

View File

@@ -27,39 +27,40 @@ import java.util.Collections;
import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import static org.lwjgl.input.Keyboard.*;
/**
* Game mods.
*/
public enum GameMod {
EASY (Category.EASY, 0, GameImage.MOD_EASY, "EZ", 2, Input.KEY_Q, 0.5f,
EASY (Category.EASY, 0, GameImage.MOD_EASY, "EZ", 2, KEY_Q, 0.5f,
"Easy", "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."),
NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, Input.KEY_W, 0.5f,
NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, KEY_W, 0.5f,
"NoFail", "You can't fail. No matter what."),
HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f,
HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, KEY_E, 0.3f,
"HalfTime", "Less zoom."),
HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, Input.KEY_A, 1.06f,
HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, KEY_A, 1.06f,
"HardRock", "Everything just got a bit harder..."),
SUDDEN_DEATH (Category.HARD, 1, GameImage.MOD_SUDDEN_DEATH, "SD", 32, Input.KEY_S, 1f,
SUDDEN_DEATH (Category.HARD, 1, GameImage.MOD_SUDDEN_DEATH, "SD", 32, KEY_S, 1f,
"SuddenDeath", "Miss a note and fail."),
// PERFECT (Category.HARD, 1, GameImage.MOD_PERFECT, "PF", 64, Input.KEY_S, 1f,
// "Perfect", "SS or quit."),
DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f,
DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, KEY_D, 1.12f,
"DoubleTime", "Zoooooooooom."),
// NIGHTCORE (Category.HARD, 2, GameImage.MOD_NIGHTCORE, "NT", 64, Input.KEY_D, 1.12f,
// "Nightcore", "uguuuuuuuu"),
HIDDEN (Category.HARD, 3, GameImage.MOD_HIDDEN, "HD", 8, Input.KEY_F, 1.06f,
HIDDEN (Category.HARD, 3, GameImage.MOD_HIDDEN, "HD", 8, KEY_F, 1.06f,
"Hidden", "Play with no approach circles and fading notes for a slight score advantage."),
FLASHLIGHT (Category.HARD, 4, GameImage.MOD_FLASHLIGHT, "FL", 1024, Input.KEY_G, 1.12f,
FLASHLIGHT (Category.HARD, 4, GameImage.MOD_FLASHLIGHT, "FL", 1024, KEY_G, 1.12f,
"Flashlight", "Restricted view area."),
RELAX (Category.SPECIAL, 0, GameImage.MOD_RELAX, "RL", 128, Input.KEY_Z, 0f,
RELAX (Category.SPECIAL, 0, GameImage.MOD_RELAX, "RL", 128, KEY_Z, 0f,
"Relax", "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.\n**UNRANKED**"),
AUTOPILOT (Category.SPECIAL, 1, GameImage.MOD_AUTOPILOT, "AP", 8192, Input.KEY_X, 0f,
AUTOPILOT (Category.SPECIAL, 1, GameImage.MOD_AUTOPILOT, "AP", 8192, KEY_X, 0f,
"Relax2", "Automatic cursor movement - just follow the rhythm.\n**UNRANKED**"),
SPUN_OUT (Category.SPECIAL, 2, GameImage.MOD_SPUN_OUT, "SO", 4096, Input.KEY_C, 0.9f,
SPUN_OUT (Category.SPECIAL, 2, GameImage.MOD_SPUN_OUT, "SO", 4096, KEY_C, 0.9f,
"SpunOut", "Spinners will be automatically completed."),
AUTO (Category.SPECIAL, 3, GameImage.MOD_AUTO, "", 2048, Input.KEY_V, 1f,
AUTO (Category.SPECIAL, 3, GameImage.MOD_AUTO, "", 2048, KEY_V, 1f,
"Autoplay", "Watch a perfect automated play through the song.");
/** Mod categories. */

View File

@@ -18,87 +18,75 @@
package itdelatrisu.opsu;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.utils.ManifestWrapper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.lang.reflect.Field;
import java.util.jar.JarFile;
/**
* Native loader, based on the JarSplice launcher.
*
* @author http://ninjacave.com
*/
public class NativeLoader {
/** The directory to unpack natives to. */
private final File nativeDir;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Constructor.
* @param dir the directory to unpack natives to
*/
public NativeLoader(File dir) {
nativeDir = dir;
public class NativeLoader {
public static void setNativePath() {
String nativepath = config.NATIVE_DIR.getAbsolutePath();
System.setProperty("org.lwjgl.librarypath", nativepath);
System.setProperty("java.library.path", nativepath);
try {
// Workaround for "java.library.path" property being read-only.
// http://stackoverflow.com/a/24988095
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (Exception e) {
Log.warn("Failed to set 'sys_paths' field.", e);
}
}
/**
* Unpacks natives for the current operating system to the natives directory.
* @throws IOException if an I/O exception occurs
*/
public void loadNatives() throws IOException {
if (!nativeDir.exists())
nativeDir.mkdir();
JarFile jarFile = Utils.getJarFile();
if (jarFile == null)
return;
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry e = entries.nextElement();
if (e == null)
break;
File f = new File(nativeDir, 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();
}
public static void loadNatives(JarFile jarfile, ManifestWrapper manifest) throws IOException {
if (!config.NATIVE_DIR.exists() && !config.NATIVE_DIR.mkdir()) {
String msg = String.format("Could not create folder '%s'",
config.NATIVE_DIR.getAbsolutePath());
throw new RuntimeException(msg);
}
jarFile.close();
}
/**
* Returns whether the given file name is a native file for the current operating system.
* @param entryName the file name
* @return true if the file is a native that should be loaded, false otherwise
*/
private boolean isNativeFile(String entryName) {
String osName = System.getProperty("os.name");
String name = entryName.toLowerCase();
String nativekey = null;
if (osName.startsWith("Win")) {
if (name.endsWith(".dll"))
return true;
nativekey = "WinNatives";
} else if (osName.startsWith("Linux")) {
if (name.endsWith(".so"))
return true;
nativekey = "NixNatives";
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
if (name.endsWith(".dylib") || name.endsWith(".jnilib"))
return true;
nativekey = "MacNatives";
}
if (nativekey == null) {
Log.warn("Cannot determine natives for os " + osName);
return;
}
String natives = manifest.valueOrDefault(null, nativekey, null);
if (natives == null) {
String msg = String.format("No entry for '%s' in manifest, jar is badly packed or damaged",
nativekey);
throw new RuntimeException(msg);
}
String[] nativefiles = natives.split(",");
for (String nativefile : nativefiles) {
File unpackedFile = new File(config.NATIVE_DIR, nativefile);
if (unpackedFile.exists()) {
continue;
}
Utils.unpackFromJar(jarfile, unpackedFile, nativefile);
}
return false;
}
}

View File

@@ -20,22 +20,13 @@ package itdelatrisu.opsu;
import itdelatrisu.opsu.downloads.Download;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Scanner;
import java.util.jar.JarFile;
@@ -50,41 +41,21 @@ import org.json.JSONObject;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Input;
import org.newdawn.slick.util.Log;
import com.sun.jna.platform.FileUtils;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.NotNull;
import yugecin.opsudance.core.Nullable;
import yugecin.opsudance.options.Options;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Contains miscellaneous utilities.
*/
public class Utils {
/**
* List of illegal filename characters.
* @see #cleanFileName(String, char)
*/
private final static int[] illegalChars = {
34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47
};
static {
Arrays.sort(illegalChars);
}
// This class should not be instantiated.
private Utils() {}
/**
* Initializes game settings and class data.
*/
public static void init(DisplayContainer displayContainer) {
// TODO clean this up
// game settings
}
/**
* Draws an animation based on its center.
@@ -183,15 +154,12 @@ public class Utils {
* @return true if pressed
*/
public static boolean isGameKeyPressed() {
/*
boolean mouseDown = !Options.isMouseDisabled() && (
input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) ||
input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON));
return (mouseDown ||
input.isKeyDown(Options.getGameKeyLeft()) ||
input.isKeyDown(Options.getGameKeyRight()));
*/
return true;
return
input.isKeyPressed(Options.OPTION_KEY_LEFT.intval) ||
input.isKeyPressed(Options.OPTION_KEY_RIGHT.intval) ||
(!Options.OPTION_DISABLE_MOUSE_BUTTONS.state && (
input.isMousePressed(Input.MOUSE_LEFT_BUTTON) ||
input.isMousePressed(Input.MOUSE_RIGHT_BUTTON)));
}
@@ -210,26 +178,31 @@ public class Utils {
}
/**
* Cleans a file name.
* @param badFileName the original name string
* @param replace the character to replace illegal characters with (or 0 if none)
* @return the cleaned file name
* @author Sarel Botha (http://stackoverflow.com/a/5626340)
* Changes bad characters to the replacement char given.
* Bad characters:
* non-printable (0-31)
* " (34) * (42) / (47) : (58)
* < (60) > (62) ? (63) \ (92)
* DEL (124)
*/
public static String cleanFileName(String badFileName, char replace) {
if (badFileName == null)
return null;
boolean doReplace = (replace > 0 && Arrays.binarySearch(illegalChars, replace) < 0);
StringBuilder cleanName = new StringBuilder();
for (int i = 0, n = badFileName.length(); i < n; i++) {
int c = badFileName.charAt(i);
if (Arrays.binarySearch(illegalChars, c) < 0)
cleanName.append((char) c);
else if (doReplace)
cleanName.append(replace);
public static String cleanFileName(@NotNull String badFileName, char replacement) {
char[] chars = badFileName.toCharArray();
long additionalBadChars =
1L << (34 - 32)|
1L << (42 - 32)|
1L << (47 - 32)|
1L << (58 - 32)|
1L << (60 - 32)|
1L << (62 - 32)|
1L << (63 - 32)|
1L << (92 - 32);
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c < 32 || c == 124 || (c < 93 && 0 != (additionalBadChars & (1L << (c - 32))))) {
chars[i] = replacement;
}
}
return cleanName.toString();
return new String(chars);
}
/**
@@ -338,7 +311,7 @@ public class Utils {
try {
json = new JSONObject(s);
} catch (JSONException e) {
ErrorHandler.error("Failed to create JSON object.", e).show();
explode("Failed to create JSON object.", e, DEFAULT_OPTIONS);
}
}
return json;
@@ -357,7 +330,7 @@ public class Utils {
try {
json = new JSONArray(s);
} catch (JSONException e) {
ErrorHandler.error("Failed to create JSON array.", e).show();
explode("Failed to create JSON array.", e, DEFAULT_OPTIONS);
}
}
return json;
@@ -399,7 +372,7 @@ public class Utils {
result.append(String.format("%02x", b));
return result.toString();
} catch (NoSuchAlgorithmException | IOException e) {
ErrorHandler.error("Failed to calculate MD5 hash.", e).show();
explode("Failed to calculate MD5 hash.", e, DEFAULT_OPTIONS);
}
return null;
}
@@ -418,43 +391,6 @@ public class Utils {
return String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
}
/**
* Returns whether or not the application is running within a JAR.
* @return true if JAR, false if file
*/
public static boolean isJarRunning() {
return Utils.class.getResource(String.format("%s.class", Utils.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(Utils.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.
* @return the directory, or null if it could not be determined
*/
public static File getRunningDirectory() {
try {
return new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
} catch (URISyntaxException e) {
Log.error("Could not get the running directory.", e);
return null;
}
}
/**
* Parses the integer string argument as a boolean:
* {@code 1} is {@code true}, and all other values are {@code false}.
@@ -470,8 +406,9 @@ public class Utils {
* most recent update to the working directory (e.g. fetch or successful push).
* @return the 40-character SHA-1 hash, or null if it could not be determined
*/
@Nullable
public static String getGitHash() {
if (isJarRunning())
if (env.isJarRunning)
return null;
File f = new File(".git/refs/remotes/origin/master");
if (!f.isFile())
@@ -516,11 +453,20 @@ public class Utils {
} catch (Exception e) {}
}
public static int getQuadrant(double x, double y) {
if (x < Options.width / 2d) {
return y < Options.height / 2d ? 2 : 3;
}
return y < Options.height / 2d ? 1 : 4;
/**
* Gets the region where the given point is in.
* First bit is set if x > half
* Second bit is set if y > half
*
* 2 | 3
* --+--
* 0 | 1
*/
public static int getRegion(double x, double y) {
int q = 0;
if (y < displayContainer.height / 2d) q = 2;
if (x < displayContainer.width / 2d) q |= 1;
return q;
}
/*
@@ -537,24 +483,24 @@ public class Utils {
*/
public static float[] mirrorPoint(float x, float y) {
double dx = x - Options.width / 2d;
double dy = y - Options.height / 2d;
double dx = x - displayContainer.width / 2d;
double dy = y - displayContainer.height / 2d;
double ang = Math.atan2(dy, dx);
double d = -Math.sqrt(dx * dx + dy * dy);
return new float[]{
(float) (Options.width / 2d + Math.cos(ang) * d),
(float) (Options.height / 2d + Math.sin(ang) * d)
(float) (displayContainer.width / 2d + Math.cos(ang) * d),
(float) (displayContainer.height / 2d + Math.sin(ang) * d)
};
}
public static float[] mirrorPoint(float x, float y, float degrees) {
double dx = x - Options.width / 2d;
double dy = y - Options.height / 2d;
double dx = x - displayContainer.width / 2d;
double dy = y - displayContainer.height / 2d;
double ang = Math.atan2(dy, dx) + (degrees * Math.PI / 180d);
double d = Math.sqrt(dx * dx + dy * dy);
return new float[]{
(float) (Options.width / 2d + Math.cos(ang) * d),
(float) (Options.height / 2d + Math.sin(ang) * d)
(float) (displayContainer.width / 2d + Math.cos(ang) * d),
(float) (displayContainer.height / 2d + Math.sin(ang) * d)
};
}
@@ -573,4 +519,19 @@ public class Utils {
key != Keyboard.KEY_F7 && key != Keyboard.KEY_F10 && key != Keyboard.KEY_F12);
}
public static void unpackFromJar(@NotNull JarFile jarfile, @NotNull File unpackedFile,
@NotNull String filename) throws IOException {
InputStream in = jarfile.getInputStream(jarfile.getEntry(filename));
OutputStream out = new FileOutputStream(unpackedFile);
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();
}
}

View File

@@ -1,7 +1,5 @@
package itdelatrisu.opsu.audio;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
@@ -14,6 +12,8 @@ import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Extension of Clip that allows playing multiple copies of a Clip simultaneously.
* http://stackoverflow.com/questions/1854616/
@@ -194,7 +194,8 @@ public class MultiClip {
try {
audioIn.close();
} catch (IOException e) {
ErrorHandler.error(String.format("Could not close AudioInputStream for MultiClip %s.", name), e).show();
explode(String.format("Could not close AudioInputStream for MultiClip %s.", name), e,
DEFAULT_OPTIONS);
}
}
}

View File

@@ -33,6 +33,7 @@ import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import itdelatrisu.opsu.ui.Colors;
import org.lwjgl.BufferUtils;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.AL10;
@@ -44,11 +45,10 @@ import org.newdawn.slick.openal.SoundStore;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import org.tritonus.share.sampled.file.TAudioFileFormat;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -103,7 +103,8 @@ public class MusicController {
if (lastBeatmap == null || !beatmap.audioFilename.equals(lastBeatmap.audioFilename)) {
final File audioFile = beatmap.audioFilename;
if (!audioFile.isFile() && !ResourceLoader.resourceExists(audioFile.getPath())) {
EventBus.post(new BarNotificationEvent(String.format("Could not find track '%s'.", audioFile.getName())));
BarNotifListener.EVENT.make().onBarNotif(String.format("Could not find track '%s'.",
audioFile.getName()));
return;
}
@@ -158,7 +159,7 @@ public class MusicController {
} catch (Exception e) {
String err = String.format("Could not play track '%s'.", file.getName());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
}
}
@@ -575,7 +576,7 @@ public class MusicController {
player = null;
} catch (Exception e) {
ErrorHandler.error("Failed to destroy OpenAL.", e).show();
explode("Failed to destroy OpenAL.", e, DEFAULT_OPTIONS);
}
}

View File

@@ -36,15 +36,15 @@ import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -104,7 +104,7 @@ public class SoundController {
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
return loadClip(ref, audioIn, isMP3);
} catch (Exception e) {
ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e).show();
explode(String.format("Failed to load file '%s'.", ref), e, DEFAULT_OPTIONS);
return null;
}
}
@@ -220,7 +220,8 @@ public class SoundController {
// menu and game sounds
for (SoundEffect s : SoundEffect.values()) {
if ((currentFileName = getSoundFileName(s.getFileName())) == null) {
EventBus.post(new BubbleNotificationEvent("Could not find sound file " + s.getFileName(), BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif(
"Could not find sound file " + s.getFileName(), Colors.BUB_ORANGE);
continue;
}
MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3"));
@@ -239,7 +240,8 @@ public class SoundController {
for (HitSound s : HitSound.values()) {
String filename = String.format("%s-%s", ss.getName(), s.getFileName());
if ((currentFileName = getSoundFileName(filename)) == null) {
EventBus.post(new BubbleNotificationEvent("Could not find hit sound file " + filename, BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif(
"Could not find hit sound file " + filename, Colors.BUB_ORANGE);
continue;
}
MultiClip newClip = loadClip(currentFileName, false);
@@ -283,7 +285,7 @@ public class SoundController {
try {
clip.start(volume, listener);
} catch (LineUnavailableException e) {
ErrorHandler.error(String.format("Could not start a clip '%s'.", clip.getName()), e).show();
explode(String.format("Could not start a clip '%s'.", clip.getName()), e, DEFAULT_OPTIONS);
}
}
}
@@ -396,7 +398,8 @@ public class SoundController {
@Override
public void error() {
EventBus.post(new BarNotificationEvent("Failed to download track preview."));
BarNotifListener.EVENT.make().onBarNotif(
"Failed to download track preview");
}
});
try {

View File

@@ -31,16 +31,15 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.core.Nullable;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -48,12 +47,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class BeatmapParser {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
/** The string lookup database. */
private static HashMap<String, String> stringdb = new HashMap<String, String>();
@@ -78,14 +71,9 @@ public class BeatmapParser {
/** If no Provider supports a MessageDigestSpi implementation for the MD5 algorithm. */
private boolean hasNoMD5Algorithm = false;
@Inject
public BeatmapParser() {
}
/**
* Invokes parser for each OSU file in a root directory and
* adds the beatmaps to a new BeatmapSetList.
* @param root the root directory (search has depth 1)
*/
public void parseAll() {
// create a new BeatmapSetList
@@ -93,7 +81,7 @@ public class BeatmapParser {
// create a new watch service
if (OPTION_ENABLE_WATCH_SERVICE.state) {
BeatmapWatchService.create(instanceContainer);
BeatmapWatchService.create();
}
// parse all directories
@@ -106,8 +94,8 @@ public class BeatmapParser {
* @param dirs the array of directories to parse
* @return the last BeatmapSetNode parsed, or null if none
*/
public BeatmapSetNode parseDirectories(File[] dirs) {
if (dirs == null)
public BeatmapSetNode parseDirectories(@Nullable File[] dirs) {
if (dirs == null || dirs.length == 0)
return null;
// progress tracking
@@ -172,8 +160,8 @@ public class BeatmapParser {
try {
beatmap = parseFile(file, dir, beatmaps, false);
} catch(Exception e) {
Log.error("could not parse beatmap " + file.getName() + ": " + e.getMessage());
EventBus.post(new BubbleNotificationEvent("Could not parse beatmap " + file.getName(), BubbleNotificationEvent.COLOR_ORANGE));
logAndShowErrorNotification(e, "Could not parse beatmap %s: %s",
file.getName(), e.getMessage());
}
// add to parsed beatmap list
@@ -260,11 +248,9 @@ public class BeatmapParser {
}
map.timingPoints.trimToSize();
} catch (IOException e) {
String err = String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
logAndShowErrorNotification(e, "Failed to read file '%s'.", map.getFile().getAbsolutePath());
} catch (NoSuchAlgorithmException e) {
ErrorHandler.error("Failed to get MD5 hash stream.", e).show();
explode("Failed to get MD5 hash stream.", e, DEFAULT_OPTIONS);
// retry without MD5
hasNoMD5Algorithm = true;
@@ -665,11 +651,9 @@ public class BeatmapParser {
if (md5stream != null)
beatmap.md5Hash = md5stream.getMD5();
} catch (IOException e) {
String err = String.format("Failed to read file '%s'.", file.getAbsolutePath());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
logAndShowErrorNotification(e, "Failed to read file '%s'.", file.getAbsolutePath());
} catch (NoSuchAlgorithmException e) {
ErrorHandler.error("Failed to get MD5 hash stream.", e).show();
explode("Failed to get MD5 hash stream.", e, DEFAULT_OPTIONS);
// retry without MD5
hasNoMD5Algorithm = true;
@@ -748,9 +732,8 @@ public class BeatmapParser {
}
beatmap.timingPoints.trimToSize();
} catch (IOException e) {
String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
logAndShowErrorNotification(e, "Failed to read file '%s'.",
beatmap.getFile().getAbsolutePath());
}
}
@@ -828,12 +811,12 @@ public class BeatmapParser {
// check that all objects were parsed
if (objectIndex != beatmap.objects.length)
ErrorHandler.error(String.format("Parsed %d objects for beatmap '%s', %d objects expected.",
objectIndex, beatmap.toString(), beatmap.objects.length), new Exception("no")).show();
explode(String.format("Parsed %d objects for beatmap '%s', %d objects expected.",
objectIndex, beatmap.toString(), beatmap.objects.length), new Exception("no"),
DEFAULT_OPTIONS);
} catch (IOException e) {
String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
logAndShowErrorNotification(e, "Failed to read file '%s'.",
beatmap.getFile().getAbsolutePath());
}
}
@@ -904,4 +887,10 @@ public class BeatmapParser {
return DBString;
}
private static void logAndShowErrorNotification(Exception e, String message, Object... formatArgs) {
message = String.format(message, formatArgs);
Log.error(message, e);
BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED);
}
}

View File

@@ -21,8 +21,8 @@ package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.BeatmapDB;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BubbleNotificationEvent;
import itdelatrisu.opsu.ui.Colors;
import yugecin.opsudance.events.BubNotifListener;
import java.io.File;
import java.io.IOException;
@@ -215,7 +215,7 @@ public class BeatmapSetList {
try {
Utils.deleteToTrash(dir);
} catch (IOException e) {
EventBus.post(new BubbleNotificationEvent("Could not delete song group", BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif("Could not delete song group", Colors.BUB_ORANGE);
}
if (ws != null)
ws.resume();
@@ -271,7 +271,7 @@ public class BeatmapSetList {
try {
Utils.deleteToTrash(file);
} catch (IOException e) {
EventBus.post(new BubbleNotificationEvent("Could not delete song", BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif("Could not delete song", Colors.BUB_ORANGE);
}
if (ws != null)
ws.resume();

View File

@@ -38,12 +38,12 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/*
@@ -83,6 +83,7 @@ import static yugecin.opsudance.options.Options.*;
* @author The Java Tutorials (http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java) (base)
*/
public class BeatmapWatchService {
/** Beatmap watcher service instance. */
private static BeatmapWatchService ws;
@@ -90,17 +91,17 @@ public class BeatmapWatchService {
* Creates a new watch service instance (overwriting any previous instance),
* registers the beatmap directory, and starts processing events.
*/
public static void create(InstanceContainer instanceContainer) {
public static void create() {
// close the existing watch service
destroy();
// create a new watch service
try {
ws = instanceContainer.provide(BeatmapWatchService.class);
ws.register(instanceContainer.provide(Configuration.class).beatmapDir.toPath());
ws = new BeatmapWatchService();
ws.register(config.beatmapDir.toPath());
} catch (IOException e) {
Log.error("Could not create watch service", e);
EventBus.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif("Could not create watch service", Colors.BUB_RED);
return;
}
@@ -121,8 +122,9 @@ public class BeatmapWatchService {
ws.service.shutdownNow();
ws = null;
} catch (IOException e) {
Log.error("An I/O exception occurred while closing the previous watch service.", e);
EventBus.post(new BubbleNotificationEvent("An I/O exception occurred while closing the previous watch service.", BubbleNotificationEvent.COMMONCOLOR_RED));
String msg = "An I/O exception occurred while closing the previous watch service.";
Log.error(msg, e);
BarNotifListener.EVENT.make().onBarNotif(msg);
ws = null;
}
}
@@ -137,7 +139,10 @@ public class BeatmapWatchService {
return ws;
}
/** Watch service listener interface. */
/**
* Watch service listener interface.
* TODO: replace by event system?
*/
public interface BeatmapWatchServiceListener {
/**
* Indication that an event was received.

View File

@@ -23,36 +23,27 @@ import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import itdelatrisu.opsu.ui.Colors;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Unpacker for OSZ (ZIP) archives.
*/
public class OszUnpacker {
@Inject
private Configuration config;
/** The index of the current file being unpacked. */
private int fileIndex = -1;
/** The total number of files to unpack. */
private File[] files;
@Inject
public OszUnpacker() {
}
/**
* Invokes the unpacker for each OSZ archive in a root directory.
* @param root the root directory
* @param dest the destination directory
* @return an array containing the new (unpacked) directories, or null
* if no OSZs found
*/
@@ -106,7 +97,7 @@ public class OszUnpacker {
} catch (ZipException e) {
String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
}
}

View File

@@ -33,8 +33,9 @@ import java.util.List;
import java.util.Map;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Handles connections and queries with the cached beatmap database.
@@ -89,17 +90,10 @@ public class BeatmapDB {
/** Current size of beatmap cache table. */
private static int cacheSize = -1;
// This class should not be instantiated.
private BeatmapDB() {}
private static Configuration config; // TODO
/**
* Initializes the database connection.
*/
public static void init(Configuration config) {
BeatmapDB.config = config;
public static void init() {
// create a database connection
connection = DBController.createConnection(config.BEATMAP_DB.getPath());
if (connection == null)
@@ -115,7 +109,7 @@ public class BeatmapDB {
try {
updateSizeStmt = connection.prepareStatement("REPLACE INTO info (key, value) VALUES ('size', ?)");
} catch (SQLException e) {
ErrorHandler.error("Failed to prepare beatmap statements.", e).show();
explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS);
}
// retrieve the cache size
@@ -137,7 +131,7 @@ public class BeatmapDB {
updatePlayStatsStmt = connection.prepareStatement("UPDATE beatmaps SET playCount = ?, lastPlayed = ? WHERE dir = ? AND file = ?");
setFavoriteStmt = connection.prepareStatement("UPDATE beatmaps SET favorite = ? WHERE dir = ? AND file = ?");
} catch (SQLException e) {
ErrorHandler.error("Failed to prepare beatmap statements.", e).show();
explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS);
}
}
@@ -175,7 +169,7 @@ public class BeatmapDB {
sql = String.format("INSERT OR IGNORE INTO info(key, value) VALUES('version', '%s')", DATABASE_VERSION);
stmt.executeUpdate(sql);
} catch (SQLException e) {
ErrorHandler.error("Coudl not create beatmap database.", e).show();
explode("Could not create beatmap database.", e, DEFAULT_OPTIONS);
}
}
@@ -227,7 +221,7 @@ public class BeatmapDB {
ps.close();
}
} catch (SQLException e) {
ErrorHandler.error("Failed to update beatmap database.", e).show();
explode("Failed to update beatmap database.", e, DEFAULT_OPTIONS);
}
}
@@ -245,7 +239,7 @@ public class BeatmapDB {
}
rs.close();
} catch (SQLException e) {
ErrorHandler.error("Could not get beatmap cache size.", e).show();
explode("Could not get beatmap cache size.", e, DEFAULT_OPTIONS);
}
}
@@ -260,7 +254,7 @@ public class BeatmapDB {
updateSizeStmt.setString(1, Integer.toString(Math.max(cacheSize, 0)));
updateSizeStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error("Could not update beatmap cache size.", e).show();
explode("Could not update beatmap cache size.", e, DEFAULT_OPTIONS);
}
}
@@ -278,7 +272,7 @@ public class BeatmapDB {
cacheSize = 0;
updateCacheSize();
} catch (SQLException e) {
ErrorHandler.error("Could not drop beatmap database.", e).show();
explode("Could not drop beatmap database.", e, DEFAULT_OPTIONS);
}
createDatabase();
}
@@ -296,7 +290,7 @@ public class BeatmapDB {
cacheSize += insertStmt.executeUpdate();
updateCacheSize();
} catch (SQLException e) {
ErrorHandler.error("Failed to add beatmap to database.", e).show();
explode("Failed to add beatmap to database.", e, DEFAULT_OPTIONS);
}
}
@@ -349,7 +343,7 @@ public class BeatmapDB {
// update cache size
updateCacheSize();
} catch (SQLException e) {
ErrorHandler.error("Failed to add beatmaps to database.", e).show();
explode("Failed to add beatmaps to database.", e, DEFAULT_OPTIONS);
}
}
@@ -437,7 +431,7 @@ public class BeatmapDB {
}
rs.close();
} catch (SQLException e) {
ErrorHandler.error("Failed to load Beatmap from database.", e).show();
explode("Failed to load Beatmap from database.", e, DEFAULT_OPTIONS);
}
}
@@ -500,7 +494,7 @@ public class BeatmapDB {
}
rs.close();
} catch (SQLException e) {
ErrorHandler.error("Failed to load beatmaps from database.", e).show();
explode("Failed to load beatmaps from database.", e, DEFAULT_OPTIONS);
}
}
@@ -601,7 +595,7 @@ public class BeatmapDB {
rs.close();
return map;
} catch (SQLException e) {
ErrorHandler.error("Failed to get last modified map from database.", e).show();
explode("Failed to get last modified map from database.", e, DEFAULT_OPTIONS);
return null;
}
}
@@ -621,7 +615,7 @@ public class BeatmapDB {
cacheSize -= deleteMapStmt.executeUpdate();
updateCacheSize();
} catch (SQLException e) {
ErrorHandler.error("Failed to delete beatmap entry from database.", e).show();
explode("Failed to delete beatmap entry from database.", e, DEFAULT_OPTIONS);
}
}
@@ -638,7 +632,7 @@ public class BeatmapDB {
cacheSize -= deleteGroupStmt.executeUpdate();
updateCacheSize();
} catch (SQLException e) {
ErrorHandler.error("Failed to delete beatmap group entry from database.", e).show();
explode("Failed to delete beatmap group entry from database.", e, DEFAULT_OPTIONS);
}
}
@@ -656,8 +650,8 @@ public class BeatmapDB {
setStarsStmt.setString(3, beatmap.getFile().getName());
setStarsStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error(String.format("Failed to save star rating '%.4f' for beatmap '%s' in database.",
beatmap.starRating, beatmap.toString()), e).show();
explode(String.format("Failed to save star rating '%.4f' for beatmap '%s' in database.",
beatmap.starRating, beatmap.toString()), e, DEFAULT_OPTIONS);
}
}
@@ -676,8 +670,8 @@ public class BeatmapDB {
updatePlayStatsStmt.setString(4, beatmap.getFile().getName());
updatePlayStatsStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error(String.format("Failed to update play statistics for beatmap '%s' in database.",
beatmap.toString()), e).show();
explode(String.format("Failed to update play statistics for beatmap '%s' in database.",
beatmap.toString()), e, DEFAULT_OPTIONS);
}
}
@@ -695,8 +689,8 @@ public class BeatmapDB {
setFavoriteStmt.setString(3, beatmap.getFile().getName());
setFavoriteStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error(String.format("Failed to update favorite status for beatmap '%s' in database.",
beatmap.toString()), e).show();
explode(String.format("Failed to update favorite status for beatmap '%s' in database.",
beatmap.toString()), e, DEFAULT_OPTIONS);
}
}
@@ -716,7 +710,7 @@ public class BeatmapDB {
connection.close();
connection = null;
} catch (SQLException e) {
ErrorHandler.error("Failed to close beatmap database.", e).show();
explode("Failed to close beatmap database.", e, DEFAULT_OPTIONS);
}
}
}

View File

@@ -18,13 +18,12 @@
package itdelatrisu.opsu.db;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Database controller.
*/
@@ -35,17 +34,17 @@ public class DBController {
/**
* Initializes all databases.
*/
public static void init(Configuration config) {
public static void init() {
// load the sqlite-JDBC driver using the current class loader
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
ErrorHandler.error("Could not load sqlite-JDBC driver.", e).show();
explode("Could not load sqlite-JDBC driver.", e, DEFAULT_OPTIONS);
}
// initialize the databases
BeatmapDB.init(config);
ScoreDB.init(config);
BeatmapDB.init();
ScoreDB.init();
}
/**
@@ -66,7 +65,7 @@ public class DBController {
return DriverManager.getConnection(String.format("jdbc:sqlite:%s", path));
} catch (SQLException e) {
// if the error message is "out of memory", it probably means no database file is found
ErrorHandler.error(String.format("Could not connect to database: '%s'.", path), e).show();
explode(String.format("Could not connect to database: '%s'.", path), e, DEFAULT_OPTIONS);
return null;
}
}

View File

@@ -20,8 +20,6 @@ package itdelatrisu.opsu.db;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.beatmap.Beatmap;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -36,6 +34,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Handles connections and queries with the scores database.
*/
@@ -77,13 +78,10 @@ public class ScoreDB {
/** Score deletion statement. */
private static PreparedStatement deleteSongStmt, deleteScoreStmt;
// This class should not be instantiated.
private ScoreDB() {}
/**
* Initializes the database connection.
*/
public static void init(Configuration config) {
public static void init() {
// create a database connection
connection = DBController.createConnection(config.SCORE_DB.getPath());
if (connection == null)
@@ -124,7 +122,7 @@ public class ScoreDB {
// TODO: extra playerName checks not needed if name is guaranteed not null
);
} catch (SQLException e) {
ErrorHandler.error("Failed to prepare score statements.", e).show();
explode("Failed to prepare score statements.", e, DEFAULT_OPTIONS);
}
}
@@ -157,7 +155,7 @@ public class ScoreDB {
sql = String.format("INSERT OR IGNORE INTO info(key, value) VALUES('version', %d)", DATABASE_VERSION);
stmt.executeUpdate(sql);
} catch (SQLException e) {
ErrorHandler.error("Could not create score database.", e).show();
explode("Could not create score database.", e, DEFAULT_OPTIONS);
}
}
@@ -209,7 +207,7 @@ public class ScoreDB {
ps.close();
}
} catch (SQLException e) {
ErrorHandler.error("Failed to update score database.", e).show();
explode("Failed to update score database.", e, DEFAULT_OPTIONS);
}
}
@@ -227,7 +225,7 @@ public class ScoreDB {
insertStmt.setString(19, data.playerName);
insertStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error("Failed to save score to database.", e).show();
explode("Failed to save score to database.", e, DEFAULT_OPTIONS);
}
}
@@ -247,7 +245,7 @@ public class ScoreDB {
deleteScoreStmt.setString(21, data.playerName);
deleteScoreStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error("Failed to delete score from database.", e).show();
explode("Failed to delete score from database.", e, DEFAULT_OPTIONS);
}
}
@@ -267,7 +265,7 @@ public class ScoreDB {
deleteSongStmt.setString(5, beatmap.version);
deleteSongStmt.executeUpdate();
} catch (SQLException e) {
ErrorHandler.error("Failed to delete scores from database.", e).show();
explode("Failed to delete scores from database.", e, DEFAULT_OPTIONS);
}
}
@@ -335,7 +333,7 @@ public class ScoreDB {
}
rs.close();
} catch (SQLException e) {
ErrorHandler.error("Failed to read scores from database.", e).show();
explode("Failed to read scores from database.", e, DEFAULT_OPTIONS);
return null;
}
return getSortedArray(list);
@@ -377,7 +375,7 @@ public class ScoreDB {
map.put(version, getSortedArray(list));
rs.close();
} catch (SQLException e) {
ErrorHandler.error("Failed to read scores from database.", e).show();
explode("Failed to read scores from database.", e, DEFAULT_OPTIONS);
return null;
}
return map;
@@ -406,7 +404,7 @@ public class ScoreDB {
connection.close();
connection = null;
} catch (SQLException e) {
ErrorHandler.error("Failed to close score database.", e).show();
explode("Failed to close score database.", e, DEFAULT_OPTIONS);
}
}
}

View File

@@ -33,10 +33,11 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* File download.
@@ -92,7 +93,7 @@ public class Download {
private String localPath;
/** The local path to rename the file to when finished. */
private String rename;
private String renamedFileName;
/** The download URL. */
private URL url;
@@ -137,18 +138,20 @@ public class Download {
* Constructor.
* @param remoteURL the download URL
* @param localPath the path to save the download
* @param rename the file name to rename the download to when complete
* @param renamedFileName the file name to rename the download to when complete
*/
public Download(String remoteURL, String localPath, String rename) {
public Download(String remoteURL, String localPath, String renamedFileName) {
try {
this.url = new URL(remoteURL);
} catch (MalformedURLException e) {
this.status = Status.ERROR;
ErrorHandler.error(String.format("Bad download URL: '%s'", remoteURL), e).show();
explode(String.format("Bad download URL: '%s'", remoteURL), e, DEFAULT_OPTIONS);
return;
}
this.localPath = localPath;
this.rename = Utils.cleanFileName(rename, '-');
if (renamedFileName != null) {
this.renamedFileName = Utils.cleanFileName(renamedFileName, '-');
}
}
/**
@@ -159,7 +162,7 @@ public class Download {
/**
* Returns the local path to save the download (after renamed).
*/
public String getLocalPath() { return (rename != null) ? rename : localPath; }
public String getLocalPath() { return (renamedFileName != null) ? renamedFileName : localPath; }
/**
* Sets the download listener.
@@ -217,7 +220,7 @@ public class Download {
else if (redirectCount > MAX_REDIRECTS)
error = String.format("Download for URL '%s' is attempting too many redirects (over %d).", base.toString(), MAX_REDIRECTS);
if (error != null) {
EventBus.post(new BubbleNotificationEvent(error, BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif(error, Colors.BUB_ORANGE);
throw new IOException();
}
@@ -263,9 +266,9 @@ public class Download {
status = Status.COMPLETE;
rbc.close();
fos.close();
if (rename != null) {
if (renamedFileName != null) {
Path source = new File(localPath).toPath();
Files.move(source, source.resolveSibling(rename), StandardCopyOption.REPLACE_EXISTING);
Files.move(source, source.resolveSibling(renamedFileName), StandardCopyOption.REPLACE_EXISTING);
}
if (listener != null)
listener.completed();
@@ -419,7 +422,7 @@ public class Download {
}
} catch (IOException e) {
this.status = Status.ERROR;
ErrorHandler.error("Failed to cancel download.", e).show();
explode("Failed to cancel download.", e, DEFAULT_OPTIONS);
}
}
}

View File

@@ -33,12 +33,10 @@ import java.io.File;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -46,9 +44,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class DownloadNode {
@Inject
private Configuration config;
/** The associated Download object. */
private Download download;
@@ -285,12 +280,14 @@ public class DownloadNode {
download.setListener(new DownloadListener() {
@Override
public void completed() {
EventBus.post(new BarNotificationEvent(String.format("Download complete: %s", getTitle())));
BarNotifListener.EVENT.make().onBarNotif(
String.format("Download complete: %s", getTitle()));
}
@Override
public void error() {
EventBus.post(new BarNotificationEvent("Download failed due to a connection error."));
BarNotifListener.EVENT.make().onBarNotif(
"Download failed due to a connection error.");
}
});
this.download = download;
@@ -412,7 +409,9 @@ public class DownloadNode {
public void drawDownload(Graphics g, float position, int id, boolean hover) {
Download download = this.download; // in case clearDownload() is called asynchronously
if (download == null) {
EventBus.post(new BubbleNotificationEvent("Trying to draw download information for button without Download object", BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif(
"Trying to draw download information for button without Download object",
Colors.BUB_ORANGE);
return;
}

View File

@@ -35,26 +35,17 @@ import java.util.Properties;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.core.Constants;
import yugecin.opsudance.events.BarNotifListener;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Handles automatic program updates.
*/
public class Updater {
@Inject
private Configuration config;
private static Updater updater;
public static Updater get() {
return updater;
}
/** The exit confirmation message. */
public static final String EXIT_CONFIRMATION = "An opsu! update is being downloaded.\nAre you sure you want to quit opsu!?";
@@ -95,7 +86,7 @@ public class Updater {
* Returns the status description.
*/
public String getDescription() { return description; }
};
}
/** The current updater status. */
private Status status;
@@ -119,10 +110,8 @@ public class Updater {
return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion();
}
@Inject
public Updater() {
status = Status.INITIAL;
updater = this;
}
/**
@@ -145,7 +134,7 @@ public class Updater {
Date date = null;
try {
Properties props = new Properties();
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
props.load(ResourceLoader.getResourceAsStream(Constants.VERSION_FILE));
String build = props.getProperty("build.date");
if (build == null || build.equals("${timestamp}") || build.equals("${maven.build.timestamp}"))
date = new Date();
@@ -214,16 +203,16 @@ public class Updater {
// get current version
Properties props = new Properties();
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
props.load(ResourceLoader.getResourceAsStream(Constants.VERSION_FILE));
if ((currentVersion = getVersion(props)) == null)
return;
// get latest version
String s = null;
try {
s = Utils.readDataFromUrl(new URL(config.VERSION_REMOTE));
s = Utils.readDataFromUrl(new URL(Constants.VERSION_REMOTE));
} catch (UnknownHostException e) {
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", config.VERSION_REMOTE));
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", Constants.VERSION_REMOTE));
}
if (s == null) {
status = Status.CONNECTION_ERROR;
@@ -252,13 +241,14 @@ public class Updater {
@Override
public void completed() {
status = Status.UPDATE_DOWNLOADED;
EventBus.post(new BarNotificationEvent("Update has finished downloading"));
BarNotifListener.EVENT.make().onBarNotif("Update has finished downloading");
}
@Override
public void error() {
status = Status.CONNECTION_ERROR;
EventBus.post(new BarNotificationEvent("Update failed due to a connection error."));
BarNotifListener.EVENT.make().onBarNotif(
"Update failed due to a connection error.");
}
});
}
@@ -301,7 +291,7 @@ public class Updater {
pb.start();
} catch (IOException e) {
status = Status.INTERNAL_ERROR;
ErrorHandler.error("Failed to start new process.", e).show();
explode("Failed to start new process.", e, DEFAULT_OPTIONS);
}
}
}

View File

@@ -33,18 +33,14 @@ import java.util.Date;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Download server: http://bloodcat.com/osu/
*/
public class BloodcatServer extends DownloadServer {
@Inject
public InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "Bloodcat";
@@ -60,10 +56,6 @@ public class BloodcatServer extends DownloadServer {
/** Total result count from the last query. */
private int totalResults = -1;
@Inject
public BloodcatServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -89,12 +81,12 @@ public class BloodcatServer extends DownloadServer {
nodes = new DownloadNode[arr.length()];
for (int i = 0; i < nodes.length; i++) {
JSONObject item = arr.getJSONObject(i);
nodes[i] = instanceContainer.injectFields(new DownloadNode(
nodes[i] = new DownloadNode(
item.getInt("id"), formatDate(item.getString("synced")), //"date"
item.getString("title"), item.isNull("titleU") ? null : item.getString("titleU"), //"titleUnicode"
item.getString("artist"), item.isNull("artistU") ? null : item.getString("artistU"), //"artistUnicode"
item.getString("creator")
));
);
}
// store total result count
@@ -104,7 +96,7 @@ public class BloodcatServer extends DownloadServer {
resultCount++;
this.totalResults = resultCount;
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
}
return nodes;
}

View File

@@ -29,9 +29,8 @@ import java.net.URLEncoder;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Download server: https://osu.hexide.com/
@@ -40,9 +39,6 @@ import yugecin.opsudance.core.inject.InstanceContainer;
*/
public class HexideServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "Hexide";
@@ -64,10 +60,6 @@ public class HexideServer extends DownloadServer {
/** Total result count from the last query. */
private int totalResults = -1;
@Inject
public HexideServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -124,10 +116,10 @@ public class HexideServer extends DownloadServer {
artist = creator = "?";
}
}
nodes[i] = instanceContainer.injectFields(new DownloadNode(
nodes[i] = new DownloadNode(
item.getInt("ranked_id"), item.getString("date"),
title, null, artist, null, creator
));
);
}
// store total result count
@@ -135,7 +127,7 @@ public class HexideServer extends DownloadServer {
// all results at once; this approach just gets pagination correct.
this.totalResults = arr.length() + resultIndex;
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
}
return nodes;
}

View File

@@ -29,18 +29,14 @@ import java.net.URLEncoder;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Download server: http://osu.mengsky.net/
*/
public class MengSkyServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "MengSky";
@@ -56,10 +52,6 @@ public class MengSkyServer extends DownloadServer {
/** Total result count from the last query. */
private int totalResults = -1;
@Inject
public MengSkyServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -93,10 +85,10 @@ public class MengSkyServer extends DownloadServer {
// sometimes titleU is artistU instead of the proper title
if (titleU.equals(artistU) && !titleU.equals(title))
titleU = title;
nodes[i] = instanceContainer.injectFields(new DownloadNode(
nodes[i] = new DownloadNode(
item.getInt("id"), item.getString("syncedDateTime"),
title, titleU, artist, artistU, creator
));
);
}
// store total result count
@@ -107,7 +99,7 @@ public class MengSkyServer extends DownloadServer {
}
this.totalResults = resultCount;
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
}
return nodes;
}

View File

@@ -20,9 +20,6 @@ package itdelatrisu.opsu.downloads.servers;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -34,14 +31,13 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Download server: http://osu.uu.gl/
*/
public class MnetworkServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "Mnetwork";
@@ -57,10 +53,6 @@ public class MnetworkServer extends DownloadServer {
/** Beatmap pattern. */
private Pattern BEATMAP_PATTERN = Pattern.compile("^(\\d+) ([^-]+) - (.+)\\.osz$");
@Inject
public MnetworkServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -119,7 +111,7 @@ public class MnetworkServer extends DownloadServer {
if (!m.matches())
continue;
nodeList.add(instanceContainer.injectFields(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, "")));
nodeList.add(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, ""));
}
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
@@ -127,7 +119,7 @@ public class MnetworkServer extends DownloadServer {
// store total result count
this.totalResults = nodes.length;
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
}
return nodes;
}

View File

@@ -35,9 +35,8 @@ import java.util.TimeZone;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Download server: http://loli.al/
@@ -46,9 +45,6 @@ import yugecin.opsudance.core.inject.InstanceContainer;
*/
public class OsuMirrorServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "osu!Mirror";
@@ -73,10 +69,6 @@ public class OsuMirrorServer extends DownloadServer {
/** Lookup table from beatmap set ID -> server download ID. */
private HashMap<Integer, Integer> idTable = new HashMap<Integer, Integer>();
@Inject
public OsuMirrorServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -113,12 +105,12 @@ public class OsuMirrorServer extends DownloadServer {
JSONObject item = arr.getJSONObject(i);
int beatmapSetID = item.getInt("OSUSetid");
int serverID = item.getInt("id");
nodes[i] = instanceContainer.injectFields(new DownloadNode(
nodes[i] = new DownloadNode(
beatmapSetID, formatDate(item.getString("ModifyDate")),
item.getString("Title"), null,
item.getString("Artist"), null,
item.getString("Mapper")
));
);
idTable.put(beatmapSetID, serverID);
if (serverID > maxServerID)
maxServerID = serverID;
@@ -130,7 +122,7 @@ public class OsuMirrorServer extends DownloadServer {
else
this.totalResults = maxServerID;
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
}
return nodes;
}

View File

@@ -33,18 +33,14 @@ import java.util.Iterator;
import java.util.List;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
/**
* Download server: http://osu.yas-online.net/
*/
public class YaSOnlineServer extends DownloadServer {
@Inject
public InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "YaS Online";
@@ -72,10 +68,6 @@ public class YaSOnlineServer extends DownloadServer {
/** Max server download ID seen (for approximating total pages). */
private int maxServerID = 0;
@Inject
public YaSOnlineServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -121,7 +113,8 @@ public class YaSOnlineServer extends DownloadServer {
String downloadLink = item.getString("downloadLink");
return String.format(DOWNLOAD_FETCH_URL, downloadLink);
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e).show();
explode(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e,
DEFAULT_OPTIONS);
return null;
} finally {
Utils.setSSLCertValidation(true);
@@ -183,7 +176,7 @@ public class YaSOnlineServer extends DownloadServer {
if (serverID > maxServerID)
maxServerID = serverID;
nodeList.add(instanceContainer.injectFields(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, "")));
nodeList.add(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, ""));
}
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
@@ -193,7 +186,7 @@ public class YaSOnlineServer extends DownloadServer {
else
this.totalResults = maxServerID;
} catch (MalformedURLException | UnsupportedEncodingException e) {
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
} finally {
Utils.setSSLCertValidation(true);
}

View File

@@ -30,9 +30,8 @@ import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import yugecin.opsudance.Dancer;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.render.GameObjectRenderer;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -40,9 +39,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class Circle extends GameObject {
@Inject
private GameObjectRenderer gameObjectRenderer;
/** The associated HitObject. */
private HitObject hitObject;
@@ -156,7 +152,7 @@ public class Circle extends GameObject {
@Override
public boolean mousePressed(int x, int y, int trackPosition) {
double distance = Math.hypot(this.x - x, this.y - y);
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
if (distance < gameObjectRenderer.circleDiameter / 2) {
int timeDiff = trackPosition - hitObject.getTime();
int result = hitResult(timeDiff);

View File

@@ -35,11 +35,9 @@ import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.Dancer;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -47,12 +45,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class Slider extends GameObject {
@Inject
private DisplayContainer displayContainer;
@Inject
private GameObjectRenderer gameObjectRenderer;
/** Slider ball frames. */
private static Image[] sliderBallImages;
@@ -605,7 +597,7 @@ public class Slider extends GameObject {
return false;
double distance = Math.hypot(this.x - x, this.y - y);
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
if (distance < gameObjectRenderer.circleDiameter / 2) {
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
int[] hitResultOffset = game.getHitResultOffsets();

View File

@@ -37,8 +37,8 @@ import org.lwjgl.opengl.GL20;
import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.render.GameObjectRenderer;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -316,7 +316,7 @@ public class CurveRenderState {
double diff_x = x - last_x;
double diff_y = y - last_y;
float dist = Utils.distance(x, y, last_x, last_y);
if (dist < GameObjectRenderer.instance.getCircleDiameter() / 8) {
if (dist < gameObjectRenderer.circleDiameter / 8) {
x = (float) (x - diff_x / 2);
y = (float) (y - diff_y / 2);
} else {

View File

@@ -39,15 +39,15 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import itdelatrisu.opsu.ui.Colors;
import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
import org.newdawn.slick.util.Log;
import lzma.streams.LzmaOutputStream;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Captures osu! replay data.
@@ -57,9 +57,6 @@ import yugecin.opsudance.options.Configuration;
*/
public class Replay {
@Inject
public Configuration config;
/** The associated file. */
private File file;
@@ -278,7 +275,7 @@ public class Replay {
public void save() {
// create replay directory
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
EventBus.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif("Failed to create replay directory", Colors.BUB_RED);
return;
}
@@ -347,7 +344,7 @@ public class Replay {
compressedOut.write(bytes);
} catch (IOException e) {
// possible OOM: https://github.com/jponge/lzma-java/issues/9
ErrorHandler.error("LZMA compression failed (possible out-of-memory error).", e).show();
explode("LZMA compression failed (possible out-of-memory error).", e, DEFAULT_OPTIONS);
}
compressedOut.close();
bout.close();
@@ -361,7 +358,7 @@ public class Replay {
writer.close();
} catch (IOException e) {
ErrorHandler.error("Could not save replay data.", e).show();
explode("Could not save replay data.", e, DEFAULT_OPTIONS);
}
}
}.start();

View File

@@ -28,24 +28,17 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BubNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Importer for replay files.
*/
public class ReplayImporter {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
/** The subdirectory (within the replay import directory) to move replays that could not be imported. */
private final String FAILED_IMPORT_DIR = "failed";
@@ -55,10 +48,6 @@ public class ReplayImporter {
/** The total number of replays to import. */
private File[] files;
@Inject
public ReplayImporter() {
}
/**
* Invokes the importer for each OSR file in the replay import dir, adding the replay
* to the score database and moving the file into the replay directory.
@@ -80,21 +69,21 @@ public class ReplayImporter {
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath());
Log.error(err);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
return;
}
// import OSRs
for (File file : files) {
fileIndex++;
Replay r = instanceContainer.injectFields(new Replay(file));
Replay r = new Replay(file);
try {
r.loadHeader();
} catch (IOException e) {
moveToFailedDirectory(file);
String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
continue;
}
Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash);
@@ -113,7 +102,7 @@ public class ReplayImporter {
moveToFailedDirectory(file);
String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName());
Log.error(err);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
}
}

View File

@@ -29,10 +29,10 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BubNotifListener;
/**
* Loads skin configuration files.
@@ -293,7 +293,7 @@ public class SkinLoader {
} catch (IOException e) {
String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath());
Log.error(err, e);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
}
return skin;

View File

@@ -35,14 +35,15 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.BaseOpsuState;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Generic button menu state.
* <p>
@@ -68,7 +69,7 @@ public class ButtonMenu extends BaseOpsuState {
BEATMAP (new Button[] { Button.CLEAR_SCORES, Button.FAVORITE_ADD, Button.DELETE, Button.CANCEL }) {
@Override
public String[] getTitle() {
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
BeatmapSetNode node = buttonState.getNode();
String beatmapString = (node != null) ? BeatmapSetList.get().getBaseNode(node.index).toString() : "";
return new String[] { beatmapString, "What do you want to do with this beatmap?" };
}
@@ -99,7 +100,7 @@ public class ButtonMenu extends BaseOpsuState {
BEATMAP_DELETE_SELECT (new Button[] { Button.DELETE_GROUP, Button.DELETE_SONG, Button.CANCEL_DELETE }) {
@Override
public String[] getTitle() {
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
BeatmapSetNode node = buttonState.getNode();
String beatmapString = (node != null) ? node.toString() : "";
return new String[] { String.format("Are you sure you wish to delete '%s' from disk?", beatmapString) };
}
@@ -179,7 +180,7 @@ public class ButtonMenu extends BaseOpsuState {
}
@Override
protected float getBaseY(DisplayContainer displayContainer) {
protected float getBaseY() {
return displayContainer.height * 2f / 3;
}
@@ -268,9 +269,6 @@ public class ButtonMenu extends BaseOpsuState {
}
};
public static DisplayContainer displayContainer;
public static InstanceContainer instanceContainer;
/** The buttons in the state. */
private final Button[] buttons;
@@ -299,7 +297,7 @@ public class ButtonMenu extends BaseOpsuState {
*/
public void revalidate(Image button, Image buttonL, Image buttonR) {
float center = displayContainer.width / 2;
float baseY = getBaseY(displayContainer);
float baseY = getBaseY();
float offsetY = button.getHeight() * 1.25f;
menuButtons = new MenuButton[buttons.length];
@@ -314,7 +312,7 @@ public class ButtonMenu extends BaseOpsuState {
/**
* Returns the base Y coordinate for the buttons.
*/
protected float getBaseY(DisplayContainer displayContainer) {
protected float getBaseY() {
float baseY = displayContainer.height * 0.2f;
baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight());
return baseY;
@@ -437,62 +435,62 @@ public class ButtonMenu extends BaseOpsuState {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(MainMenu.class);
displayContainer.switchState(mainmenuState);
}
},
CLEAR_SCORES ("Clear local scores", Color.magenta) {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP, node);
displayContainer.switchState(SongMenu.class);
BeatmapSetNode node = buttonState.getNode();
songMenuState.doStateActionOnLoad(MenuState.BEATMAP, node);
displayContainer.switchState(songMenuState);
}
},
FAVORITE_ADD ("Add to Favorites", Color.blue) {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
BeatmapSetNode node = buttonState.getNode();
node.getBeatmapSet().setFavorite(true);
displayContainer.switchState(SongMenu.class);
displayContainer.switchState(songMenuState);
}
},
FAVORITE_REMOVE ("Remove from Favorites", Color.blue) {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
BeatmapSetNode node = buttonState.getNode();
node.getBeatmapSet().setFavorite(false);
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_FAVORITE);
displayContainer.switchState(SongMenu.class);
songMenuState.doStateActionOnLoad(MenuState.BEATMAP_FAVORITE);
displayContainer.switchState(songMenuState);
}
},
DELETE ("Delete...", Color.red) {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
BeatmapSetNode node = buttonState.getNode();
MenuState ms = (node.beatmapIndex == -1 || node.getBeatmapSet().size() == 1) ?
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
instanceContainer.provide(ButtonMenu.class).setMenuState(ms, node);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(ms, node);
displayContainer.switchState(buttonState);
}
},
CANCEL ("Cancel", Color.gray) {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(SongMenu.class);
displayContainer.switchState(songMenuState);
}
},
DELETE_CONFIRM ("Yes, delete this beatmap!", Color.red) {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
displayContainer.switchState(SongMenu.class);
BeatmapSetNode node = buttonState.getNode();
songMenuState.doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
displayContainer.switchState(songMenuState);
}
},
DELETE_GROUP ("Yes, delete all difficulties!", Color.red) {
@@ -505,9 +503,9 @@ public class ButtonMenu extends BaseOpsuState {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
displayContainer.switchState(SongMenu.class);
BeatmapSetNode node = buttonState.getNode();
songMenuState.doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
displayContainer.switchState(songMenuState);
}
},
CANCEL_DELETE ("Nooooo! I didn't mean to!", Color.gray) {
@@ -520,8 +518,8 @@ public class ButtonMenu extends BaseOpsuState {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.RELOAD);
displayContainer.switchState(SongMenu.class);
songMenuState.doStateActionOnLoad(MenuState.RELOAD);
displayContainer.switchState(songMenuState);
}
},
RELOAD_CANCEL ("Cancel", Color.red) {
@@ -534,9 +532,9 @@ public class ButtonMenu extends BaseOpsuState {
@Override
public void click() {
SoundController.playSound(SoundEffect.MENUHIT);
ScoreData scoreData = instanceContainer.provide(ButtonMenu.class).getScoreData();
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.SCORE, scoreData);
displayContainer.switchState(SongMenu.class);
ScoreData scoreData = buttonState.getScoreData();
songMenuState.doStateActionOnLoad(MenuState.SCORE, scoreData);
displayContainer.switchState(songMenuState);
}
},
CLOSE ("Close", Color.gray) {
@@ -556,9 +554,6 @@ public class ButtonMenu extends BaseOpsuState {
}
};
public static DisplayContainer displayContainer;
public static InstanceContainer instanceContainer;
/** The text to show on the button. */
private final String text;
@@ -600,12 +595,6 @@ public class ButtonMenu extends BaseOpsuState {
/** The score data to process in the state. */
private ScoreData scoreData;
public ButtonMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
super();
Button.displayContainer = MenuState.displayContainer = displayContainer;
Button.instanceContainer = MenuState.instanceContainer = instanceContainer;
}
@Override
public void revalidate() {
super.revalidate();
@@ -662,7 +651,7 @@ public class ButtonMenu extends BaseOpsuState {
return true;
}
if (key == Input.KEY_ESCAPE) {
if (key == Keyboard.KEY_ESCAPE) {
menuState.leave();
return true;
}

View File

@@ -22,10 +22,8 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
import itdelatrisu.opsu.beatmap.OszUnpacker;
import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.DownloadList;
import itdelatrisu.opsu.downloads.DownloadNode;
@@ -54,12 +52,11 @@ import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.gui.TextField;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BarNotifListener;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* Downloads menu.
@@ -69,18 +66,6 @@ import yugecin.opsudance.options.Configuration;
*/
public class DownloadsMenu extends ComplexOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
@Inject
private OszUnpacker oszUnpacker;
@Inject
private BeatmapParser beatmapParser;
/** Delay time, in milliseconds, between each search. */
private static final int SEARCH_DELAY = 700;
@@ -275,32 +260,35 @@ public class DownloadsMenu extends ComplexOpsuState {
} finally {
finished = true;
}
};
}
/** Imports all packed beatmaps. */
private void importBeatmaps() {
// invoke unpacker and parser
File[] dirs = oszUnpacker.unpackAll();
if (dirs != null && dirs.length > 0) {
this.importedNode = beatmapParser.parseDirectories(dirs);
if (importedNode != null) {
// send notification
EventBus.post(new BarNotificationEvent((dirs.length == 1) ? "Imported 1 new song." :
String.format("Imported %d new songs.", dirs.length)));
}
}
File[] dirs = oszunpacker.unpackAll();
this.importedNode = beatmapParser.parseDirectories(dirs);
DownloadList.get().clearDownloads(Download.Status.COMPLETE);
if (this.importedNode == null) {
return;
}
String msg;
if (dirs.length == 1) {
msg = "Imported 1 new song.";
} else {
msg = String.format("Imported %d new songs.", dirs.length);
}
BarNotifListener.EVENT.make().onBarNotif(msg);
}
}
@Inject
public DownloadsMenu(InstanceContainer instanceContainer) {
public DownloadsMenu() {
SERVERS = new DownloadServer[] {
instanceContainer.provide(BloodcatServer.class),
instanceContainer.provide(YaSOnlineServer.class),
instanceContainer.provide(MnetworkServer.class),
instanceContainer.provide(MengSkyServer.class),
new BloodcatServer(),
new YaSOnlineServer(),
new MnetworkServer(),
new MengSkyServer(),
};
}
@@ -319,7 +307,7 @@ public class DownloadsMenu extends ComplexOpsuState {
// search
searchTimer = SEARCH_DELAY;
searchResultString = "Loading data from server...";
search = new TextField(displayContainer, Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) {
search = new TextField(Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) {
@Override
public boolean isFocusable() {
return false;
@@ -555,7 +543,7 @@ public class DownloadsMenu extends ComplexOpsuState {
// focus new beatmap
// NOTE: This can't be called in another thread because it makes OpenGL calls.
instanceContainer.provide(SongMenu.class).setFocus(importedNode, -1, true, true);
songMenuState.setFocus(importedNode, -1, true, true);
}
importThread = null;
}
@@ -633,7 +621,7 @@ public class DownloadsMenu extends ComplexOpsuState {
// back
if (UI.getBackButton().contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(MainMenu.class);
displayContainer.switchState(mainmenuState);
return true;
}
@@ -698,7 +686,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (playing)
previewID = node.getID();
} catch (SlickException e) {
EventBus.post(new BarNotificationEvent("Failed to load track preview. See log for details."));
BarNotifListener.EVENT.make().onBarNotif("Failed to load track preview. See log for details.");
Log.error(e);
}
}
@@ -721,7 +709,7 @@ public class DownloadsMenu extends ComplexOpsuState {
if (!DownloadList.get().contains(node.getID())) {
node.createDownload(serverMenu.getSelectedItem());
if (node.getDownload() == null) {
EventBus.post(new BarNotificationEvent("The download could not be started"));
BarNotifListener.EVENT.make().onBarNotif("The download could not be started");
} else {
DownloadList.get().addNode(node);
node.getDownload().start();
@@ -901,12 +889,12 @@ public class DownloadsMenu extends ComplexOpsuState {
}
// block input during beatmap importing
if (importThread != null && key != Input.KEY_ESCAPE) {
if (importThread != null && key != KEY_ESCAPE) {
return true;
}
switch (key) {
case Input.KEY_ESCAPE:
case KEY_ESCAPE:
if (importThread != null) {
// beatmap importing: stop parsing beatmaps by sending interrupt to BeatmapParser
importThread.interrupt();
@@ -918,16 +906,16 @@ public class DownloadsMenu extends ComplexOpsuState {
} else {
// return to main menu
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(MainMenu.class);
displayContainer.switchState(mainmenuState);
}
return true;
case Input.KEY_ENTER:
case KEY_RETURN:
if (!search.getText().isEmpty()) {
pageDir = Page.RESET;
resetSearchTimer();
}
return true;
case Input.KEY_F5:
case KEY_F5:
SoundController.playSound(SoundEffect.MENUCLICK);
lastQuery = null;
pageDir = Page.CURRENT;
@@ -937,7 +925,7 @@ public class DownloadsMenu extends ComplexOpsuState {
return true;
}
// wait for user to finish typing
if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) {
if (Character.isLetterOrDigit(c) || key == KEY_BACK) {
search.keyPressed(key, c);
searchTimer = 0;
pageDir = Page.RESET;
@@ -963,7 +951,7 @@ public class DownloadsMenu extends ComplexOpsuState {
pageDir = Page.RESET;
previewID = -1;
if (barNotificationOnLoad != null) {
EventBus.post(new BarNotificationEvent(barNotificationOnLoad));
BarNotifListener.EVENT.make().onBarNotif(barNotificationOnLoad);
barNotificationOnLoad = null;
}
}

View File

@@ -24,7 +24,6 @@ import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.db.BeatmapDB;
@@ -60,41 +59,26 @@ import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.*;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.options.Options;
import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.sbv2.MoveStoryboard;
import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.ui.OptionsOverlay;
import yugecin.opsudance.ui.StoryboardOverlay;
import yugecin.opsudance.utils.GLHelper;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.options.Options.*;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* "Game" state.
*/
public class Game extends ComplexOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private GameObjectRenderer gameObjectRenderer;
@Inject
private BeatmapParser beatmapParser;
public static boolean isInGame; // TODO delete this when #79 is fixed
/** Game restart states. */
public enum Restart {
@@ -332,7 +316,7 @@ public class Game extends ComplexOpsuState {
private boolean skippedToCheckpoint;
public Game(DisplayContainer displayContainer) {
public Game() {
super();
mirrorCursor = new Cursor(true);
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
@@ -354,7 +338,9 @@ public class Game extends ComplexOpsuState {
gOffscreen.setBackground(Color.black);
} catch (SlickException e) {
Log.error("could not create offscreen graphics", e);
EventBus.post(new BubbleNotificationEvent("Exception while creating offscreen graphics. See logfile for details.", BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(
"Exception while creating offscreen graphics. See logfile for details.",
Colors.BUB_RED);
}
// initialize music position bar location
@@ -370,8 +356,7 @@ public class Game extends ComplexOpsuState {
scoreboardStarStream.setDurationSpread(700, 100);
// create the associated GameData object
data = instanceContainer.injectFields(new GameData(displayContainer.width, displayContainer.height));
gameObjectRenderer.setGameData(data);
gameObjectRenderer.gameData = data = new GameData();
}
@@ -725,10 +710,10 @@ public class Game extends ComplexOpsuState {
displayContainer.cursor.draw(replayKeyPressed);
} else if (GameMod.AUTO.isActive()) {
displayContainer.cursor.draw(autoMousePressed);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
if (OPTION_DANCE_MIRROR.state) {
mirrorCursor.draw(autoMousePressed);
}
} else if (GameMod.AUTOPILOT.isActive()) {
} else {
displayContainer.cursor.draw(Utils.isGameKeyPressed());
}
@@ -775,13 +760,6 @@ public class Game extends ComplexOpsuState {
if (!isLeadIn())
MusicController.resume();
}
// focus lost: go back to pause screen
else if (!Display.isActive()) {
displayContainer.switchStateNow(GamePauseMenu.class);
pausePulse = 0f;
}
// advance pulse animation
else {
pausePulse += delta / 750f;
@@ -895,7 +873,7 @@ public class Game extends ComplexOpsuState {
onCloseRequest();
} else {
// go to ranking screen
displayContainer.switchState(GameRanking.class);
displayContainer.switchState(gameRankingState);
}
}
}
@@ -942,14 +920,16 @@ public class Game extends ComplexOpsuState {
} else if (GameMod.AUTO.isActive()) {
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
double dx = autoMousePosition.x - Options.width / 2d;
double dy = autoMousePosition.y - Options.height / 2d;
double dx = autoMousePosition.x - displayContainer.width / 2d;
double dy = autoMousePosition.y - displayContainer.height / 2d;
double d = Math.sqrt(dx * dx + dy * dy);
double a = Math.atan2(dy, dx) + Math.PI;
mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + Options.width / 2), (int) (Math.sin(a) * d + Options.height / 2));
mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + displayContainer.width / 2), (int) (Math.sin(a) * d + displayContainer.height / 2));
}
} else if (GameMod.AUTOPILOT.isActive()) {
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
} else {
displayContainer.cursor.setCursorPosition(displayContainer.delta, displayContainer.mouseX, displayContainer.mouseY);
}
}
@@ -977,7 +957,7 @@ public class Game extends ComplexOpsuState {
// save score and replay
if (!checkpointLoaded) {
boolean unranked = (GameMod.AUTO.isActive() || GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
instanceContainer.provide(GameRanking.class).setGameData(data);
gameRankingState.setGameData(data);
if (isReplay)
data.setReplay(replay);
else if (replayFrames != null) {
@@ -1063,7 +1043,7 @@ public class Game extends ComplexOpsuState {
if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition;
}
displayContainer.switchStateNow(GamePauseMenu.class);
displayContainer.switchStateInstantly(pauseState);
}
// drain health
@@ -1090,7 +1070,7 @@ public class Game extends ComplexOpsuState {
rotations = new IdentityHashMap<>();
SoundController.playSound(SoundEffect.FAIL);
displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300);
displayContainer.switchState(pauseState, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, 300);
}
}
}
@@ -1123,8 +1103,8 @@ public class Game extends ComplexOpsuState {
@Override
public boolean onCloseRequest() {
instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
displayContainer.switchState(SongMenu.class);
songMenuState.resetGameDataOnLoad();
displayContainer.switchState(songMenuState);
return false;
}
@@ -1156,7 +1136,7 @@ public class Game extends ComplexOpsuState {
}
switch (key) {
case Input.KEY_ESCAPE:
case KEY_ESCAPE:
// "auto" mod or watching replay: go back to song menu
if (GameMod.AUTO.isActive() || isReplay) {
onCloseRequest();
@@ -1171,15 +1151,15 @@ public class Game extends ComplexOpsuState {
if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition;
}
displayContainer.switchStateNow(GamePauseMenu.class);
displayContainer.switchStateInstantly(pauseState);
break;
case Input.KEY_SPACE:
case KEY_SPACE:
// skip intro
skipIntro();
break;
case Input.KEY_R:
case KEY_R:
// restart
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
if (input.isControlDown()) {
if (trackPosition < beatmap.objects[0].getTime()) {
retries--; // don't count this retry (cancel out later increment)
}
@@ -1188,9 +1168,9 @@ public class Game extends ComplexOpsuState {
skipIntro();
}
break;
case Input.KEY_S:
case KEY_S:
// save checkpoint
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
if (input.isControlDown()) {
if (isLeadIn()) {
break;
}
@@ -1200,40 +1180,40 @@ public class Game extends ComplexOpsuState {
if (0 <= time && time < 3600) {
OPTION_CHECKPOINT.setValue(time);
SoundController.playSound(SoundEffect.MENUCLICK);
EventBus.post(new BarNotificationEvent("Checkpoint saved."));
BarNotifListener.EVENT.make().onBarNotif("Checkpoint saved.");
}
}
break;
case Input.KEY_L:
case KEY_L:
// load checkpoint
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
if (input.isControlDown()) {
int checkpoint = OPTION_CHECKPOINT.val * 1000;
if (checkpoint == 0 || checkpoint > beatmap.endTime)
break; // invalid checkpoint
loadCheckpoint(checkpoint);
SoundController.playSound(SoundEffect.MENUHIT);
EventBus.post(new BarNotificationEvent("Checkpoint loaded."));
BarNotifListener.EVENT.make().onBarNotif("Checkpoint loaded.");
}
break;
case Input.KEY_F:
case KEY_F:
// change playback speed
if (isReplay || GameMod.AUTO.isActive()) {
playbackSpeed = playbackSpeed.next();
MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier());
}
break;
case Input.KEY_UP:
case KEY_UP:
UI.changeVolume(1);
break;
case Input.KEY_DOWN:
case KEY_DOWN:
UI.changeVolume(-1);
break;
case Input.KEY_TAB:
case KEY_TAB:
if (!OPTION_DANCE_HIDE_UI.state) {
scoreboardVisible = !scoreboardVisible;
}
break;
case Input.KEY_M:
case KEY_M:
if (OPTION_DANCE_MIRROR.state) {
mirrorTo = objectIndex;
} else {
@@ -1243,7 +1223,7 @@ public class Game extends ComplexOpsuState {
}
OPTION_DANCE_MIRROR.toggle();
break;
case Input.KEY_P:
case KEY_P:
if (OPTION_DANCE_MIRROR.state) {
mirrorTo = objectIndex;
} else {
@@ -1253,14 +1233,14 @@ public class Game extends ComplexOpsuState {
}
OPTION_DANCE_MIRROR.toggle();
break;
case Input.KEY_MINUS:
case KEY_MINUS:
currentMapMusicOffset += 5;
EventBus.post(new BarNotificationEvent("Current map offset: " + currentMapMusicOffset));
BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
break;
}
if (key == Input.KEY_ADD || c == '+') {
if (key == KEY_ADD || c == '+') {
currentMapMusicOffset -= 5;
EventBus.post(new BarNotificationEvent("Current map offset: " + currentMapMusicOffset));
BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
}
return true;
@@ -1324,7 +1304,7 @@ public class Game extends ComplexOpsuState {
if (MusicController.isPlaying() || isLeadIn()) {
pauseTime = trackPosition;
}
displayContainer.switchStateNow(GamePauseMenu.class);
displayContainer.switchStateInstantly(pauseState);
return true;
}
@@ -1425,7 +1405,7 @@ public class Game extends ComplexOpsuState {
keys = ReplayFrame.KEY_K2;
}
if (keys != ReplayFrame.KEY_NONE) {
gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition());
gameKeyReleased(keys, input.getMouseX(), input.getMouseY(), MusicController.getPosition());
}
return true;
@@ -1511,9 +1491,7 @@ public class Game extends ComplexOpsuState {
hue += hueshift;
}
if (isReplay || GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
displayContainer.drawCursor = false;
}
displayContainer.drawCursor = false;
isInGame = true;
if (!skippedToCheckpoint) {
@@ -1521,8 +1499,8 @@ public class Game extends ComplexOpsuState {
}
if (beatmap == null || beatmap.objects == null) {
EventBus.post(new BubbleNotificationEvent("Game was running without a beatmap", BubbleNotificationEvent.COMMONCOLOR_RED));
displayContainer.switchStateInstantly(SongMenu.class);
BubNotifListener.EVENT.make().onBubNotif("Game was running without a beatmap", Colors.BUB_RED);
displayContainer.switchStateInstantly(songMenuState);
}
Dancer.instance.reset();
@@ -1619,16 +1597,16 @@ public class Game extends ComplexOpsuState {
try {
if (hitObject.isCircle()) {
gameObjects[i] = instanceContainer.injectFields(new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
gameObjects[i] = new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
} else if (hitObject.isSlider()) {
gameObjects[i] = instanceContainer.injectFields(new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
gameObjects[i] = new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
} else if (hitObject.isSpinner()) {
gameObjects[i] = new Spinner(hitObject, this, data);
}
} catch (Exception e) {
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
Log.error(message, e);
EventBus.post(new BubbleNotificationEvent(message, BubbleNotificationEvent.COMMONCOLOR_RED));
BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED);
gameObjects[i] = new DummyObject(hitObject);
}
}
@@ -1909,7 +1887,7 @@ public class Game extends ComplexOpsuState {
gameObj.draw(g, trackPosition, false);
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
g.pushTransform();
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
g.rotate(displayContainer.width / 2f, displayContainer.height / 2f, 180f);
gameObj.draw(g, trackPosition, true);
g.popTransform();
}
@@ -2053,7 +2031,7 @@ public class Game extends ComplexOpsuState {
skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT);
// load other images...
instanceContainer.provide(GamePauseMenu.class).loadImages();
pauseState.loadImages();
data.loadImages();
}
@@ -2090,7 +2068,7 @@ public class Game extends ComplexOpsuState {
// initialize objects
gameObjectRenderer.initForGame(data, diameter);
Slider.init(gameObjectRenderer.getCircleDiameter(), beatmap);
Slider.init(gameObjectRenderer.circleDiameter, beatmap);
Spinner.init(displayContainer, overallDifficulty);
Color sliderBorderColor = SkinService.skin.getSliderBorderColor();
if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) {
@@ -2214,7 +2192,8 @@ public class Game extends ComplexOpsuState {
this.replay = null;
} else {
if (replay.frames == null) {
EventBus.post(new BubbleNotificationEvent("Attempting to set a replay with no frames.", BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif("Attempting to set a replay with no frames.",
Colors.BUB_ORANGE);
return;
}
this.isReplay = true;

View File

@@ -30,10 +30,10 @@ import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.BaseOpsuState;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -44,12 +44,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class GamePauseMenu extends BaseOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Game gameState;
private MenuButton continueButton, retryButton, backButton;
@Override
@@ -101,24 +95,24 @@ public class GamePauseMenu extends BaseOpsuState {
}
}
if (key == Input.KEY_ESCAPE) {
if (key == KEY_ESCAPE) {
// 'esc' will normally unpause, but will return to song menu if health is zero
if (gameState.getRestart() == Game.Restart.LOSE) {
SoundController.playSound(SoundEffect.MENUBACK);
instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
songMenuState.resetGameDataOnLoad();
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
displayContainer.switchState(SongMenu.class);
displayContainer.switchState(songMenuState);
} else {
SoundController.playSound(SoundEffect.MENUBACK);
gameState.setRestart(Game.Restart.FALSE);
displayContainer.switchState(Game.class);
displayContainer.switchState(gameState);
}
return true;
}
if (key == Input.KEY_R && (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL))) {
if (key == KEY_R && input.isControlDown()) {
gameState.setRestart(Game.Restart.MANUAL);
displayContainer.switchState(Game.class);
displayContainer.switchState(gameState);
return true;
}
@@ -139,14 +133,14 @@ public class GamePauseMenu extends BaseOpsuState {
if (continueButton.contains(x, y) && !loseState) {
SoundController.playSound(SoundEffect.MENUBACK);
gameState.setRestart(Game.Restart.FALSE);
displayContainer.switchState(Game.class);
displayContainer.switchState(gameState);
} else if (retryButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
gameState.setRestart(Game.Restart.MANUAL);
displayContainer.switchState(Game.class);
displayContainer.switchState(gameState);
} else if (backButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
songMenuState.resetGameDataOnLoad();
if (loseState)
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
else
@@ -155,7 +149,7 @@ public class GamePauseMenu extends BaseOpsuState {
displayContainer.resetCursor();
}
MusicController.setPitch(1.0f);
displayContainer.switchState(SongMenu.class);
displayContainer.switchState(songMenuState);
}
return true;
@@ -188,10 +182,9 @@ public class GamePauseMenu extends BaseOpsuState {
@Override
public boolean onCloseRequest() {
SongMenu songmenu = instanceContainer.provide(SongMenu.class);
songmenu.resetTrackOnLoad();
songmenu.resetGameDataOnLoad();
displayContainer.switchState(SongMenu.class);
songMenuState.resetTrackOnLoad();
songMenuState.resetGameDataOnLoad();
displayContainer.switchState(songMenuState);
return false;
}

View File

@@ -32,15 +32,15 @@ import itdelatrisu.opsu.ui.UI;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.BaseOpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BarNotifListener;
import static yugecin.opsudance.core.InstanceContainer.*;
/**
* "Game Ranking" (score card) state.
@@ -51,9 +51,6 @@ import yugecin.opsudance.events.BarNotificationEvent;
*/
public class GameRanking extends BaseOpsuState {
@Inject
private InstanceContainer instanceContainer;
/** Associated GameData object. */
private GameData data;
@@ -125,7 +122,7 @@ public class GameRanking extends BaseOpsuState {
return true;
}
if (key == Input.KEY_ESCAPE) {
if (key == Keyboard.KEY_ESCAPE) {
returnToSongMenu();
}
return true;
@@ -149,7 +146,6 @@ public class GameRanking extends BaseOpsuState {
}
// replay
Game gameState = instanceContainer.provide(Game.class);
boolean returnToGame = false;
boolean replayButtonPressed = replayButton.contains(x, y);
if (replayButtonPressed && !(data.isGameplay() && GameMod.AUTO.isActive())) {
@@ -161,13 +157,14 @@ public class GameRanking extends BaseOpsuState {
gameState.setRestart((data.isGameplay()) ? Game.Restart.REPLAY : Game.Restart.NEW);
returnToGame = true;
} catch (FileNotFoundException e) {
EventBus.post(new BarNotificationEvent("Replay file not found."));
BarNotifListener.EVENT.make().onBarNotif("Replay file not found.");
} catch (IOException e) {
Log.error("Failed to load replay data.", e);
EventBus.post(new BarNotificationEvent("Failed to load replay data. See log for details."));
BarNotifListener.EVENT.make().onBarNotif(
"Failed to load replay data. See log for details.");
}
} else
EventBus.post(new BarNotificationEvent("Replay file not found."));
BarNotifListener.EVENT.make().onBarNotif("Replay file not found.");
}
// retry
@@ -183,7 +180,7 @@ public class GameRanking extends BaseOpsuState {
Beatmap beatmap = MusicController.getBeatmap();
gameState.loadBeatmap(beatmap);
SoundController.playSound(SoundEffect.MENUHIT);
displayContainer.switchState(Game.class);
displayContainer.switchState(gameState);
}
return true;
}
@@ -217,12 +214,11 @@ public class GameRanking extends BaseOpsuState {
@Override
public boolean onCloseRequest() {
SongMenu songmenu = instanceContainer.provide(SongMenu.class);
if (data != null && data.isGameplay()) {
songmenu.resetTrackOnLoad();
songMenuState.resetTrackOnLoad();
}
songmenu.resetGameDataOnLoad();
displayContainer.switchState(SongMenu.class);
songMenuState.resetGameDataOnLoad();
displayContainer.switchState(songMenuState);
return false;
}
@@ -232,25 +228,24 @@ public class GameRanking extends BaseOpsuState {
private void returnToSongMenu() {
SoundController.muteSoundComponent();
SoundController.playSound(SoundEffect.MENUBACK);
SongMenu songMenu = instanceContainer.provide(SongMenu.class);
if (data.isGameplay()) {
songMenu.resetTrackOnLoad();
songMenuState.resetTrackOnLoad();
}
songMenu.resetGameDataOnLoad();
songMenuState.resetGameDataOnLoad();
if (displayContainer.cursor.isBeatmapSkinned()) {
displayContainer.resetCursor();
}
displayContainer.switchState(SongMenu.class);
displayContainer.switchState(songMenuState);
}
/**
* Sets the associated GameData object.
* @param data the GameData
*/
public void setGameData(GameData data) { this.data = data; }
public void setGameData(GameData data) { this.data = data; } // TODO why is this unused
/**
* Returns the current GameData object (usually null unless state active).
*/
public GameData getGameData() { return data; }
public GameData getGameData() { return data; } // TODO why is this unused
}

View File

@@ -45,14 +45,14 @@ import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.Constants;
import yugecin.opsudance.core.state.BaseOpsuState;
import yugecin.opsudance.core.state.OpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.events.BubNotifListener;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -62,12 +62,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class MainMenu extends BaseOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Updater updater;
/** Idle time, in milliseconds, before returning the logo to its original position. */
private static final short LOGO_IDLE_DELAY = 10000;
@@ -472,12 +466,11 @@ public class MainMenu extends BaseOpsuState {
UI.enter();
if (!enterNotification) {
if (updater.getStatus() == Updater.Status.UPDATE_AVAILABLE) {
EventBus.post(new BarNotificationEvent("An opsu! update is available."));
enterNotification = true;
BarNotifListener.EVENT.make().onBarNotif("An opsu! update is available.");
} else if (updater.justUpdated()) {
EventBus.post(new BarNotificationEvent("opsu! is now up to date!"));
enterNotification = true;
BarNotifListener.EVENT.make().onBarNotif("opsu! is now up to date!");
}
enterNotification = true;
}
// reset measure info
@@ -538,58 +531,60 @@ public class MainMenu extends BaseOpsuState {
if (musicPlay.contains(x, y)) {
if (MusicController.isPlaying()) {
MusicController.pause();
EventBus.post(new BarNotificationEvent("Pause"));
BarNotifListener.EVENT.make().onBarNotif("Pause");
} else if (!MusicController.isTrackLoading()) {
MusicController.resume();
EventBus.post(new BarNotificationEvent("Play"));
BarNotifListener.EVENT.make().onBarNotif("Play");
}
return true;
} else if (musicNext.contains(x, y)) {
nextTrack(true);
EventBus.post(new BarNotificationEvent(">> Next"));
BarNotifListener.EVENT.make().onBarNotif(">> Next");
return true;
} else if (musicPrevious.contains(x, y)) {
lastMeasureProgress = 0f;
if (!previous.isEmpty()) {
instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
songMenuState.setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
if (OPTION_DYNAMIC_BACKGROUND.state) {
bgAlpha.setTime(0);
}
} else {
MusicController.setPosition(0);
}
EventBus.post(new BarNotificationEvent("<< Previous"));
BarNotifListener.EVENT.make().onBarNotif("<< Previous");
return true;
}
// downloads button actions
if (downloadsButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
displayContainer.switchState(DownloadsMenu.class);
displayContainer.switchState(downloadState);
return true;
}
// repository button actions
if (repoButton != null && repoButton.contains(x, y)) {
try {
Desktop.getDesktop().browse(config.REPOSITORY_URI);
Desktop.getDesktop().browse(Constants.REPOSITORY_URI);
} catch (UnsupportedOperationException e) {
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
BarNotifListener.EVENT.make().onBarNotif(
"The repository web page could not be opened.");
} catch (IOException e) {
Log.error("could not browse to repo", e);
EventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif("Could not browse to repo", Colors.BUB_ORANGE);
}
return true;
}
if (danceRepoButton != null && danceRepoButton.contains(x, y)) {
try {
Desktop.getDesktop().browse(config.DANCE_REPOSITORY_URI);
Desktop.getDesktop().browse(Constants.DANCE_REPOSITORY_URI);
} catch (UnsupportedOperationException e) {
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
BarNotifListener.EVENT.make().onBarNotif(
"The repository web page could not be opened.");
} catch (IOException e) {
Log.error("could not browse to repo", e);
EventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE));
BubNotifListener.EVENT.make().onBubNotif("Could not browse to repo", Colors.BUB_ORANGE);
}
return true;
}
@@ -657,18 +652,18 @@ public class MainMenu extends BaseOpsuState {
}
switch (key) {
case Input.KEY_ESCAPE:
case Input.KEY_Q:
case KEY_ESCAPE:
case KEY_Q:
if (logoTimer > 0) {
logoState = LogoState.CLOSING;
logoClose.setTime(0);
logoTimer = 0;
break;
}
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.EXIT);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(MenuState.EXIT);
displayContainer.switchState(buttonState);
return true;
case Input.KEY_P:
case KEY_P:
SoundController.playSound(SoundEffect.MENUHIT);
if (logoState == LogoState.DEFAULT || logoState == LogoState.CLOSING) {
logoState = LogoState.OPENING;
@@ -679,17 +674,17 @@ public class MainMenu extends BaseOpsuState {
} else
enterSongMenu();
return true;
case Input.KEY_D:
case KEY_D:
SoundController.playSound(SoundEffect.MENUHIT);
displayContainer.switchState(DownloadsMenu.class);
displayContainer.switchState(downloadState);
return true;
case Input.KEY_R:
case KEY_R:
nextTrack(true);
return true;
case Input.KEY_UP:
case KEY_UP:
UI.changeVolume(1);
return true;
case Input.KEY_DOWN:
case KEY_DOWN:
UI.changeVolume(-1);
return true;
}
@@ -719,7 +714,7 @@ public class MainMenu extends BaseOpsuState {
MusicController.playAt(0, false);
return;
}
BeatmapSetNode node = instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
BeatmapSetNode node = songMenuState.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
boolean sameAudio = false;
if (node != null) {
sameAudio = MusicController.getBeatmap().audioFilename.equals(node.getBeatmapSet().get(0).audioFilename);
@@ -735,10 +730,10 @@ public class MainMenu extends BaseOpsuState {
* Enters the song menu, or the downloads menu if no beatmaps are loaded.
*/
private void enterSongMenu() {
Class<? extends OpsuState> state = SongMenu.class;
OpsuState state = songMenuState;
if (BeatmapSetList.get().getMapSetCount() == 0) {
instanceContainer.provide(DownloadsMenu.class).notifyOnLoad("Download some beatmaps to get started!");
state = DownloadsMenu.class;
downloadState.notifyOnLoad("Download some beatmaps to get started!");
state = downloadState;
}
displayContainer.switchState(state);
}

View File

@@ -35,7 +35,6 @@ import itdelatrisu.opsu.beatmap.BeatmapSortOrder;
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
import itdelatrisu.opsu.beatmap.BeatmapWatchService.BeatmapWatchServiceListener;
import itdelatrisu.opsu.beatmap.LRUCache;
import itdelatrisu.opsu.beatmap.OszUnpacker;
import itdelatrisu.opsu.db.BeatmapDB;
import itdelatrisu.opsu.db.ScoreDB;
import itdelatrisu.opsu.states.ButtonMenu.MenuState;
@@ -56,6 +55,7 @@ import java.nio.file.WatchEvent.Kind;
import java.util.Map;
import java.util.Stack;
import org.lwjgl.input.Mouse;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
@@ -63,16 +63,13 @@ import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.gui.TextField;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.events.BarNotifListener;
import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.ui.OptionsOverlay;
import static org.lwjgl.input.Keyboard.*;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -83,18 +80,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class SongMenu extends ComplexOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
@Inject
private OszUnpacker oszUnpacker;
@Inject
private BeatmapParser beatmapParser;
/** The max number of song buttons to be shown on each screen. */
public static final int MAX_SONG_BUTTONS = 6;
@@ -246,7 +231,7 @@ public class SongMenu extends ComplexOpsuState {
private void reloadBeatmaps() {
if (fullReload) {
BeatmapDB.clearDatabase();
oszUnpacker.unpackAll();
oszunpacker.unpackAll();
}
beatmapParser.parseAll();
}
@@ -328,7 +313,7 @@ public class SongMenu extends ComplexOpsuState {
private final OptionsOverlay optionsOverlay;
public SongMenu(DisplayContainer displayContainer) {
public SongMenu() {
super();
optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.normalOptions);
overlays.add(optionsOverlay);
@@ -406,7 +391,7 @@ public class SongMenu extends ComplexOpsuState {
// search
int textFieldX = (int) (displayContainer.width * 0.7125f + Fonts.BOLD.getWidth("Search: "));
int textFieldY = (int) (headerY + Fonts.BOLD.getLineHeight() / 2);
searchTextField = new TextField(displayContainer, Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
searchTextField = new TextField(Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
@Override
public boolean isFocusable() {
return false;
@@ -454,12 +439,15 @@ public class SongMenu extends ComplexOpsuState {
BeatmapWatchService.addListener(new BeatmapWatchServiceListener() {
@Override
public void eventReceived(Kind<?> kind, Path child) {
if (!songFolderChanged && kind != StandardWatchEventKinds.ENTRY_MODIFY) {
songFolderChanged = true;
if (displayContainer.isInState(SongMenu.class)) {
EventBus.post(new BarNotificationEvent("Changed is Songs folder detected. Hit F5 to refresh."));
}
if (songFolderChanged || kind == StandardWatchEventKinds.ENTRY_MODIFY) {
return;
}
songFolderChanged = true;
if (!displayContainer.isInState(SongMenu.class)) {
return;
}
BarNotifListener.EVENT.make().onBarNotif(
"Changed is Songs folder detected. Hit F5 to refresh.");
}
});
@@ -761,8 +749,8 @@ public class SongMenu extends ComplexOpsuState {
if (focusNode != null) {
MenuState state = focusNode.getBeatmapSet().isFavorite() ?
MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP;
instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(state, focusNode);
displayContainer.switchState(buttonState);
}
return;
}
@@ -922,19 +910,19 @@ public class SongMenu extends ComplexOpsuState {
if (UI.getBackButton().contains(x, y)) {
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(MainMenu.class);
displayContainer.switchState(mainmenuState);
return true;
}
// selection buttons
if (selectModsButton.contains(x, y)) {
this.keyPressed(Input.KEY_F1, '\0');
this.keyPressed(KEY_F1, '\0');
return true;
} else if (selectRandomButton.contains(x, y)) {
this.keyPressed(Input.KEY_F2, '\0');
this.keyPressed(KEY_F2, '\0');
return true;
} else if (selectMapOptionsButton.contains(x, y)) {
this.keyPressed(Input.KEY_F3, '\0');
this.keyPressed(KEY_F3, '\0');
return true;
} else if (selectOptionsButton.contains(x, y)) {
SoundController.playSound(SoundEffect.MENUHIT);
@@ -944,30 +932,32 @@ public class SongMenu extends ComplexOpsuState {
// group tabs
for (BeatmapGroup group : BeatmapGroup.values()) {
if (group.contains(x, y)) {
if (group != BeatmapGroup.current()) {
BeatmapGroup.set(group);
SoundController.playSound(SoundEffect.MENUCLICK);
startNode = focusNode = null;
oldFocusNode = null;
randomStack = new Stack<SongNode>();
songInfo = null;
scoreMap = null;
focusScores = null;
searchTextField.setText("");
searchTimer = SEARCH_DELAY;
searchTransitionTimer = SEARCH_TRANSITION_TIME;
searchResultString = null;
BeatmapSetList.get().reset();
BeatmapSetList.get().init();
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) {
EventBus.post(new BarNotificationEvent(group.getEmptyMessage()));
}
}
if (!group.contains(x, y)) {
continue;
}
if (group == BeatmapGroup.current()) {
return true;
}
BeatmapGroup.set(group);
SoundController.playSound(SoundEffect.MENUCLICK);
startNode = focusNode = null;
oldFocusNode = null;
randomStack = new Stack<SongNode>();
songInfo = null;
scoreMap = null;
focusScores = null;
searchTextField.setText("");
searchTimer = SEARCH_DELAY;
searchTransitionTimer = SEARCH_TRANSITION_TIME;
searchResultString = null;
BeatmapSetList.get().reset();
BeatmapSetList.get().init();
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) {
BarNotifListener.EVENT.make().onBarNotif(group.getEmptyMessage());
}
return true;
}
if (focusNode == null) {
@@ -1029,12 +1019,12 @@ public class SongMenu extends ComplexOpsuState {
SoundController.playSound(SoundEffect.MENUHIT);
if (button != Input.MOUSE_RIGHT_BUTTON) {
// view score
instanceContainer.provide(GameRanking.class).setGameData(instanceContainer.injectFields(new GameData(focusScores[rank], displayContainer.width, displayContainer.height)));
displayContainer.switchState(GameRanking.class);
gameRankingState.setGameData(new GameData(focusScores[rank]));
displayContainer.switchState(gameRankingState);
} else {
// score management
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.SCORE, focusScores[rank]);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(MenuState.SCORE, focusScores[rank]);
displayContainer.switchState(buttonState);
}
return true;
}
@@ -1050,14 +1040,12 @@ public class SongMenu extends ComplexOpsuState {
}
// block input
if ((reloadThread != null && key != Input.KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) {
if ((reloadThread != null && key != KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) {
return true;
}
Input input = displayContainer.input;
switch (key) {
case Input.KEY_ESCAPE:
case KEY_ESCAPE:
if (reloadThread != null) {
// beatmap reloading: stop parsing beatmaps by sending interrupt to BeatmapParser
reloadThread.interrupt();
@@ -1070,19 +1058,19 @@ public class SongMenu extends ComplexOpsuState {
} else {
// return to main menu
SoundController.playSound(SoundEffect.MENUBACK);
displayContainer.switchState(MainMenu.class);
displayContainer.switchState(mainmenuState);
}
return true;
case Input.KEY_F1:
case KEY_F1:
SoundController.playSound(SoundEffect.MENUHIT);
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.MODS);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(MenuState.MODS);
displayContainer.switchState(buttonState);
return true;
case Input.KEY_F2:
case KEY_F2:
if (focusNode == null)
break;
SoundController.playSound(SoundEffect.MENUHIT);
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
if (isKeyDown(KEY_RSHIFT) || isKeyDown(KEY_LSHIFT)) {
// shift key: previous random track
SongNode prev;
if (randomStack.isEmpty() || (prev = randomStack.pop()) == null)
@@ -1098,47 +1086,47 @@ public class SongMenu extends ComplexOpsuState {
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
}
return true;
case Input.KEY_F3:
case KEY_F3:
if (focusNode == null)
break;
SoundController.playSound(SoundEffect.MENUHIT);
MenuState state = focusNode.getBeatmapSet().isFavorite() ?
MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP;
instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(state, focusNode);
displayContainer.switchState(buttonState);
return true;
case Input.KEY_F5:
case KEY_F5:
SoundController.playSound(SoundEffect.MENUHIT);
if (songFolderChanged)
reloadBeatmaps(false);
else {
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.RELOAD);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(MenuState.RELOAD);
displayContainer.switchState(buttonState);
}
return true;
case Input.KEY_DELETE:
case KEY_DELETE:
if (focusNode == null)
break;
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
if (isKeyDown(KEY_RSHIFT) || isKeyDown(KEY_LSHIFT)) {
SoundController.playSound(SoundEffect.MENUHIT);
MenuState ms = (focusNode.beatmapIndex == -1 || focusNode.getBeatmapSet().size() == 1) ?
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
instanceContainer.provide(ButtonMenu.class).setMenuState(ms, focusNode);
displayContainer.switchState(ButtonMenu.class);
buttonState.setMenuState(ms, focusNode);
displayContainer.switchState(buttonState);
}
return true;
case Input.KEY_ENTER:
case KEY_RETURN:
if (focusNode == null)
break;
startGame();
return true;
case Input.KEY_DOWN:
case KEY_DOWN:
changeIndex(1);
return true;
case Input.KEY_UP:
case KEY_UP:
changeIndex(-1);
return true;
case Input.KEY_RIGHT:
case KEY_RIGHT:
if (focusNode == null)
break;
BeatmapSetNode next = focusNode.next;
@@ -1154,7 +1142,7 @@ public class SongMenu extends ComplexOpsuState {
}
}
return true;
case Input.KEY_LEFT:
case KEY_LEFT:
if (focusNode == null)
break;
BeatmapSetNode prev = focusNode.prev;
@@ -1170,25 +1158,25 @@ public class SongMenu extends ComplexOpsuState {
}
}
return true;
case Input.KEY_NEXT:
case KEY_NEXT:
changeIndex(MAX_SONG_BUTTONS);
return true;
case Input.KEY_PRIOR:
case KEY_PRIOR:
changeIndex(-MAX_SONG_BUTTONS);
return true;
}
if (key == Input.KEY_O && (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL))) {
if (key == KEY_O && input.isControlDown()) {
optionsOverlay.show();
return true;
}
// wait for user to finish typing
// TODO: accept all characters (current conditions are from TextField class)
if ((c > 31 && c < 127) || key == Input.KEY_BACK) {
if ((c > 31 && c < 127) || key == KEY_BACK) {
searchTimer = 0;
searchTextField.keyPressed(key, c);
int textLength = searchTextField.getText().length();
if (lastSearchTextLength != textLength) {
if (key == Input.KEY_BACK) {
if (key == KEY_BACK) {
if (textLength == 0)
searchTransitionTimer = 0;
} else if (textLength == 1)
@@ -1216,9 +1204,9 @@ public class SongMenu extends ComplexOpsuState {
// check mouse button (right click scrolls faster on songs)
int multiplier;
if (displayContainer.input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
if (Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
multiplier = 10;
} else if (displayContainer.input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
} else if (Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON)) {
multiplier = 1;
} else {
return false;
@@ -1238,8 +1226,6 @@ public class SongMenu extends ComplexOpsuState {
return true;
}
Input input = displayContainer.input;
if (isInputBlocked()) {
return true;
}
@@ -1310,7 +1296,7 @@ public class SongMenu extends ComplexOpsuState {
// reset game data
if (resetGame) {
instanceContainer.provide(Game.class).resetGameData();
gameState.resetGameData();
// destroy extra Clips
MultiClip.destroyExtraClips();
@@ -1775,22 +1761,20 @@ public class SongMenu extends ComplexOpsuState {
Beatmap beatmap = MusicController.getBeatmap();
if (focusNode == null || beatmap != focusNode.getSelectedBeatmap()) {
EventBus.post(new BarNotificationEvent("Unable to load the beatmap audio."));
BarNotifListener.EVENT.make().onBarNotif("Unable to load the beatmap audio.");
return;
}
// turn on "auto" mod if holding "ctrl" key
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
if (!GameMod.AUTO.isActive())
GameMod.AUTO.toggle(true);
if (input.isControlDown() && !GameMod.AUTO.isActive()) {
GameMod.AUTO.toggle(true);
}
SoundController.playSound(SoundEffect.MENUHIT);
MultiClip.destroyExtraClips();
Game gameState = instanceContainer.provide(Game.class);
gameState.loadBeatmap(beatmap);
gameState.setRestart(Game.Restart.NEW);
gameState.setReplay(null);
displayContainer.switchState(Game.class);
displayContainer.switchState(gameState);
}
}

View File

@@ -21,20 +21,18 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.beatmap.OszUnpacker;
import itdelatrisu.opsu.replay.ReplayImporter;
import itdelatrisu.opsu.ui.UI;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.opengl.renderer.Renderer;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.state.BaseOpsuState;
import static yugecin.opsudance.core.InstanceContainer.*;
import static yugecin.opsudance.options.Options.*;
/**
@@ -44,18 +42,6 @@ import static yugecin.opsudance.options.Options.*;
*/
public class Splash extends BaseOpsuState {
@Inject
private SongMenu songMenu;
@Inject
private ReplayImporter replayImporter;
@Inject
private OszUnpacker oszUnpacker;
@Inject
private BeatmapParser beatmapParser;
/** Whether or not loading has completed. */
private boolean finished;
@@ -73,7 +59,7 @@ public class Splash extends BaseOpsuState {
super.revalidate();
// pre-revalidate some states to reduce lag between switching
songMenu.revalidate();
songMenuState.revalidate();
if (inited) {
return;
@@ -86,7 +72,7 @@ public class Splash extends BaseOpsuState {
thread = new Thread() {
@Override
public void run() {
oszUnpacker.unpackAll();
oszunpacker.unpackAll();
beatmapParser.parseAll();
replayImporter.importAll();
@@ -109,7 +95,7 @@ public class Splash extends BaseOpsuState {
// initialize song list
if (BeatmapSetList.get().size() == 0) {
MusicController.playThemeSong(config.themeBeatmap);
displayContainer.switchStateInstantly(MainMenu.class);
displayContainer.switchStateInstantly(mainmenuState);
return;
}
@@ -117,9 +103,9 @@ public class Splash extends BaseOpsuState {
if (OPTION_ENABLE_THEME_SONG.state) {
MusicController.playThemeSong(config.themeBeatmap);
} else {
songMenu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
songMenuState.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
}
displayContainer.switchStateInstantly(MainMenu.class);
displayContainer.switchStateInstantly(mainmenuState);
}
@Override
@@ -147,7 +133,7 @@ public class Splash extends BaseOpsuState {
@Override
public boolean keyPressed(int key, char c) {
if (key != Input.KEY_ESCAPE) {
if (key != Keyboard.KEY_ESCAPE) {
return false;
}
if (++escapeCount >= 3) {

View File

@@ -49,6 +49,11 @@ public class Colors {
BLACK_BG_NORMAL = new Color(0, 0, 0, 0.25f),
BLACK_BG_HOVER = new Color(0, 0, 0, 0.5f),
BLACK_BG_FOCUS = new Color(0, 0, 0, 0.75f),
BUB_GREEN = new Color(98, 131, 59),
BUB_WHITE = new Color(220, 220, 220),
BUB_PURPLE = new Color(94, 46, 149),
BUB_RED = new Color(141, 49, 16),
BUB_ORANGE = new Color(138, 72, 51),
GHOST_LOGO = new Color(1.0f, 1.0f, 1.0f, 0.25f);
// This class should not be instantiated.

View File

@@ -22,6 +22,7 @@ import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Color;
import org.newdawn.slick.Font;
import org.newdawn.slick.Graphics;
@@ -82,7 +83,7 @@ public class DropdownMenu<E> extends Component {
@Override
public void keyPressed(int key, char c) {
if (key == Input.KEY_ESCAPE) {
if (key == Keyboard.KEY_ESCAPE) {
this.expanded = false;
}
}

View File

@@ -34,7 +34,7 @@ import org.newdawn.slick.font.effects.ColorEffect;
import org.newdawn.slick.font.effects.Effect;
import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.core.Constants;
/**
* Fonts used for drawing.
@@ -54,9 +54,9 @@ public class Fonts {
* @throws FontFormatException if any font stream data does not contain the required font tables
* @throws IOException if a font stream cannot be completely read
*/
public static void init(Configuration config) throws SlickException, FontFormatException, IOException {
public static void init() throws SlickException, FontFormatException, IOException {
float fontBase = 12f * GameImage.getUIscale();
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, ResourceLoader.getResourceAsStream(config.FONT_NAME));
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, ResourceLoader.getResourceAsStream(Constants.FONT_NAME));
Font font = javaFont.deriveFont(Font.PLAIN, (int) (fontBase * 4 / 3));
DEFAULT = new UnicodeFont(font);
BOLD = new UnicodeFont(font.deriveFont(Font.BOLD));

View File

@@ -47,7 +47,7 @@ public class KineticScrolling {
private float totalDelta;
/** The maximum and minimum value the position can reach. */
private float max = Float.MAX_VALUE, min = -Float.MAX_VALUE;
public float max = Float.MAX_VALUE, min = -Float.MAX_VALUE;
/** Whether the mouse is currently pressed or not. */
private boolean pressed = false;