Merge branch 'master' into replaystuff
# Conflicts: # src/itdelatrisu/opsu/states/Game.java
This commit is contained in:
@@ -8,7 +8,8 @@ import itdelatrisu.opsu.objects.GameObject;
|
||||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
/**
|
||||
* This class is just a dummy {@link GameObject} to place in the middle of 2 GameObjects.
|
||||
@@ -22,8 +23,8 @@ public class FakeGameObject extends GameObject {
|
||||
public FakeGameObject() {
|
||||
this.start = new Vec2f();
|
||||
this.end = new Vec2f();
|
||||
this.start.x = this.end.x = Options.width / 2;
|
||||
this.start.y = this.end.y = Options.height / 2;
|
||||
this.start.x = this.end.x = displayContainer.width / 2;
|
||||
this.start.y = this.end.y = displayContainer.height / 2;
|
||||
}
|
||||
|
||||
public FakeGameObject(GameObject start, GameObject end) {
|
||||
|
||||
@@ -5,7 +5,8 @@ import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import yugecin.opsudance.movers.Mover;
|
||||
import yugecin.opsudance.movers.factories.AutoMoverFactory;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Created by Alex Wieser on 09.10.2016.
|
||||
@@ -130,6 +131,6 @@ public class CombinedSpiralMover extends Mover {
|
||||
}
|
||||
|
||||
private boolean checkBounds(double[] pos) {
|
||||
return 0 < pos[0] && pos[0] < Options.width && 0 < pos[1] && pos[1] < Options.height;
|
||||
return 0 < pos[0] && pos[0] < displayContainer.width && 0 < pos[1] && pos[1] < displayContainer.height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import awlex.ospu.movers.CombinedSpiralMover;
|
||||
import yugecin.opsudance.movers.Mover;
|
||||
import awlex.ospu.movers.SpiralToMover;
|
||||
import yugecin.opsudance.movers.factories.MoverFactory;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
/**
|
||||
* Created by Alex Wieser on 09.10.2016.
|
||||
@@ -87,7 +88,7 @@ public class SpiralMoverFactory implements MoverFactory {
|
||||
* @return
|
||||
*/
|
||||
private boolean checkBounds(double[] pos) {
|
||||
return 0 < pos[0] && pos[0] < Options.width && 0 < pos[1] && pos[1] < Options.height;
|
||||
return 0 < pos[0] && pos[0] < displayContainer.width && 0 < pos[1] && pos[1] < displayContainer.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package awlex.ospu.spinners;
|
||||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import yugecin.opsudance.options.Options;
|
||||
import yugecin.opsudance.spinners.Spinner;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Created by Alex Wieser on 09.10.2016.
|
||||
* WHO DO YOU THINK I AM?
|
||||
@@ -42,11 +43,11 @@ public class SpiralSpinner extends Spinner {
|
||||
double ang;
|
||||
double rad;
|
||||
for (int i = 0; i < SIZE / 2; i++) {
|
||||
MAX_RAD = (int) (Options.height * .35);
|
||||
MAX_RAD = (int) (displayContainer.height * .35);
|
||||
ang = (DENSITY * (Math.PI / SIZE) * i);
|
||||
rad = (MAX_RAD / (SIZE / 2)) * i;
|
||||
int offsetX = Options.width / 2;
|
||||
int offsetY = Options.height / 2;
|
||||
int offsetX = displayContainer.width / 2;
|
||||
int offsetY = displayContainer.height / 2;
|
||||
points[SIZE / 2 - 1 - i] = new double[]{
|
||||
offsetX + rad * Math.cos(ang),
|
||||
offsetY + rad * Math.sin(ang)
|
||||
@@ -83,12 +84,12 @@ public class SpiralSpinner extends Spinner {
|
||||
}
|
||||
|
||||
private void rotatePointAroundCenter(double[] point, double beta) {
|
||||
double angle = Math.atan2(point[1] - Options.height / 2, point[0] - Options.width / 2);
|
||||
double rad = Utils.distance(point[0], point[1], Options.width / 2, Options.height / 2);
|
||||
double angle = Math.atan2(point[1] - displayContainer.height / 2, point[0] - displayContainer.width / 2);
|
||||
double rad = Utils.distance(point[0], point[1], displayContainer.width / 2, displayContainer.height / 2);
|
||||
|
||||
//rotationMatrix
|
||||
point[0] = Options.width / 2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta));
|
||||
point[1] = Options.height / 2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
|
||||
point[0] = displayContainer.width / 2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta));
|
||||
point[1] = displayContainer.height / 2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
10
src/org/newdawn/slick/InputListener.java
Normal file
10
src/org/newdawn/slick/InputListener.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.newdawn.slick;
|
||||
|
||||
/**
|
||||
* A listener that will be notified of keyboard and mouse events
|
||||
* Edited for opsu!
|
||||
*
|
||||
* @author kevin
|
||||
*/
|
||||
public interface InputListener extends MouseListener, KeyListener {
|
||||
}
|
||||
27
src/org/newdawn/slick/KeyListener.java
Normal file
27
src/org/newdawn/slick/KeyListener.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package org.newdawn.slick;
|
||||
|
||||
/**
|
||||
* Describes classes capable of responding to key presses
|
||||
* Edited for opsu!
|
||||
*
|
||||
* @author kevin
|
||||
*/
|
||||
public interface KeyListener {
|
||||
|
||||
/**
|
||||
* Notification that a key was pressed
|
||||
*
|
||||
* @param key The key code that was pressed (@see org.newdawn.slick.Input)
|
||||
* @param c The character of the key that was pressed
|
||||
*/
|
||||
boolean keyPressed(int key, char c);
|
||||
|
||||
/**
|
||||
* Notification that a key was released
|
||||
*
|
||||
* @param key The key code that was released (@see org.newdawn.slick.Input)
|
||||
* @param c The character of the key that was released
|
||||
*/
|
||||
boolean keyReleased(int key, char c);
|
||||
|
||||
}
|
||||
46
src/org/newdawn/slick/MouseListener.java
Normal file
46
src/org/newdawn/slick/MouseListener.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package org.newdawn.slick;
|
||||
|
||||
/**
|
||||
* Description of classes that respond to mouse related input events
|
||||
* Edited for opsu!
|
||||
*
|
||||
* @author kevin
|
||||
*/
|
||||
public interface MouseListener {
|
||||
|
||||
/**
|
||||
* Notification that the mouse wheel position was updated
|
||||
*
|
||||
* @param delta The amount of the wheel has moved
|
||||
*/
|
||||
boolean mouseWheelMoved(int delta);
|
||||
|
||||
/**
|
||||
* Notification that a mouse button was pressed
|
||||
*
|
||||
* @param button The index of the button (starting at 0)
|
||||
* @param x The x position of the mouse when the button was pressed
|
||||
* @param y The y position of the mouse when the button was pressed
|
||||
*/
|
||||
boolean mousePressed(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* Notification that a mouse button was released
|
||||
*
|
||||
* @param button The index of the button (starting at 0)
|
||||
* @param x The x position of the mouse when the button was released
|
||||
* @param y The y position of the mouse when the button was released
|
||||
*/
|
||||
boolean mouseReleased(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* Notification that mouse cursor was dragged
|
||||
*
|
||||
* @param oldx The old x position of the mouse
|
||||
* @param oldy The old y position of the mouse
|
||||
* @param newx The new x position of the mouse
|
||||
* @param newy The new y position of the mouse
|
||||
*/
|
||||
boolean mouseDragged(int oldx, int oldy, int newx, int newy);
|
||||
|
||||
}
|
||||
@@ -32,12 +32,13 @@ import org.lwjgl.Sys;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Font;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.geom.Rectangle;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.components.ActionListener;
|
||||
import yugecin.opsudance.core.components.Component;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* A single text field supporting text entry
|
||||
*
|
||||
@@ -48,8 +49,6 @@ public class TextField extends Component {
|
||||
private static final int INITIAL_KEY_REPEAT_INTERVAL = 400;
|
||||
private static final int KEY_REPEAT_INTERVAL = 50;
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
|
||||
private String value = "";
|
||||
private Font font;
|
||||
private int maxCharacter = 10000;
|
||||
@@ -65,8 +64,7 @@ public class TextField extends Component {
|
||||
|
||||
private ActionListener listener;
|
||||
|
||||
public TextField(DisplayContainer displayContainer, Font font, int x, int y, int width, int height) {
|
||||
this.displayContainer = displayContainer;
|
||||
public TextField(Font font, int x, int y, int width, int height) {
|
||||
this.font = font;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -97,7 +95,7 @@ public class TextField extends Component {
|
||||
|
||||
public void render(Graphics g) {
|
||||
if (lastKey != -1) {
|
||||
if (displayContainer.input.isKeyDown(lastKey)) {
|
||||
if (isKeyDown(lastKey)) {
|
||||
if (repeatTimer < System.currentTimeMillis()) {
|
||||
repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
|
||||
keyPressed(lastKey, lastChar);
|
||||
@@ -170,10 +168,8 @@ public class TextField extends Component {
|
||||
}
|
||||
|
||||
public void keyPressed(int key, char c) {
|
||||
if (key != -1)
|
||||
{
|
||||
if ((key == Input.KEY_V) &&
|
||||
((displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) || (displayContainer.input.isKeyDown(Input.KEY_RCONTROL)))) {
|
||||
if (key != -1) {
|
||||
if (key == KEY_V && input.isControlDown()) {
|
||||
String text = Sys.getClipboard();
|
||||
if (text != null) {
|
||||
doPaste(text);
|
||||
@@ -190,7 +186,7 @@ public class TextField extends Component {
|
||||
}
|
||||
lastChar = c;
|
||||
|
||||
if (key == Input.KEY_LEFT) { /*
|
||||
if (key == KEY_LEFT) { /*
|
||||
if (cursorPos > 0) {
|
||||
cursorPos--;
|
||||
}
|
||||
@@ -198,7 +194,7 @@ public class TextField extends Component {
|
||||
if (consume) {
|
||||
container.getInput().consumeEvent();
|
||||
}
|
||||
*/ } else if (key == Input.KEY_RIGHT) { /*
|
||||
*/ } else if (key == KEY_RIGHT) { /*
|
||||
if (cursorPos < value.length()) {
|
||||
cursorPos++;
|
||||
}
|
||||
@@ -206,9 +202,9 @@ public class TextField extends Component {
|
||||
if (consume) {
|
||||
container.getInput().consumeEvent();
|
||||
}
|
||||
*/ } else if (key == Input.KEY_BACK) {
|
||||
*/ } else if (key == KEY_BACK) {
|
||||
if ((cursorPos > 0) && (value.length() > 0)) {
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_LCONTROL) || displayContainer.input.isKeyDown(Input.KEY_RCONTROL)) {
|
||||
if (input.isControlDown()) {
|
||||
int sp = 0;
|
||||
boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1));
|
||||
boolean charSeen = false;
|
||||
@@ -240,7 +236,7 @@ public class TextField extends Component {
|
||||
cursorPos--;
|
||||
}
|
||||
}
|
||||
} else if (key == Input.KEY_DELETE) {
|
||||
} else if (key == KEY_DELETE) {
|
||||
if (value.length() > cursorPos) {
|
||||
value = value.substring(0,cursorPos) + value.substring(cursorPos+1);
|
||||
}
|
||||
@@ -252,7 +248,7 @@ public class TextField extends Component {
|
||||
value = value.substring(0, cursorPos) + c;
|
||||
}
|
||||
cursorPos++;
|
||||
} else if (key == Input.KEY_RETURN) {
|
||||
} else if (key == KEY_RETURN) {
|
||||
if (listener != null) {
|
||||
listener.onAction();
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
package org.newdawn.slick.state.transition;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.state.GameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
|
||||
/**
|
||||
* A transition to fade out to a given colour after a delay.
|
||||
*
|
||||
* @author kevin (base)
|
||||
*/
|
||||
public class DelayedFadeOutTransition implements Transition {
|
||||
/** The color to fade to */
|
||||
private final Color color;
|
||||
/** The time it takes the fade to happen */
|
||||
private final int fadeTime;
|
||||
/** The time it takes before the fade starts */
|
||||
private final int delay;
|
||||
/** The elapsed time */
|
||||
private int elapsedTime = 0;
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition.
|
||||
*/
|
||||
public DelayedFadeOutTransition() { this(Color.black, 500, 0); }
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
*/
|
||||
public DelayedFadeOutTransition(Color color) { this(color, 500, 0); }
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
* @param delay The time before the fade starts (must be less than {@code fadeTime})
|
||||
* @throws IllegalArgumentException if {@code delay} is greater than {@code fadeTime}
|
||||
*/
|
||||
public DelayedFadeOutTransition(Color color, int fadeTime, int delay) {
|
||||
if (delay > fadeTime)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
this.color = new Color(color);
|
||||
this.color.a = 0;
|
||||
this.fadeTime = fadeTime;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() { return (color.a >= 1); }
|
||||
|
||||
@Override
|
||||
public void postRender(StateBasedGame game, GameContainer container, Graphics g) {
|
||||
Color old = g.getColor();
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, container.getWidth() * 2, container.getHeight() * 2);
|
||||
g.setColor(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(StateBasedGame game, GameContainer container, int delta) {
|
||||
if (elapsedTime < delay) {
|
||||
elapsedTime += delta;
|
||||
return;
|
||||
}
|
||||
|
||||
color.a += delta * (1.0f / (fadeTime - delay));
|
||||
if (color.a > 1)
|
||||
color.a = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRender(StateBasedGame game, GameContainer container, Graphics g) {}
|
||||
|
||||
@Override
|
||||
public void init(GameState firstState, GameState secondState) {}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package org.newdawn.slick.state.transition;
|
||||
|
||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.state.GameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
|
||||
/**
|
||||
* A transition to fade out to a given colour using an easing function.
|
||||
*
|
||||
* @author kevin (base)
|
||||
*/
|
||||
public class EasedFadeOutTransition implements Transition {
|
||||
/** The color to fade to */
|
||||
private final Color color;
|
||||
/** The time it takes the fade to happen */
|
||||
private final int fadeTime;
|
||||
/** The easing function */
|
||||
private final AnimationEquation eq;
|
||||
/** The transition progress */
|
||||
private float t = 0f;
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*/
|
||||
public EasedFadeOutTransition() { this(Color.black, 500, AnimationEquation.OUT_QUART); }
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
*/
|
||||
public EasedFadeOutTransition(Color color) { this(color, 500, AnimationEquation.OUT_QUART); }
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
*/
|
||||
public EasedFadeOutTransition(Color color, int fadeTime) { this(color, fadeTime, AnimationEquation.OUT_QUART); }
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
* @param eq The easing function to use
|
||||
*/
|
||||
public EasedFadeOutTransition(Color color, int fadeTime, AnimationEquation eq) {
|
||||
this.color = new Color(color);
|
||||
this.color.a = 0;
|
||||
this.fadeTime = fadeTime;
|
||||
this.eq = eq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() { return (color.a >= 1); }
|
||||
|
||||
@Override
|
||||
public void postRender(StateBasedGame game, GameContainer container, Graphics g) {
|
||||
Color old = g.getColor();
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, container.getWidth() * 2, container.getHeight() * 2);
|
||||
g.setColor(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(StateBasedGame game, GameContainer container, int delta) {
|
||||
t += delta * (1.0f / fadeTime);
|
||||
float alpha = t > 1f ? 1f : eq.calc(t);
|
||||
color.a = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRender(StateBasedGame game, GameContainer container, Graphics g) {}
|
||||
|
||||
@Override
|
||||
public void init(GameState firstState, GameState secondState) {}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import yugecin.opsudance.spinners.*;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class Dancer {
|
||||
@@ -194,12 +195,12 @@ public class Dancer {
|
||||
}
|
||||
isCurrentLazySlider = false;
|
||||
// detect lazy sliders, should work pretty good
|
||||
if (c.isSlider() && OPTION_DANCE_LAZY_SLIDERS.state && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||
if (c.isSlider() && OPTION_DANCE_LAZY_SLIDERS.state && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= gameObjectRenderer.circleDiameter * 0.8f) {
|
||||
Slider s = (Slider) c;
|
||||
Vec2f mid = s.getCurve().pointAt(1f);
|
||||
if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||
if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= gameObjectRenderer.circleDiameter * 0.8f) {
|
||||
mid = s.getCurve().pointAt(0.5f);
|
||||
if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||
if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= gameObjectRenderer.circleDiameter * 0.8f) {
|
||||
isCurrentLazySlider = true;
|
||||
}
|
||||
}
|
||||
@@ -251,8 +252,8 @@ public class Dancer {
|
||||
}
|
||||
}
|
||||
Pippi.dance(time, c, isCurrentLazySlider);
|
||||
x = Utils.clamp(x, 10, width - 10);
|
||||
y = Utils.clamp(y, 10, height - 10);
|
||||
x = Utils.clamp(x, 10, displayContainer.width - 10);
|
||||
y = Utils.clamp(y, 10, displayContainer.height - 10);
|
||||
}
|
||||
|
||||
private void createNewMover() {
|
||||
|
||||
@@ -21,22 +21,16 @@ import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
|
||||
import itdelatrisu.opsu.db.DBController;
|
||||
import itdelatrisu.opsu.downloads.DownloadList;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.states.Splash;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.options.OptionsService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.Entrypoint.sout;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/*
|
||||
@@ -44,30 +38,13 @@ import static yugecin.opsudance.options.Options.*;
|
||||
*/
|
||||
public class OpsuDance {
|
||||
|
||||
@Inject
|
||||
private DisplayContainer container;
|
||||
|
||||
@Inject
|
||||
private OptionsService optionsService;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
@Inject
|
||||
private Updater updater;
|
||||
|
||||
private ServerSocket singleInstanceSocket;
|
||||
|
||||
@Inject
|
||||
public OpsuDance() {
|
||||
}
|
||||
|
||||
public void start(String[] args) {
|
||||
try {
|
||||
sout("initialized");
|
||||
|
||||
checkRunningDirectory();
|
||||
optionsService.loadOptions();
|
||||
optionservice.loadOptions();
|
||||
ensureSingleInstance();
|
||||
sout("prechecks done and options parsed");
|
||||
|
||||
@@ -75,15 +52,15 @@ public class OpsuDance {
|
||||
initUpdater(args);
|
||||
sout("database & updater initialized");
|
||||
|
||||
container.init(Splash.class);
|
||||
displayContainer.init(splashState);
|
||||
} catch (Exception e) {
|
||||
errorAndExit("startup failure", e);
|
||||
}
|
||||
|
||||
while (rungame());
|
||||
container.teardownAL();
|
||||
displayContainer.teardownAL();
|
||||
|
||||
optionsService.saveOptions();
|
||||
optionservice.saveOptions();
|
||||
closeSingleInstanceSocket();
|
||||
DBController.closeConnections();
|
||||
DownloadList.get().cancelAllDownloads();
|
||||
@@ -95,26 +72,26 @@ public class OpsuDance {
|
||||
|
||||
private boolean rungame() {
|
||||
try {
|
||||
container.setup();
|
||||
container.resume();
|
||||
displayContainer.setup();
|
||||
displayContainer.resume();
|
||||
} catch (Exception e) {
|
||||
ErrorHandler.error("could not initialize GL", e).allowTerminate().preventContinue().show();
|
||||
explode("could not initialize GL", e, ALLOW_TERMINATE | PREVENT_CONTINUE);
|
||||
return false;
|
||||
}
|
||||
Exception caughtException = null;
|
||||
try {
|
||||
container.run();
|
||||
displayContainer.run();
|
||||
} catch (Exception e) {
|
||||
caughtException = e;
|
||||
}
|
||||
container.teardown();
|
||||
container.pause();
|
||||
return caughtException != null && ErrorHandler.error("update/render error", caughtException).allowTerminate().show().shouldIgnoreAndContinue();
|
||||
displayContainer.teardown();
|
||||
displayContainer.pause();
|
||||
return caughtException != null && explode("update/render error", caughtException, ALLOW_TERMINATE);
|
||||
}
|
||||
|
||||
private void initDatabase() {
|
||||
try {
|
||||
DBController.init(config);
|
||||
DBController.init();
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
errorAndExit("Could not initialize database.", e);
|
||||
}
|
||||
@@ -142,20 +119,6 @@ public class OpsuDance {
|
||||
}.start();
|
||||
}
|
||||
|
||||
private void checkRunningDirectory() {
|
||||
if (!Utils.isJarRunning()) {
|
||||
return;
|
||||
}
|
||||
File runningDir = Utils.getRunningDirectory();
|
||||
if (runningDir == null) {
|
||||
return;
|
||||
}
|
||||
if (runningDir.getAbsolutePath().indexOf('!') == -1) {
|
||||
return;
|
||||
}
|
||||
errorAndExit("Cannot run from a path that contains a '!'. Please move or rename the jar and try again.");
|
||||
}
|
||||
|
||||
private void ensureSingleInstance() {
|
||||
if (OPTION_NOSINGLEINSTANCE.state) {
|
||||
return;
|
||||
@@ -183,13 +146,8 @@ public class OpsuDance {
|
||||
}
|
||||
}
|
||||
|
||||
private void errorAndExit(String errstr) {
|
||||
ErrorHandler.error(errstr, new Throwable()).allowTerminate().preventContinue().show();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private void errorAndExit(String errstr, Throwable cause) {
|
||||
ErrorHandler.error(errstr, cause).preventContinue().show();
|
||||
explode(errstr, cause, PREVENT_CONTINUE);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ package yugecin.opsudance;
|
||||
|
||||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import itdelatrisu.opsu.objects.Slider;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class Pippi {
|
||||
|
||||
@@ -38,14 +38,14 @@ public class Pippi {
|
||||
|
||||
public static void setRadiusPercent(int radiusPercent) {
|
||||
Pippi.radiusPercent = radiusPercent;
|
||||
pippiminrad = pippirad = (GameObjectRenderer.instance.getCircleDiameter() / 2d - 10d) * radiusPercent / 100d;
|
||||
pippiminrad = pippirad = (gameObjectRenderer.circleDiameter / 2d - 10d) * radiusPercent / 100d;
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
angle = 0;
|
||||
currentdelta = 0;
|
||||
setRadiusPercent(radiusPercent);
|
||||
pippimaxrad = GameObjectRenderer.instance.getCircleDiameter() - 10d;
|
||||
pippimaxrad = gameObjectRenderer.circleDiameter - 10d;
|
||||
}
|
||||
|
||||
public static void dance(int time, GameObject c, boolean isCurrentLazySlider) {
|
||||
@@ -92,7 +92,7 @@ public class Pippi {
|
||||
}
|
||||
|
||||
public static boolean shouldPreventWobblyStream(double distance) {
|
||||
return OPTION_PIPPI_ENABLE.state && distance < GameObjectRenderer.instance.getCircleDiameter() * 0.93f && OPTION_PIPPI_PREVENT_WOBBLY_STREAMS.state;
|
||||
return OPTION_PIPPI_ENABLE.state && distance < gameObjectRenderer.circleDiameter * 0.93f && OPTION_PIPPI_PREVENT_WOBBLY_STREAMS.state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance;
|
||||
|
||||
import itdelatrisu.opsu.NativeLoader;
|
||||
import org.newdawn.slick.util.FileSystemLocation;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class PreStartupInitializer {
|
||||
|
||||
private final Configuration config;
|
||||
|
||||
@Inject
|
||||
public PreStartupInitializer(Configuration config) {
|
||||
this.config = config;
|
||||
loadNatives();
|
||||
setResourcePath();
|
||||
}
|
||||
|
||||
private void loadNatives() {
|
||||
File nativeDir = loadNativesUsingOptionsPath();
|
||||
|
||||
System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
|
||||
System.setProperty("java.library.path", nativeDir.getAbsolutePath());
|
||||
|
||||
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 (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
Log.warn("Failed to set 'sys_paths' field.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private File loadNativesUsingOptionsPath() {
|
||||
File nativeDir = config.NATIVE_DIR;
|
||||
try {
|
||||
new NativeLoader(nativeDir).loadNatives();
|
||||
} catch (IOException e) {
|
||||
Log.error("Error loading natives.", e);
|
||||
}
|
||||
return nativeDir;
|
||||
}
|
||||
|
||||
private void setResourcePath() {
|
||||
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,28 +15,18 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import java.net.URI;
|
||||
|
||||
public abstract class FadeTransitionState extends TransitionState {
|
||||
public class Constants {
|
||||
|
||||
private final Color black;
|
||||
|
||||
public FadeTransitionState() {
|
||||
super();
|
||||
black = new Color(Color.black);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics g) {
|
||||
applicableState.render(g);
|
||||
black.a = getMaskAlphaLevel((float) transitionTime / transitionTargetTime);
|
||||
g.setColor(black);
|
||||
g.fillRect(0, 0, displayContainer.width, displayContainer.height);
|
||||
}
|
||||
|
||||
protected abstract float getMaskAlphaLevel(float fadeProgress);
|
||||
public static final String PROJECT_NAME = "opsu!dance";
|
||||
public static final String FONT_NAME = "DroidSansFallback.ttf";
|
||||
public static final String VERSION_FILE = "version";
|
||||
public static final URI REPOSITORY_URI = URI.create("https://github.com/itdelatrisu/opsu");
|
||||
public static final URI DANCE_REPOSITORY_URI = URI.create("https://github.com/yugecin/opsu-dance");
|
||||
public static final String ISSUES_URL = "https://github.com/yugecin/opsu-dance/issues/new?title=%s&body=%s";
|
||||
public static final String VERSION_REMOTE = "https://raw.githubusercontent.com/yugecin/opsu-dance/master/version";
|
||||
|
||||
}
|
||||
@@ -26,10 +26,12 @@ import itdelatrisu.opsu.downloads.DownloadNode;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.render.CurveRenderState;
|
||||
import itdelatrisu.opsu.replay.PlaybackSpeed;
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import itdelatrisu.opsu.ui.Cursor;
|
||||
import itdelatrisu.opsu.ui.Fonts;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.DisplayMode;
|
||||
@@ -39,58 +41,38 @@ import org.newdawn.slick.opengl.InternalTextureLoader;
|
||||
import org.newdawn.slick.opengl.renderer.Renderer;
|
||||
import org.newdawn.slick.opengl.renderer.SGL;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.OpsuState;
|
||||
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubNotifState;
|
||||
import yugecin.opsudance.core.state.specialstates.FpsRenderState;
|
||||
import yugecin.opsudance.core.state.transitions.*;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
import yugecin.opsudance.events.SkinChangedListener;
|
||||
import yugecin.opsudance.utils.GLHelper;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import static yugecin.opsudance.core.Entrypoint.sout;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
* based on org.newdawn.slick.AppGameContainer
|
||||
*/
|
||||
public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListener {
|
||||
|
||||
@Inject
|
||||
private SkinService skinService;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
public class DisplayContainer implements ErrorDumpable, ResolutionChangedListener, SkinChangedListener {
|
||||
|
||||
private static SGL GL = Renderer.get();
|
||||
|
||||
private final InstanceContainer instanceContainer;
|
||||
|
||||
private FpsRenderState fpsState;
|
||||
private BarNotificationState barNotifState;
|
||||
private BubbleNotificationState bubNotifState;
|
||||
|
||||
private TransitionState outTransitionState;
|
||||
private TransitionState inTransitionState;
|
||||
|
||||
private final TransitionFinishedListener outTransitionListener;
|
||||
private final TransitionFinishedListener inTransitionListener;
|
||||
private BubNotifState bubNotifState;
|
||||
|
||||
private OpsuState state;
|
||||
|
||||
public final DisplayMode nativeDisplayMode;
|
||||
|
||||
private Graphics graphics;
|
||||
public Input input;
|
||||
|
||||
public int width;
|
||||
public int height;
|
||||
@@ -123,38 +105,52 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
public final Cursor cursor;
|
||||
public boolean drawCursor;
|
||||
|
||||
@Inject
|
||||
public DisplayContainer(InstanceContainer instanceContainer) {
|
||||
this.instanceContainer = instanceContainer;
|
||||
class Transition {
|
||||
int in;
|
||||
int out;
|
||||
int total;
|
||||
int progress = -1;
|
||||
OpsuState nextstate;
|
||||
Color OVERLAY = new Color(Color.black);
|
||||
|
||||
public void update() {
|
||||
if (progress == -1) {
|
||||
return;
|
||||
}
|
||||
progress += delta;
|
||||
if (progress > out && nextstate != null) {
|
||||
switchStateInstantly(nextstate);
|
||||
nextstate = null;
|
||||
}
|
||||
if (progress > total) {
|
||||
progress = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void render(Graphics graphics) {
|
||||
if (progress == -1) {
|
||||
return;
|
||||
}
|
||||
int relprogress = progress;
|
||||
int reltotal = out;
|
||||
if (progress > out) {
|
||||
reltotal = in;
|
||||
relprogress = total - progress;
|
||||
}
|
||||
OVERLAY.a = (float) relprogress / reltotal;
|
||||
graphics.setColor(OVERLAY);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private final Transition transition = new Transition();
|
||||
|
||||
public DisplayContainer() {
|
||||
this.cursor = new Cursor();
|
||||
drawCursor = true;
|
||||
|
||||
outTransitionListener = new TransitionFinishedListener() {
|
||||
@Override
|
||||
public void onFinish() {
|
||||
state.leave();
|
||||
outTransitionState.getApplicableState().leave();
|
||||
state = inTransitionState;
|
||||
state.enter();
|
||||
inTransitionState.getApplicableState().enter();
|
||||
}
|
||||
};
|
||||
|
||||
inTransitionListener = new TransitionFinishedListener() {
|
||||
@Override
|
||||
public void onFinish() {
|
||||
state.leave();
|
||||
state = inTransitionState.getApplicableState();
|
||||
}
|
||||
};
|
||||
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
destroyImages();
|
||||
reinit();
|
||||
}
|
||||
});
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
SkinChangedListener.EVENT.addListener(this);
|
||||
|
||||
this.nativeDisplayMode = Display.getDisplayMode();
|
||||
targetBackgroundRenderInterval = 41; // ~24 fps
|
||||
@@ -163,13 +159,25 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
renderDelta = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
destroyImages();
|
||||
reinit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkinChanged(String stringName) {
|
||||
destroyImages();
|
||||
reinit();
|
||||
}
|
||||
|
||||
private void reinit() {
|
||||
// this used to be in Utils.init
|
||||
// TODO find a better place for this?
|
||||
setFPS(targetFPS[targetFPSIndex]);
|
||||
MusicController.setMusicVolume(OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f);
|
||||
|
||||
skinService.loadSkin();
|
||||
skinservice.loadSkin();
|
||||
|
||||
// initialize game images
|
||||
for (GameImage img : GameImage.values()) {
|
||||
@@ -196,16 +204,16 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
targetRenderInterval = 1000 / targetRendersPerSecond;
|
||||
}
|
||||
|
||||
public void init(Class<? extends OpsuState> startingState) {
|
||||
public void init(OpsuState startingState) {
|
||||
setUPS(OPTION_TARGET_UPS.val);
|
||||
setFPS(targetFPS[targetFPSIndex]);
|
||||
|
||||
state = instanceContainer.provide(startingState);
|
||||
state.enter();
|
||||
fpsState = new FpsRenderState();
|
||||
bubNotifState = new BubNotifState();
|
||||
barNotifState = new BarNotificationState();
|
||||
|
||||
fpsState = instanceContainer.provide(FpsRenderState.class);
|
||||
bubNotifState = instanceContainer.provide(BubbleNotificationState.class);
|
||||
barNotifState = instanceContainer.provide(BarNotificationState.class);
|
||||
state = startingState;
|
||||
state.enter();
|
||||
}
|
||||
|
||||
|
||||
@@ -220,6 +228,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
mouseX = input.getMouseX();
|
||||
mouseY = input.getMouseY();
|
||||
|
||||
transition.update();
|
||||
fpsState.update();
|
||||
|
||||
state.update();
|
||||
@@ -254,13 +263,17 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
|
||||
cursor.updateAngle(renderDelta);
|
||||
if (drawCursor) {
|
||||
cursor.draw(input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON));
|
||||
cursor.draw(Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON) ||
|
||||
Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON));
|
||||
}
|
||||
UI.drawTooltip(graphics);
|
||||
|
||||
transition.render(graphics);
|
||||
|
||||
timeSinceLastRender = 0;
|
||||
|
||||
Display.update(false);
|
||||
GL11.glFlush();
|
||||
}
|
||||
|
||||
Display.processMessages();
|
||||
@@ -270,8 +283,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
|
||||
public void setup() throws Exception {
|
||||
width = height = -1;
|
||||
Input.disableControllers();
|
||||
Display.setTitle("opsu!dance");
|
||||
setupResolutionOptionlist(nativeDisplayMode.getWidth(), nativeDisplayMode.getHeight());
|
||||
updateDisplayMode(OPTION_SCREEN_RESOLUTION.getValueString());
|
||||
Display.create();
|
||||
GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" });
|
||||
@@ -281,6 +294,19 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
GLHelper.hideNativeCursor();
|
||||
}
|
||||
|
||||
// TODO: move this elsewhere
|
||||
private void setupResolutionOptionlist(int width, int height) {
|
||||
final Object[] resolutions = OPTION_SCREEN_RESOLUTION.getListItems();
|
||||
final String nativeRes = width + "x" + height;
|
||||
resolutions[0] = nativeRes;
|
||||
for (int i = 0; i < resolutions.length; i++) {
|
||||
if (nativeRes.equals(resolutions[i].toString())) {
|
||||
resolutions[i] = resolutions[i] + " (borderless)";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void teardown() {
|
||||
destroyImages();
|
||||
CurveRenderState.shutdown();
|
||||
@@ -316,13 +342,13 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
return true;
|
||||
}
|
||||
if (DownloadList.get().hasActiveDownloads()) {
|
||||
EventBus.post(new BubbleNotificationEvent(DownloadList.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
||||
BubNotifListener.EVENT.make().onBubNotif(DownloadList.EXIT_CONFIRMATION, Colors.BUB_RED);
|
||||
exitRequested = false;
|
||||
exitconfirmation = System.currentTimeMillis();
|
||||
return false;
|
||||
}
|
||||
if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING) {
|
||||
EventBus.post(new BubbleNotificationEvent(Updater.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
||||
if (updater.getStatus() == Updater.Status.UPDATE_DOWNLOADING) {
|
||||
BubNotifListener.EVENT.make().onBubNotif(Updater.EXIT_CONFIRMATION, Colors.BUB_PURPLE);
|
||||
exitRequested = false;
|
||||
exitconfirmation = System.currentTimeMillis();
|
||||
return false;
|
||||
@@ -334,6 +360,11 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
int screenWidth = nativeDisplayMode.getWidth();
|
||||
int screenHeight = nativeDisplayMode.getHeight();
|
||||
|
||||
int eos = resolutionString.indexOf(' ');
|
||||
if (eos > -1) {
|
||||
resolutionString = resolutionString.substring(0, eos);
|
||||
}
|
||||
|
||||
int width = screenWidth;
|
||||
int height = screenHeight;
|
||||
if (resolutionString.matches("^[0-9]+x[0-9]+$")) {
|
||||
@@ -348,18 +379,17 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
height = 600;
|
||||
}
|
||||
|
||||
if (!OPTION_FULLSCREEN.state) {
|
||||
boolean borderless = (screenWidth == width && screenHeight == height);
|
||||
System.setProperty("org.lwjgl.opengl.Window.undecorated", Boolean.toString(borderless));
|
||||
}
|
||||
|
||||
try {
|
||||
setDisplayMode(width, height, OPTION_FULLSCREEN.state);
|
||||
} catch (Exception e) {
|
||||
EventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Failed to change resolution", Colors.BUB_RED);
|
||||
Log.error("Failed to set display mode.", e);
|
||||
}
|
||||
|
||||
if (OPTION_FULLSCREEN.state) {
|
||||
// set borderless window if dimensions match screen size
|
||||
boolean borderless = (screenWidth == width && screenHeight == height);
|
||||
System.setProperty("org.lwjgl.opengl.Window.undecorated", Boolean.toString(borderless));
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception {
|
||||
@@ -377,8 +407,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
displayMode = new DisplayMode(width, height);
|
||||
if (fullscreen) {
|
||||
fullscreen = false;
|
||||
Log.warn("could not find fullscreen displaymode for " + width + "x" + height);
|
||||
EventBus.post(new BubbleNotificationEvent("Fullscreen mode is not supported for " + width + "x" + height, BubbleNotificationEvent.COLOR_ORANGE));
|
||||
String msg = String.format("Fullscreen mode is not supported for %sx%s", width, height);
|
||||
Log.warn(msg);
|
||||
BubNotifListener.EVENT.make().onBubNotif(msg, Colors.BUB_ORANGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,17 +435,20 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
graphics = new Graphics(width, height);
|
||||
graphics.setAntiAlias(false);
|
||||
|
||||
input = new Input(height);
|
||||
input.enableKeyRepeat();
|
||||
input.addKeyListener(this);
|
||||
input.addMouseListener(this);
|
||||
if (input == null) {
|
||||
input = new Input(height);
|
||||
input.enableKeyRepeat();
|
||||
input.addListener(new GlobalInputListener());
|
||||
input.addMouseListener(bubNotifState);
|
||||
}
|
||||
input.addListener(state);
|
||||
|
||||
sout("GL ready");
|
||||
|
||||
GameImage.init(width, height);
|
||||
Fonts.init(config);
|
||||
Fonts.init();
|
||||
|
||||
EventBus.post(new ResolutionOrSkinChangedEvent(null, width, height));
|
||||
ResolutionChangedListener.EVENT.make().onResolutionChanged(width, height);
|
||||
}
|
||||
|
||||
public void resetCursor() {
|
||||
@@ -432,110 +466,51 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
||||
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
|
||||
}
|
||||
|
||||
public boolean isWidescreen() {
|
||||
return width * 1000 / height > 1500; // 1777 = 16:9, 1333 = 4:3
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeErrorDump(StringWriter dump) {
|
||||
dump.append("> DisplayContainer dump\n");
|
||||
dump.append("OpenGL version: ").append(glVersion).append( "(").append(glVendor).append(")\n");
|
||||
if (isTransitioning()) {
|
||||
dump.append("doing a transition\n");
|
||||
dump.append("using out transition ").append(outTransitionState.getClass().getSimpleName()).append('\n');
|
||||
dump.append("using in transition ").append(inTransitionState.getClass().getSimpleName()).append('\n');
|
||||
if (state == inTransitionState) {
|
||||
dump.append("currently doing the in transition\n");
|
||||
} else {
|
||||
dump.append("currently doing the out transition\n");
|
||||
}
|
||||
if (state == null) {
|
||||
dump.append("state is null!\n");
|
||||
return;
|
||||
}
|
||||
state.writeErrorDump(dump);
|
||||
}
|
||||
|
||||
// TODO change this
|
||||
public boolean isInState(Class<? extends OpsuState> state) {
|
||||
return state.isInstance(state);
|
||||
}
|
||||
|
||||
public boolean isTransitioning() {
|
||||
return state instanceof TransitionState;
|
||||
public void switchState(OpsuState state) {
|
||||
switchState(state, 200, 300);
|
||||
}
|
||||
|
||||
public void switchState(Class<? extends OpsuState> newState) {
|
||||
switchState(newState, FadeOutTransitionState.class, 200, FadeInTransitionState.class, 300);
|
||||
}
|
||||
|
||||
public void switchStateNow(Class<? extends OpsuState> newState) {
|
||||
switchState(newState, EmptyTransitionState.class, 0, FadeInTransitionState.class, 300);
|
||||
}
|
||||
|
||||
public void switchStateInstantly(Class<? extends OpsuState> newState) {
|
||||
state.leave();
|
||||
state = instanceContainer.provide(newState);
|
||||
state.enter();
|
||||
}
|
||||
|
||||
public void switchState(Class<? extends OpsuState> newState, Class<? extends TransitionState> outTransition, int outTime, Class<? extends TransitionState> inTransition, int inTime) {
|
||||
if (isTransitioning()) {
|
||||
public void switchState(OpsuState newstate, int outtime, int intime) {
|
||||
if (transition.progress != -1) {
|
||||
return;
|
||||
}
|
||||
outTransitionState = instanceContainer.provide(outTransition).set(state, outTime, outTransitionListener);
|
||||
inTransitionState = instanceContainer.provide(inTransition).set(instanceContainer.provide(newState), inTime, inTransitionListener);
|
||||
state = outTransitionState;
|
||||
state.enter();
|
||||
}
|
||||
|
||||
/*
|
||||
* input events below, see org.newdawn.slick.KeyListener & org.newdawn.slick.MouseListener
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void keyPressed(int key, char c) {
|
||||
state.keyPressed(key, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(int key, char c) {
|
||||
state.keyReleased(key, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(int change) {
|
||||
state.mouseWheelMoved(change);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int button, int x, int y, int clickCount) { }
|
||||
|
||||
@Override
|
||||
public void mousePressed(int button, int x, int y) {
|
||||
state.mousePressed(button, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int button, int x, int y) {
|
||||
if (bubNotifState.mouseReleased(x, y)) {
|
||||
return;
|
||||
if (outtime == 0) {
|
||||
switchStateInstantly(newstate);
|
||||
newstate = null;
|
||||
}
|
||||
state.mouseReleased(button, x, y);
|
||||
transition.nextstate = newstate;
|
||||
transition.total = transition.in = intime;
|
||||
transition.out = outtime;
|
||||
transition.total += outtime;
|
||||
transition.progress = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(int oldx, int oldy, int newx, int newy) { }
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
state.mouseDragged(oldx, oldy, newx, newy);
|
||||
public void switchStateInstantly(OpsuState state) {
|
||||
this.state.leave();
|
||||
input.removeListener(this.state);
|
||||
this.state = state;
|
||||
this.state.enter();
|
||||
input.addListener(this.state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Input input) { }
|
||||
|
||||
@Override
|
||||
public boolean isAcceptingInput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inputEnded() { }
|
||||
|
||||
@Override
|
||||
public void inputStarted() { }
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ package yugecin.opsudance.core;
|
||||
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import yugecin.opsudance.OpsuDance;
|
||||
import yugecin.opsudance.core.inject.OpsuDanceInjector;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static yugecin.opsudance.core.Constants.PROJECT_NAME;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class Entrypoint {
|
||||
|
||||
@@ -27,10 +31,18 @@ public class Entrypoint {
|
||||
|
||||
public static void main(String[] args) {
|
||||
sout("launched");
|
||||
(new OpsuDanceInjector()).provide(OpsuDance.class).start(args);
|
||||
|
||||
if (Updater.get().getStatus() == Updater.Status.UPDATE_FINAL) {
|
||||
Updater.get().runUpdate();
|
||||
try {
|
||||
InstanceContainer.kickstart();
|
||||
} catch (Exception e) {
|
||||
JOptionPane.showMessageDialog(null, e.getMessage(), "Cannot start " + PROJECT_NAME, JOptionPane.ERROR_MESSAGE);
|
||||
// TODO replace with errorhandler
|
||||
}
|
||||
|
||||
new OpsuDance().start(args);
|
||||
|
||||
if (updater.getStatus() == Updater.Status.UPDATE_FINAL) {
|
||||
updater.runUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +51,7 @@ public class Entrypoint {
|
||||
}
|
||||
|
||||
public static void sout(String message) {
|
||||
System.out.println(String.format("[%7d] %s", runtime(), message));
|
||||
System.out.println(String.format("[%8d] %s", runtime(), message));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
53
src/yugecin/opsudance/core/Environment.java
Normal file
53
src/yugecin/opsudance/core/Environment.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static yugecin.opsudance.core.Constants.PROJECT_NAME;
|
||||
|
||||
public class Environment {
|
||||
|
||||
public final boolean isJarRunning;
|
||||
public final File workingdir;
|
||||
public final File jarfile;
|
||||
|
||||
public Environment() {
|
||||
Class thiz = Environment.class;
|
||||
String thisClassLocation = thiz.getResource(thiz.getSimpleName() + ".class").toString();
|
||||
this.isJarRunning = thisClassLocation.startsWith("jar:");
|
||||
if (!isJarRunning) {
|
||||
this.workingdir = Paths.get(".").toAbsolutePath().normalize().toFile();
|
||||
this.jarfile = null;
|
||||
} else {
|
||||
String wdir = thisClassLocation.substring(9); // remove jar:file:
|
||||
String separator = "!/";
|
||||
int separatorIdx = wdir.indexOf(separator);
|
||||
int lastSeparatorIdx = wdir.lastIndexOf(separator);
|
||||
if (separatorIdx != lastSeparatorIdx) {
|
||||
String msg = String.format("%s cannot run from paths containing '!/', please move the file. Current directory: %s",
|
||||
PROJECT_NAME, thisClassLocation.substring(0, lastSeparatorIdx));
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
this.jarfile = new File(wdir.substring(0, separatorIdx));
|
||||
this.workingdir = jarfile.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
84
src/yugecin/opsudance/core/GlobalInputListener.java
Normal file
84
src/yugecin/opsudance/core/GlobalInputListener.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.InputListener;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class GlobalInputListener implements InputListener {
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int key, char c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyReleased(int key, char c) {
|
||||
if (key == KEY_F7) {
|
||||
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
|
||||
BarNotifListener.EVENT.make().onBarNotif(String.format("Frame limiter: %s",
|
||||
OPTION_TARGET_FPS.getValueString()));
|
||||
return true;
|
||||
}
|
||||
if (key == KEY_F10) {
|
||||
OPTION_DISABLE_MOUSE_BUTTONS.toggle();
|
||||
return true;
|
||||
}
|
||||
if (key == KEY_F12) {
|
||||
config.takeScreenShot();
|
||||
return true;
|
||||
}
|
||||
if (key == KEY_S && isKeyDown(KEY_LMENU) && isKeyDown(KEY_LSHIFT) &&
|
||||
input.isControlDown() && !displayContainer.isInState(Game.class)) {
|
||||
skinservice.reloadSkin();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
if (isKeyDown(Input.KEY_LALT) || isKeyDown(Input.KEY_RALT)) {
|
||||
UI.changeVolume((delta < 0) ? -1 : 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int button, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(int button, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
137
src/yugecin/opsudance/core/InstanceContainer.java
Normal file
137
src/yugecin/opsudance/core/InstanceContainer.java
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import itdelatrisu.opsu.NativeLoader;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||
import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||
import itdelatrisu.opsu.states.*;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.util.FileSystemLocation;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.options.OptionsService;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.utils.ManifestWrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static yugecin.opsudance.utils.SyntacticSugar.closeAndSwallow;
|
||||
|
||||
public class InstanceContainer {
|
||||
|
||||
public static Environment env;
|
||||
public static Configuration config;
|
||||
|
||||
public static OptionsService optionservice;
|
||||
public static SkinService skinservice;
|
||||
public static OszUnpacker oszunpacker;
|
||||
public static ReplayImporter replayImporter;
|
||||
public static BeatmapParser beatmapParser;
|
||||
public static Updater updater;
|
||||
|
||||
public static DisplayContainer displayContainer;
|
||||
public static Input input;
|
||||
|
||||
public static GameObjectRenderer gameObjectRenderer;
|
||||
|
||||
public static Splash splashState;
|
||||
public static MainMenu mainmenuState;
|
||||
public static ButtonMenu buttonState;
|
||||
public static SongMenu songMenuState;
|
||||
public static DownloadsMenu downloadState;
|
||||
public static Game gameState;
|
||||
public static GameRanking gameRankingState;
|
||||
public static GamePauseMenu pauseState;
|
||||
|
||||
public static void kickstart() {
|
||||
updater = new Updater();
|
||||
env = new Environment();
|
||||
|
||||
JarFile jarfile = getJarfile();
|
||||
ManifestWrapper manifest = new ManifestWrapper(getJarManifest(jarfile));
|
||||
config = new Configuration(manifest);
|
||||
if (jarfile != null) {
|
||||
try {
|
||||
NativeLoader.loadNatives(jarfile, manifest);
|
||||
} catch (IOException e) {
|
||||
String msg = String.format("Could not unpack native(s): %s", e.getMessage());
|
||||
throw new RuntimeException(msg, e);
|
||||
} finally {
|
||||
closeAndSwallow(jarfile);
|
||||
}
|
||||
}
|
||||
NativeLoader.setNativePath();
|
||||
|
||||
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
|
||||
|
||||
optionservice = new OptionsService();
|
||||
skinservice = new SkinService();
|
||||
oszunpacker = new OszUnpacker();
|
||||
replayImporter = new ReplayImporter();
|
||||
beatmapParser = new BeatmapParser();
|
||||
updater = new Updater();
|
||||
|
||||
displayContainer = new DisplayContainer();
|
||||
|
||||
gameObjectRenderer = new GameObjectRenderer();
|
||||
|
||||
splashState = new Splash();
|
||||
mainmenuState = new MainMenu();
|
||||
buttonState = new ButtonMenu();
|
||||
songMenuState = new SongMenu();
|
||||
downloadState = new DownloadsMenu();
|
||||
gameState = new Game();
|
||||
gameRankingState = new GameRanking();
|
||||
pauseState = new GamePauseMenu();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JarFile getJarfile() {
|
||||
if (env.jarfile == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new JarFile(env.jarfile);
|
||||
} catch (IOException e) {
|
||||
String msg = String.format("Cannot read from jarfile (%s): %s", env.jarfile.getAbsolutePath(),
|
||||
e.getMessage());
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Manifest getJarManifest(@Nullable JarFile jarfile) {
|
||||
if (jarfile == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return jarfile.getManifest();
|
||||
} catch (IOException e) {
|
||||
String msg = String.format("Cannot read manifest from jarfile: %s", e.getMessage());
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,13 +15,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
public class EmptyTransitionState extends TransitionState {
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
finish();
|
||||
}
|
||||
|
||||
}
|
||||
@Retention(RetentionPolicy.SOURCE) public @interface NotNull {}
|
||||
@@ -15,10 +15,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.events;
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
public interface EventListener<T> {
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
void onEvent(T event);
|
||||
|
||||
}
|
||||
@Retention(RetentionPolicy.SOURCE) public @interface Nullable {}
|
||||
@@ -19,8 +19,7 @@ package yugecin.opsudance.core.errorhandling;
|
||||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.core.Constants;
|
||||
import yugecin.opsudance.utils.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -35,80 +34,52 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* based on itdelatrisu.opsu.ErrorHandler
|
||||
*/
|
||||
public class ErrorHandler {
|
||||
|
||||
private static ErrorHandler instance;
|
||||
|
||||
private final Configuration config;
|
||||
private final DisplayContainer displayContainer;
|
||||
|
||||
private String customMessage;
|
||||
private Throwable cause;
|
||||
private String errorDump;
|
||||
private String messageBody;
|
||||
|
||||
private boolean preventContinue;
|
||||
private boolean preventReport;
|
||||
private boolean ignoreAndContinue;
|
||||
private boolean allowTerminate;
|
||||
|
||||
public ErrorHandler(DisplayContainer displayContainer, Configuration config) {
|
||||
this.displayContainer = displayContainer;
|
||||
this.config = config;
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private ErrorHandler init(String customMessage, Throwable cause) {
|
||||
this.customMessage = customMessage;
|
||||
this.cause = cause;
|
||||
public final static int DEFAULT_OPTIONS = 0;
|
||||
public final static int PREVENT_CONTINUE = 1;
|
||||
public final static int PREVENT_REPORT = 2;
|
||||
public final static int ALLOW_TERMINATE = 4;
|
||||
|
||||
public static boolean explode(String customMessage, Throwable cause, int flags) {
|
||||
StringWriter dump = new StringWriter();
|
||||
try {
|
||||
displayContainer.writeErrorDump(dump);
|
||||
} catch (Exception e) {
|
||||
dump
|
||||
.append("### ")
|
||||
.append(e.getClass().getSimpleName())
|
||||
.append(" while creating errordump");
|
||||
e.printStackTrace(new PrintWriter(dump));
|
||||
if (displayContainer == null) {
|
||||
dump.append("displayContainer is null!\n");
|
||||
} else {
|
||||
try {
|
||||
displayContainer.writeErrorDump(dump);
|
||||
} catch (Exception e) {
|
||||
dump
|
||||
.append("### ")
|
||||
.append(e.getClass().getSimpleName())
|
||||
.append(" while creating errordump");
|
||||
e.printStackTrace(new PrintWriter(dump));
|
||||
}
|
||||
}
|
||||
errorDump = dump.toString();
|
||||
String errorDump = dump.toString();
|
||||
|
||||
dump = new StringWriter();
|
||||
dump.append(customMessage).append("\n");
|
||||
cause.printStackTrace(new PrintWriter(dump));
|
||||
dump.append("\n").append(errorDump);
|
||||
messageBody = dump.toString();
|
||||
String messageBody = dump.toString();
|
||||
|
||||
Log.error("====== start unhandled exception dump");
|
||||
Log.error(messageBody);
|
||||
Log.error("====== end unhandled exception dump");
|
||||
return this;
|
||||
|
||||
int result = show(messageBody, customMessage, cause, errorDump, flags);
|
||||
|
||||
return (flags & ALLOW_TERMINATE) == 0 || result == 1;
|
||||
}
|
||||
|
||||
public static ErrorHandler error(String message, Throwable cause) {
|
||||
return instance.init(message, cause);
|
||||
}
|
||||
|
||||
public ErrorHandler preventReport() {
|
||||
preventReport = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorHandler allowTerminate() {
|
||||
allowTerminate = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorHandler preventContinue() {
|
||||
preventContinue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorHandler show() {
|
||||
private static int show(final String messageBody, final String customMessage, final Throwable cause,
|
||||
final String errorDump, final int flags) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
@@ -118,7 +89,7 @@ public class ErrorHandler {
|
||||
String title = "opsu!dance error - " + customMessage;
|
||||
|
||||
String messageText = "opsu!dance has encountered an error.";
|
||||
if (!preventReport) {
|
||||
if ((flags & PREVENT_REPORT) == 0) {
|
||||
messageText += " Please report this!";
|
||||
}
|
||||
JLabel message = new JLabel(messageText);
|
||||
@@ -132,12 +103,27 @@ public class ErrorHandler {
|
||||
textArea.setWrapStyleWord(true);
|
||||
textArea.setText(messageBody);
|
||||
|
||||
Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(), createReportButton() };
|
||||
ActionListener reportAction = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
URI url = createGithubIssueUrl(customMessage, cause, errorDump);
|
||||
Desktop.getDesktop().browse(url);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open browser to report issue", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not launch a browser",
|
||||
"errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(),
|
||||
createReportButton(flags, reportAction) };
|
||||
|
||||
String[] buttons;
|
||||
if (!allowTerminate && !preventContinue) {
|
||||
if ((flags & (ALLOW_TERMINATE | PREVENT_CONTINUE)) == 0) {
|
||||
buttons = new String[] { "Ignore & continue" };
|
||||
} else if (preventContinue) {
|
||||
} else if ((flags & PREVENT_CONTINUE) == 0) {
|
||||
buttons = new String[] { "Terminate" };
|
||||
} else {
|
||||
buttons = new String[] { "Terminate", "Ignore & continue" };
|
||||
@@ -147,52 +133,46 @@ public class ErrorHandler {
|
||||
frame.setUndecorated(true);
|
||||
frame.setVisible(true);
|
||||
frame.setLocationRelativeTo(null);
|
||||
int result = JOptionPane.showOptionDialog(frame,
|
||||
messageComponents,
|
||||
title,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE,
|
||||
null,
|
||||
buttons,
|
||||
buttons[buttons.length - 1]);
|
||||
ignoreAndContinue = !allowTerminate || result == 1;
|
||||
int result = JOptionPane.showOptionDialog(frame, messageComponents, title, JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE, null, buttons, buttons[buttons.length - 1]);
|
||||
frame.dispose();
|
||||
|
||||
return this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private JComponent createViewLogButton() {
|
||||
private static JComponent createViewLogButton() {
|
||||
return createButton("View log", Desktop.Action.OPEN, new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
Desktop.getDesktop().open(config.LOG_FILE);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open log file", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not open log file", "errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
openLogfile();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JComponent createReportButton() {
|
||||
if (preventReport) {
|
||||
private static void openLogfile() {
|
||||
if (config == null) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"Cannot open logfile, check your opsu! installation folder for .opsu.cfg",
|
||||
"errorception", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Desktop.getDesktop().open(config.LOG_FILE);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open log file", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not open log file",
|
||||
"errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private static JComponent createReportButton(int flags, ActionListener reportAction) {
|
||||
if ((flags & PREVENT_REPORT) > 0) {
|
||||
return new JLabel();
|
||||
}
|
||||
return createButton("Report error", Desktop.Action.BROWSE, new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(createGithubIssueUrl());
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open browser to report issue", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not launch a browser", "errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
return createButton("Report error", Desktop.Action.BROWSE, reportAction);
|
||||
}
|
||||
|
||||
private JButton createButton(String buttonText, Desktop.Action action, ActionListener listener) {
|
||||
private static JButton createButton(String buttonText, Desktop.Action action, ActionListener listener) {
|
||||
JButton button = new JButton(buttonText);
|
||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(action)) {
|
||||
button.addActionListener(listener);
|
||||
@@ -202,7 +182,7 @@ public class ErrorHandler {
|
||||
return button;
|
||||
}
|
||||
|
||||
private URI createGithubIssueUrl() {
|
||||
private static URI createGithubIssueUrl(String customMessage, Throwable cause, String errorDump) {
|
||||
StringWriter dump = new StringWriter();
|
||||
|
||||
dump.append(customMessage).append("\n");
|
||||
@@ -227,15 +207,16 @@ public class ErrorHandler {
|
||||
String issueTitle = "";
|
||||
String issueBody = "";
|
||||
try {
|
||||
issueTitle = URLEncoder.encode("*** Unhandled " + cause.getClass().getSimpleName() + " " + customMessage, "UTF-8");
|
||||
issueTitle = URLEncoder.encode("*** Unhandled " + cause.getClass().getSimpleName() + " " +
|
||||
customMessage, "UTF-8");
|
||||
issueBody = URLEncoder.encode(truncateGithubIssueBody(dump.toString()), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.warn("URLEncoder failed to encode the auto-filled issue report URL.", e);
|
||||
}
|
||||
return URI.create(String.format(config.ISSUES_URL, issueTitle, issueBody));
|
||||
return URI.create(String.format(Constants.ISSUES_URL, issueTitle, issueBody));
|
||||
}
|
||||
|
||||
private String truncateGithubIssueBody(String body) {
|
||||
private static String truncateGithubIssueBody(String body) {
|
||||
if (body.replaceAll("[^a-zA-Z+-]", "").length() < 1750) {
|
||||
return body;
|
||||
}
|
||||
@@ -243,8 +224,4 @@ public class ErrorHandler {
|
||||
return body.substring(0, 1640) + "** TRUNCATED **\n```";
|
||||
}
|
||||
|
||||
public boolean shouldIgnoreAndContinue() {
|
||||
return ignoreAndContinue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,38 +17,37 @@
|
||||
*/
|
||||
package yugecin.opsudance.core.events;
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.LinkedList;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class EventBus {
|
||||
public class Event<T> {
|
||||
|
||||
private EventBus() {
|
||||
private final Class<T> type;
|
||||
private final LinkedList<T> listeners;
|
||||
|
||||
public Event(Class<T> type) {
|
||||
this.type = type;
|
||||
this.listeners = new LinkedList<>();
|
||||
}
|
||||
|
||||
private static final List<Subscriber> subscribers = new LinkedList<>();
|
||||
|
||||
public static <T> void subscribe(Class<T> eventType, EventListener<T> eventListener) {
|
||||
subscribers.add(new Subscriber<>(eventType, eventListener));
|
||||
public void addListener(T listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public static void post(Object event) {
|
||||
for (Subscriber s : subscribers) {
|
||||
if (s.eventType.isInstance(event)) {
|
||||
s.listener.onEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Subscriber<T> {
|
||||
|
||||
private final Class<T> eventType;
|
||||
private final EventListener<T> listener;
|
||||
|
||||
private Subscriber(Class<T> eventType, EventListener<T> listener) {
|
||||
this.eventType = eventType;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public T make() {
|
||||
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
for (T listener : listeners) {
|
||||
method.invoke(listener, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
*
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.inject;
|
||||
@@ -22,14 +23,10 @@ import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||
import itdelatrisu.opsu.states.*;
|
||||
import yugecin.opsudance.PreStartupInitializer;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubNotifState;
|
||||
import yugecin.opsudance.core.state.specialstates.FpsRenderState;
|
||||
import yugecin.opsudance.core.state.transitions.EmptyTransitionState;
|
||||
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
|
||||
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.options.OptionsService;
|
||||
@@ -48,18 +45,14 @@ public class OpsuDanceInjector extends Injector {
|
||||
bind(Updater.class).asLazySingleton();
|
||||
bind(SkinService.class).asEagerSingleton();
|
||||
|
||||
bind(PreStartupInitializer.class).asEagerSingleton();
|
||||
//bind(PreStartupInitializer.class).asEagerSingleton();
|
||||
bind(DisplayContainer.class).asEagerSingleton();
|
||||
|
||||
bind(ErrorHandler.class).asEagerSingleton();
|
||||
|
||||
bind(FpsRenderState.class).asEagerSingleton();
|
||||
bind(BarNotificationState.class).asEagerSingleton();
|
||||
bind(BubbleNotificationState.class).asEagerSingleton();
|
||||
|
||||
bind(EmptyTransitionState.class).asEagerSingleton();
|
||||
bind(FadeInTransitionState.class).asEagerSingleton();
|
||||
bind(FadeOutTransitionState.class).asEagerSingleton();
|
||||
bind(BubNotifState.class).asEagerSingleton();
|
||||
|
||||
bind(GameObjectRenderer.class).asEagerSingleton();
|
||||
|
||||
|
||||
@@ -17,33 +17,12 @@
|
||||
*/
|
||||
package yugecin.opsudance.core.state;
|
||||
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public abstract class BaseOpsuState implements OpsuState, EventListener<ResolutionOrSkinChangedEvent> {
|
||||
|
||||
@Inject
|
||||
protected DisplayContainer displayContainer;
|
||||
|
||||
@Inject
|
||||
protected Configuration config;
|
||||
|
||||
@Inject
|
||||
protected SkinService skinService;
|
||||
public abstract class BaseOpsuState implements OpsuState, ResolutionChangedListener {
|
||||
|
||||
/**
|
||||
* state is dirty when resolution or skin changed but hasn't rendered yet
|
||||
@@ -52,7 +31,7 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
||||
private boolean isCurrentState;
|
||||
|
||||
public BaseOpsuState() {
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
protected void revalidate() {
|
||||
@@ -71,7 +50,7 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
if (isCurrentState) {
|
||||
revalidate();
|
||||
return;
|
||||
@@ -105,32 +84,11 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
||||
|
||||
@Override
|
||||
public boolean keyReleased(int key, char c) {
|
||||
if (key == Input.KEY_F7) {
|
||||
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
|
||||
EventBus.post(new BarNotificationEvent(String.format("Frame limiter: %s", OPTION_TARGET_FPS.getValueString())));
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_F10) {
|
||||
OPTION_DISABLE_MOUSE_BUTTONS.toggle();
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_F12) {
|
||||
config.takeScreenShot();
|
||||
return true;
|
||||
}
|
||||
Input input = displayContainer.input;
|
||||
if (key == Input.KEY_S && input.isKeyDown(Input.KEY_LMENU) && input.isKeyDown(Input.KEY_LSHIFT) &&input.isKeyDown(Input.KEY_LCONTROL) && !displayContainer.isInState(Game.class)) {
|
||||
skinService.reloadSkin();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) {
|
||||
UI.changeVolume((delta < 0) ? -1 : 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
*/
|
||||
package yugecin.opsudance.core.state;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import yugecin.opsudance.core.components.Component;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public abstract class ComplexOpsuState extends BaseOpsuState {
|
||||
|
||||
protected final LinkedList<Component> components;
|
||||
@@ -163,7 +165,7 @@ public abstract class ComplexOpsuState extends BaseOpsuState {
|
||||
}
|
||||
}
|
||||
if (focusedComponent != null) {
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
focusedComponent.setFocused(false);
|
||||
focusedComponent = null;
|
||||
return true;
|
||||
@@ -182,7 +184,7 @@ public abstract class ComplexOpsuState extends BaseOpsuState {
|
||||
}
|
||||
}
|
||||
if (focusedComponent != null) {
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
focusedComponent.setFocused(false);
|
||||
focusedComponent = null;
|
||||
return true;
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
package yugecin.opsudance.core.state;
|
||||
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.InputListener;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
|
||||
|
||||
public interface OpsuState extends ErrorDumpable {
|
||||
public interface OpsuState extends ErrorDumpable, InputListener {
|
||||
|
||||
void update();
|
||||
void preRenderUpdate();
|
||||
@@ -33,34 +34,4 @@ public interface OpsuState extends ErrorDumpable {
|
||||
*/
|
||||
boolean onCloseRequest();
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean keyPressed(int key, char c);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean keyReleased(int key, char c);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mouseWheelMoved(int delta);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mousePressed(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mouseReleased(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mouseDragged(int oldx, int oldy, int newx, int newy);
|
||||
|
||||
}
|
||||
|
||||
@@ -21,22 +21,20 @@ import itdelatrisu.opsu.ui.Fonts;
|
||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BarNotificationState implements EventListener<BarNotificationEvent> {
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
public class BarNotificationState implements BarNotifListener, ResolutionChangedListener {
|
||||
|
||||
private final int IN_TIME = 200;
|
||||
private final int DISPLAY_TIME = 5700 + IN_TIME;
|
||||
private final int OUT_TIME = 200;
|
||||
private final int TOTAL_TIME = DISPLAY_TIME + OUT_TIME;
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
private final Color bgcol;
|
||||
private final Color textCol;
|
||||
|
||||
@@ -49,21 +47,12 @@ public class BarNotificationState implements EventListener<BarNotificationEvent>
|
||||
private int barHalfTargetHeight;
|
||||
private int barHalfHeight;
|
||||
|
||||
public BarNotificationState(DisplayContainer displayContainer) {
|
||||
this.displayContainer = displayContainer;
|
||||
public BarNotificationState() {
|
||||
this.bgcol = new Color(Color.black);
|
||||
this.textCol = new Color(Color.white);
|
||||
this.timeShown = TOTAL_TIME;
|
||||
EventBus.subscribe(BarNotificationEvent.class, this);
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
if (timeShown >= TOTAL_TIME) {
|
||||
return;
|
||||
}
|
||||
calculatePosition();
|
||||
}
|
||||
});
|
||||
BarNotifListener.EVENT.addListener(this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
public void render(Graphics g) {
|
||||
@@ -108,10 +97,18 @@ public class BarNotificationState implements EventListener<BarNotificationEvent>
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(BarNotificationEvent event) {
|
||||
this.message = event.message;
|
||||
public void onBarNotif(String message) {
|
||||
this.message = message;
|
||||
calculatePosition();
|
||||
timeShown = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
if (timeShown >= TOTAL_TIME) {
|
||||
return;
|
||||
}
|
||||
calculatePosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,40 +21,33 @@ import itdelatrisu.opsu.ui.Fonts;
|
||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import org.newdawn.slick.MouseListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class BubbleNotificationState implements EventListener<BubbleNotificationEvent> {
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class BubNotifState implements MouseListener, BubNotifListener, ResolutionChangedListener {
|
||||
|
||||
public static final int IN_TIME = 633;
|
||||
public static final int DISPLAY_TIME = 7000 + IN_TIME;
|
||||
public static final int OUT_TIME = 433;
|
||||
public static final int TOTAL_TIME = DISPLAY_TIME + OUT_TIME;
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
private final LinkedList<Notification> bubbles;
|
||||
|
||||
private int addAnimationTime;
|
||||
private int addAnimationHeight;
|
||||
|
||||
public BubbleNotificationState(DisplayContainer displayContainer) {
|
||||
this.displayContainer = displayContainer;
|
||||
public BubNotifState() {
|
||||
this.bubbles = new LinkedList<>();
|
||||
this.addAnimationTime = IN_TIME;
|
||||
EventBus.subscribe(BubbleNotificationEvent.class, this);
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
calculatePositions();
|
||||
}
|
||||
});
|
||||
BubNotifListener.EVENT.addListener(this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
public void render(Graphics g) {
|
||||
@@ -79,20 +72,9 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
||||
} while (iter.hasNext());
|
||||
}
|
||||
|
||||
public boolean mouseReleased(int x, int y) {
|
||||
if (x < Notification.finalX) {
|
||||
return false;
|
||||
}
|
||||
for (Notification bubble : bubbles) {
|
||||
if (bubble.mouseReleased(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void calculatePositions() {
|
||||
Notification.width = (int) (displayContainer.width * 0.1703125f);
|
||||
// if width is 0, attempting to wrap it will result in infinite loop
|
||||
Notification.width = Math.max(50, (int) (displayContainer.width * 0.1703125f));
|
||||
Notification.baseLine = (int) (displayContainer.height * 0.9645f);
|
||||
Notification.paddingY = (int) (displayContainer.height * 0.0144f);
|
||||
Notification.finalX = displayContainer.width - Notification.width - (int) (displayContainer.width * 0.01);
|
||||
@@ -130,9 +112,9 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(BubbleNotificationEvent event) {
|
||||
public void onBubNotif(String message, Color borderColor) {
|
||||
finishAddAnimation();
|
||||
Notification newBubble = new Notification(event.message, event.borderColor);
|
||||
Notification newBubble = new Notification(message, borderColor);
|
||||
bubbles.add(0, newBubble);
|
||||
addAnimationTime = 0;
|
||||
addAnimationHeight = newBubble.height + Notification.paddingY;
|
||||
@@ -144,6 +126,39 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
calculatePositions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int button, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(int button, int x, int y) {
|
||||
if (x < Notification.finalX) {
|
||||
return false;
|
||||
}
|
||||
for (Notification bubble : bubbles) {
|
||||
if (bubble.mouseReleased(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class Notification {
|
||||
|
||||
private final static int HOVER_ANIM_TIME = 150;
|
||||
@@ -205,7 +220,7 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
||||
Fonts.SMALLBOLD.drawString(x + fontPaddingX, y, line, textColor);
|
||||
y += lineHeight;
|
||||
}
|
||||
return timeShown > BubbleNotificationState.TOTAL_TIME;
|
||||
return timeShown > BubNotifState.TOTAL_TIME;
|
||||
}
|
||||
|
||||
private void processAnimations(boolean mouseHovered, int delta) {
|
||||
@@ -218,17 +233,17 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
||||
borderColor.r = targetBorderColor.r + (0.977f - targetBorderColor.r) * hoverProgress;
|
||||
borderColor.g = targetBorderColor.g + (0.977f - targetBorderColor.g) * hoverProgress;
|
||||
borderColor.b = targetBorderColor.b + (0.977f - targetBorderColor.b) * hoverProgress;
|
||||
if (timeShown < BubbleNotificationState.IN_TIME) {
|
||||
float progress = (float) timeShown / BubbleNotificationState.IN_TIME;
|
||||
if (timeShown < BubNotifState.IN_TIME) {
|
||||
float progress = (float) timeShown / BubNotifState.IN_TIME;
|
||||
this.x = finalX + (int) ((1 - AnimationEquation.OUT_BACK.calc(progress)) * width / 2);
|
||||
textColor.a = borderColor.a = bgcol.a = progress;
|
||||
bgcol.a = borderColor.a * 0.8f;
|
||||
return;
|
||||
}
|
||||
x = Notification.finalX;
|
||||
if (timeShown > BubbleNotificationState.DISPLAY_TIME) {
|
||||
if (timeShown > BubNotifState.DISPLAY_TIME) {
|
||||
isFading = true;
|
||||
float progress = (float) (timeShown - BubbleNotificationState.DISPLAY_TIME) / BubbleNotificationState.OUT_TIME;
|
||||
float progress = (float) (timeShown - BubNotifState.DISPLAY_TIME) / BubNotifState.OUT_TIME;
|
||||
textColor.a = borderColor.a = 1f - progress;
|
||||
bgcol.a = borderColor.a * 0.8f;
|
||||
}
|
||||
@@ -236,7 +251,7 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
||||
|
||||
private boolean mouseReleased(int x, int y) {
|
||||
if (!isFading && isMouseHovered(x, y)) {
|
||||
timeShown = BubbleNotificationState.DISPLAY_TIME;
|
||||
timeShown = BubNotifState.DISPLAY_TIME;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -20,21 +20,18 @@ package yugecin.opsudance.core.state.specialstates;
|
||||
import itdelatrisu.opsu.ui.Fonts;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
import yugecin.opsudance.utils.FPSMeter;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEvent> {
|
||||
public class FpsRenderState implements ResolutionChangedListener {
|
||||
|
||||
private final static Color GREEN = new Color(171, 218, 25);
|
||||
private final static Color ORANGE = new Color(255, 204, 34);
|
||||
private final static Color DARKORANGE = new Color(255, 149, 24);
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
private final FPSMeter fpsMeter;
|
||||
private final FPSMeter upsMeter;
|
||||
|
||||
@@ -42,11 +39,10 @@ public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEven
|
||||
private int y;
|
||||
private int singleHeight;
|
||||
|
||||
public FpsRenderState(DisplayContainer displayContainer) {
|
||||
this.displayContainer = displayContainer;
|
||||
public FpsRenderState() {
|
||||
fpsMeter = new FPSMeter(10);
|
||||
upsMeter = new FPSMeter(10);
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
@@ -93,7 +89,7 @@ public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEven
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
singleHeight = Fonts.SMALL.getLineHeight();
|
||||
x = displayContainer.width - 3;
|
||||
y = displayContainer.height - 3 - singleHeight - 10;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
|
||||
public interface TransitionFinishedListener {
|
||||
|
||||
void onFinish();
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
import yugecin.opsudance.core.state.OpsuState;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
public abstract class TransitionState extends BaseOpsuState {
|
||||
|
||||
protected OpsuState applicableState;
|
||||
|
||||
protected int transitionTargetTime;
|
||||
protected int transitionTime;
|
||||
|
||||
private TransitionFinishedListener listener;
|
||||
|
||||
public final TransitionState set(OpsuState applicableState, int targetTime, TransitionFinishedListener listener) {
|
||||
this.applicableState = applicableState;
|
||||
this.transitionTargetTime = targetTime;
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final OpsuState getApplicableState() {
|
||||
return applicableState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
applicableState.update();
|
||||
transitionTime += displayContainer.delta;
|
||||
if (transitionTime >= transitionTargetTime) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRenderUpdate() {
|
||||
applicableState.preRenderUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics g) {
|
||||
applicableState.render(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
super.enter();
|
||||
transitionTime = 0;
|
||||
}
|
||||
|
||||
protected final void finish() {
|
||||
listener.onFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCloseRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeErrorDump(StringWriter dump) {
|
||||
dump.append("> TransitionState dump\n");
|
||||
dump.append("progress: ").append(String.valueOf(transitionTime)).append("/").append(String.valueOf(transitionTargetTime)).append('\n');
|
||||
dump.append("applicable state: ");
|
||||
if (applicableState == null) {
|
||||
dump.append("IS NULL");
|
||||
return;
|
||||
}
|
||||
dump.append(applicableState.getClass().getSimpleName()).append('\n');
|
||||
applicableState.writeErrorDump(dump);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,12 +17,12 @@
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
public class BarNotificationEvent {
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
public final String message;
|
||||
public interface BarNotifListener {
|
||||
|
||||
public BarNotificationEvent(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
Event<BarNotifListener> EVENT = new Event<>(BarNotifListener.class);
|
||||
|
||||
void onBarNotif(String message);
|
||||
|
||||
}
|
||||
30
src/yugecin/opsudance/events/BubNotifListener.java
Normal file
30
src/yugecin/opsudance/events/BubNotifListener.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
@SuppressWarnings({"UnnecessaryInterfaceModifier", "unused"})
|
||||
public interface BubNotifListener {
|
||||
|
||||
Event<BubNotifListener> EVENT = new Event<>(BubNotifListener.class);
|
||||
|
||||
void onBubNotif(String message, Color borderColor);
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
|
||||
public class BubbleNotificationEvent {
|
||||
|
||||
public static final Color COMMONCOLOR_GREEN = new Color(98, 131, 59);
|
||||
public static final Color COMMONCOLOR_WHITE = new Color(220, 220, 220);
|
||||
public static final Color COMMONCOLOR_PURPLE = new Color(94, 46, 149);
|
||||
public static final Color COMMONCOLOR_RED = new Color(141, 49, 16);
|
||||
public static final Color COLOR_ORANGE = new Color(138, 72, 51);
|
||||
|
||||
public final String message;
|
||||
public final Color borderColor;
|
||||
|
||||
public BubbleNotificationEvent(String message, Color borderColor) {
|
||||
this.message = message;
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,16 +17,12 @@
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
public class ResolutionOrSkinChangedEvent {
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
public final String skin;
|
||||
public final int width;
|
||||
public final int height;
|
||||
public interface ResolutionChangedListener {
|
||||
|
||||
public ResolutionOrSkinChangedEvent(String skin, int width, int height) {
|
||||
this.skin = skin;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
Event<ResolutionChangedListener> EVENT = new Event<>(ResolutionChangedListener.class);
|
||||
|
||||
void onResolutionChanged(int w, int h);
|
||||
|
||||
}
|
||||
@@ -15,13 +15,14 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
public class FadeInTransitionState extends FadeTransitionState {
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
@Override
|
||||
protected float getMaskAlphaLevel(float fadeProgress) {
|
||||
return 1f - fadeProgress;
|
||||
}
|
||||
public interface SkinChangedListener {
|
||||
|
||||
Event<SkinChangedListener> EVENT = new Event<>(SkinChangedListener.class);
|
||||
|
||||
void onSkinChanged(String stringName);
|
||||
|
||||
}
|
||||
@@ -19,7 +19,8 @@ package yugecin.opsudance.movers;
|
||||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class CircleMover extends Mover {
|
||||
|
||||
@@ -32,12 +33,12 @@ public class CircleMover extends Mover {
|
||||
public CircleMover(GameObject start, GameObject end, int dir) {
|
||||
super(start, end, dir);
|
||||
if (startX - endX == 0 && startY - endY == 0) {
|
||||
int quadr = Utils.getQuadrant(startX, startY);
|
||||
int quadr = Utils.getRegion(startX, startY);
|
||||
switch (quadr) {
|
||||
case 1: ang = 135d / 180d * Math.PI; break;
|
||||
case 3: ang = 135d / 180d * Math.PI; break;
|
||||
case 2: ang = 45d / 180d * Math.PI; break;
|
||||
case 3: ang = -45d / 180d * Math.PI; break;
|
||||
case 4: ang = -135d / 180d * Math.PI; break;
|
||||
case 0: ang = -45d / 180d * Math.PI; break;
|
||||
case 1: ang = -135d / 180d * Math.PI; break;
|
||||
}
|
||||
} else {
|
||||
ang = Math.atan2(startY - endY, startX - endX);
|
||||
@@ -63,7 +64,7 @@ public class CircleMover extends Mover {
|
||||
double a = ang + SOME_CONSTANT * t;
|
||||
pos[0] = (startX + (endX - startX) * t) - middlexoffset - Math.cos(a) * radius;
|
||||
pos[1] = (startY + (endY - startY) * t) - middleyoffset - Math.sin(a) * radius;
|
||||
if (pos[0] < 0 || Options.width < pos[0] || pos[1] < 0 || Options.height < pos[1]) {
|
||||
if (pos[0] < 0 || displayContainer.width < pos[0] || pos[1] < 0 || displayContainer.height < pos[1]) {
|
||||
pass = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
package yugecin.opsudance.movers;
|
||||
|
||||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class ExgonMover extends Mover {
|
||||
|
||||
@@ -44,8 +44,8 @@ public class ExgonMover extends Mover {
|
||||
pos[0] = endX;
|
||||
pos[1] = endY;
|
||||
} else {
|
||||
pos[0] = randgen.nextInt(Options.width);
|
||||
pos[1] = randgen.nextInt(Options.height);
|
||||
pos[0] = randgen.nextInt(displayContainer.width);
|
||||
pos[1] = randgen.nextInt(displayContainer.height);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
|
||||
@@ -22,9 +22,8 @@ import itdelatrisu.opsu.beatmap.HitObject;
|
||||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import yugecin.opsudance.Pippi;
|
||||
import yugecin.opsudance.movers.*;
|
||||
import yugecin.opsudance.options.Options;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class AutoMoverFactory implements MoverFactory {
|
||||
@@ -45,7 +44,7 @@ public class AutoMoverFactory implements MoverFactory {
|
||||
|
||||
// stacked: circles if not too quick
|
||||
int circle_stream = OPTION_DANCE_CIRCLE_STREAMS.state ? 58: 85;
|
||||
if (distance < GameObjectRenderer.instance.getCircleDiameter() && ((dt > circle_stream && !OPTION_DANCE_ONLY_CIRCLE_STACKS.state) || distance < HitObject.getStackOffset() * 5.2f)) { // TODO get the correct multiplier for stackoffsets
|
||||
if (distance < gameObjectRenderer.circleDiameter && ((dt > circle_stream && !OPTION_DANCE_ONLY_CIRCLE_STACKS.state) || distance < HitObject.getStackOffset() * 5.2f)) { // TODO get the correct multiplier for stackoffsets
|
||||
return new CircleMover(start, end, dir);
|
||||
}
|
||||
|
||||
@@ -103,7 +102,8 @@ public class AutoMoverFactory implements MoverFactory {
|
||||
}
|
||||
|
||||
private boolean checkBounds( double[] pos ) {
|
||||
return 0 < pos[0] && pos[0] < Options.width - Options.width / 8 && 0 < pos[1] && pos[1] < Options.height - Options.height / 8;
|
||||
return 0 < pos[0] && pos[0] < displayContainer.width - displayContainer.width / 8 &&
|
||||
0 < pos[1] && pos[1] < displayContainer.height - displayContainer.height / 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,36 +20,31 @@ package yugecin.opsudance.options;
|
||||
import com.sun.jna.platform.win32.Advapi32Util;
|
||||
import com.sun.jna.platform.win32.Win32Exception;
|
||||
import com.sun.jna.platform.win32.WinReg;
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.audio.SoundController;
|
||||
import itdelatrisu.opsu.audio.SoundEffect;
|
||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||
import itdelatrisu.opsu.beatmap.TimingPoint;
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.utils.ManifestWrapper;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Paths;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class Configuration {
|
||||
|
||||
@@ -67,13 +62,6 @@ public class Configuration {
|
||||
public final File LOG_FILE;
|
||||
public final File OPTIONS_FILE;
|
||||
|
||||
public final String FONT_NAME;
|
||||
public final String VERSION_FILE;
|
||||
public final URI REPOSITORY_URI;
|
||||
public final URI DANCE_REPOSITORY_URI;
|
||||
public final String ISSUES_URL;
|
||||
public final String VERSION_REMOTE;
|
||||
|
||||
public final File osuInstallationDirectory;
|
||||
|
||||
public final Beatmap themeBeatmap;
|
||||
@@ -85,9 +73,8 @@ public class Configuration {
|
||||
public File replayImportDir;
|
||||
public File skinRootDir;
|
||||
|
||||
@Inject
|
||||
public Configuration() {
|
||||
USE_XDG = areXDGDirectoriesEnabled();
|
||||
public Configuration(ManifestWrapper jarmanifest) {
|
||||
USE_XDG = jarmanifest.valueOrDefault(null, "Use-XDG", "").equalsIgnoreCase("true");
|
||||
|
||||
CONFIG_DIR = getXDGBaseDir("XDG_CONFIG_HOME", ".config");
|
||||
DATA_DIR = getXDGBaseDir("XDG_DATA_HOME", ".local/share");
|
||||
@@ -103,13 +90,6 @@ public class Configuration {
|
||||
LOG_FILE = new File(CONFIG_DIR, ".opsu.log");
|
||||
OPTIONS_FILE = new File(CONFIG_DIR, ".opsu.cfg");
|
||||
|
||||
FONT_NAME = "DroidSansFallback.ttf";
|
||||
VERSION_FILE = "version";
|
||||
REPOSITORY_URI = URI.create("https://github.com/itdelatrisu/opsu");
|
||||
DANCE_REPOSITORY_URI = URI.create("https://github.com/yugecin/opsu-dance");
|
||||
ISSUES_URL = "https://github.com/yugecin/opsu-dance/issues/new?title=%s&body=%s";
|
||||
VERSION_REMOTE = "https://raw.githubusercontent.com/yugecin/opsu-dance/master/version";
|
||||
|
||||
osuInstallationDirectory = loadOsuInstallationDirectory();
|
||||
|
||||
themeBeatmap = createThemeBeatmap();
|
||||
@@ -117,14 +97,14 @@ public class Configuration {
|
||||
|
||||
private Beatmap createThemeBeatmap() {
|
||||
try {
|
||||
String[] tokens = {"theme.mp3", "Rainbows", "Kevin MacLeod", "219350"};
|
||||
String[] tokens = {"theme.ogg", "On the Bach", "Jingle Punks", "66000"};
|
||||
Beatmap beatmap = new Beatmap(null);
|
||||
beatmap.audioFilename = new File(tokens[0]);
|
||||
beatmap.title = tokens[1];
|
||||
beatmap.artist = tokens[2];
|
||||
beatmap.endTime = Integer.parseInt(tokens[3]);
|
||||
beatmap.timingPoints = new ArrayList<>(1);
|
||||
beatmap.timingPoints.add(new TimingPoint("1080,545.454545454545,4,1,0,100,0,0"));
|
||||
beatmap.timingPoints.add(new TimingPoint("-44,631.578947368421,4,1,0,100,1,0"));
|
||||
return beatmap;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
@@ -170,12 +150,12 @@ public class Configuration {
|
||||
}
|
||||
|
||||
private File loadDirectory(File dir, File defaultDir, String kind) {
|
||||
if (dir.exists() && dir.isDirectory()) {
|
||||
if (dir != null && dir.exists() && dir.isDirectory()) {
|
||||
return dir;
|
||||
}
|
||||
if (!defaultDir.isDirectory() && !defaultDir.mkdir()) {
|
||||
String msg = String.format("Failed to create %s directory at '%s'.", kind, defaultDir.getAbsolutePath());
|
||||
EventBus.post(new BubbleNotificationEvent(msg, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(msg, Colors.BUB_RED);
|
||||
}
|
||||
return defaultDir;
|
||||
}
|
||||
@@ -195,49 +175,24 @@ public class Configuration {
|
||||
return loadDirectory(dir, defaultDir, kind);
|
||||
}
|
||||
|
||||
private boolean areXDGDirectoriesEnabled() {
|
||||
JarFile jarFile = Utils.getJarFile();
|
||||
if (jarFile == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Manifest manifest = jarFile.getManifest();
|
||||
if (manifest == null) {
|
||||
return false;
|
||||
}
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
String value = attributes.getValue("Use-XDG");
|
||||
return (value != null && value.equalsIgnoreCase("true"));
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory based on the XDG base directory specification for
|
||||
* Unix-like operating systems, only if the "XDG" flag is enabled.
|
||||
* @param env the environment variable to check (XDG_*_*)
|
||||
* @param envvar the environment variable to check (XDG_*_*)
|
||||
* @param fallback the fallback directory relative to ~home
|
||||
* @return the XDG base directory, or the working directory if unavailable
|
||||
*/
|
||||
private File getXDGBaseDir(String env, String fallback) {
|
||||
File workingdir;
|
||||
if (Utils.isJarRunning()) {
|
||||
workingdir = Utils.getRunningDirectory().getParentFile();
|
||||
} else {
|
||||
workingdir = Paths.get(".").toAbsolutePath().normalize().toFile();
|
||||
}
|
||||
|
||||
private File getXDGBaseDir(String envvar, String fallback) {
|
||||
if (!USE_XDG) {
|
||||
return workingdir;
|
||||
return env.workingdir;
|
||||
}
|
||||
|
||||
String OS = System.getProperty("os.name").toLowerCase();
|
||||
if (OS.indexOf("nix") == -1 && OS.indexOf("nux") == -1 && OS.indexOf("aix") == -1){
|
||||
return workingdir;
|
||||
return env.workingdir;
|
||||
}
|
||||
|
||||
String rootPath = System.getenv(env);
|
||||
String rootPath = System.getenv(envvar);
|
||||
if (rootPath == null) {
|
||||
String home = System.getProperty("user.home");
|
||||
if (home == null) {
|
||||
@@ -247,7 +202,8 @@ public class Configuration {
|
||||
}
|
||||
File dir = new File(rootPath, "opsu");
|
||||
if (!dir.isDirectory() && !dir.mkdir()) {
|
||||
ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), new Exception("empty")).preventReport().show();
|
||||
explode(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath),
|
||||
new Exception("empty"), PREVENT_REPORT);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
@@ -259,7 +215,9 @@ public class Configuration {
|
||||
// TODO: get a decent place for this
|
||||
// create the screenshot directory
|
||||
if (!screenshotDir.isDirectory() && !screenshotDir.mkdir()) {
|
||||
EventBus.post(new BubbleNotificationEvent(String.format("Failed to create screenshot directory at '%s'.", screenshotDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
String.format( "Failed to create screenshot directory at '%s'.",
|
||||
screenshotDir.getAbsolutePath()), Colors.BUB_RED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,9 +251,13 @@ public class Configuration {
|
||||
}
|
||||
}
|
||||
ImageIO.write(image, OPTION_SCREENSHOT_FORMAT.getValueString().toLowerCase(), file);
|
||||
EventBus.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Created " + fileName,
|
||||
Colors.BUB_PURPLE);
|
||||
} catch (Exception e) {
|
||||
ErrorHandler.error("Failed to take a screenshot.", e).show();
|
||||
Log.error("Could not take screenshot", e);
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
"Failed to take a screenshot. See log file for details",
|
||||
Colors.BUB_PURPLE);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
package yugecin.opsudance.options;
|
||||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
public class NumericOption extends Option {
|
||||
|
||||
@@ -53,7 +53,8 @@ public class NumericOption extends Option {
|
||||
try {
|
||||
val = Utils.clamp(Integer.parseInt(s), min, max);
|
||||
} catch (Exception ignored) {
|
||||
EventBus.post(new BubbleNotificationEvent("Failed to parse " + configurationName + " option", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Failed to parse " + configurationName + " option",
|
||||
Colors.BUB_RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,22 +17,10 @@
|
||||
*/
|
||||
package yugecin.opsudance.options;
|
||||
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class Option {
|
||||
|
||||
// keep a reference to the instancecontainer so that not every option instance needs to be injected
|
||||
protected static InstanceContainer instanceContainer;
|
||||
// caching some commonly used classes
|
||||
protected static Configuration config;
|
||||
protected static DisplayContainer displayContainer;
|
||||
public static void setInstanceContainer(InstanceContainer instanceContainer) {
|
||||
Option.instanceContainer = instanceContainer;
|
||||
Option.config = instanceContainer.provide(Configuration.class);
|
||||
Option.displayContainer = instanceContainer.provide(DisplayContainer.class);
|
||||
}
|
||||
|
||||
public final String name;
|
||||
public final String configurationName;
|
||||
public final String description;
|
||||
@@ -54,7 +42,7 @@ public class Option {
|
||||
this.name = name;
|
||||
this.configurationName = configurationName;
|
||||
this.description = description;
|
||||
OptionsService.registerOption(this);
|
||||
optionservice.registerOption(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +78,10 @@ public class Option {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
public void setFiltered(boolean flag) {
|
||||
this.filtered = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this option should be filtered (= not shown) because it does not
|
||||
* match the search string.
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
|
||||
package yugecin.opsudance.options;
|
||||
|
||||
import itdelatrisu.opsu.GameImage;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class OptionGroups {
|
||||
|
||||
public static final OptionTab[] normalOptions = new OptionTab[] {
|
||||
new OptionTab("GENERAL", null),
|
||||
new OptionTab("General", GameImage.MENU_NAV_GENERAL),
|
||||
new OptionTab("GENERAL", new Option[]{
|
||||
OPTION_DISABLE_UPDATER,
|
||||
OPTION_ENABLE_WATCH_SERVICE
|
||||
@@ -31,7 +33,7 @@ public class OptionGroups {
|
||||
new OptionTab("LANGUAGE", new Option[]{
|
||||
OPTION_SHOW_UNICODE,
|
||||
}),
|
||||
new OptionTab("GRAPHICS", null),
|
||||
new OptionTab("Graphics", GameImage.MENU_NAV_GRAPHICS),
|
||||
new OptionTab("RENDERER", new Option[] {
|
||||
OPTION_SCREEN_RESOLUTION,
|
||||
OPTION_ALLOW_LARGER_RESOLUTIONS,
|
||||
@@ -54,7 +56,7 @@ public class OptionGroups {
|
||||
OPTION_DANCING_CIRCLES,
|
||||
OPTION_DANCING_CIRCLES_MULTIPLIER,
|
||||
}),
|
||||
new OptionTab("SKIN", null),
|
||||
new OptionTab("Skin", GameImage.MENU_NAV_SKIN),
|
||||
new OptionTab("SKIN", new Option[]{
|
||||
OPTION_SKIN,
|
||||
OPTION_IGNORE_BEATMAP_SKINS,
|
||||
@@ -69,7 +71,7 @@ public class OptionGroups {
|
||||
OPTION_DISABLE_CURSOR
|
||||
// TODO use combo colour as tint for slider ball option
|
||||
}),
|
||||
new OptionTab("AUDIO", null),
|
||||
new OptionTab("Audio", GameImage.MENU_NAV_AUDIO),
|
||||
new OptionTab("VOLUME", new Option[]{
|
||||
OPTION_MASTER_VOLUME,
|
||||
OPTION_MUSIC_VOLUME,
|
||||
@@ -82,7 +84,7 @@ public class OptionGroups {
|
||||
OPTION_DISABLE_SOUNDS,
|
||||
OPTION_ENABLE_THEME_SONG
|
||||
}),
|
||||
new OptionTab("GAMEPLAY", null),
|
||||
new OptionTab("Gameplay", GameImage.MENU_NAV_GAMEPLAY),
|
||||
new OptionTab("GENERAL", new Option[] {
|
||||
OPTION_BACKGROUND_DIM,
|
||||
OPTION_FORCE_DEFAULT_PLAYFIELD,
|
||||
@@ -96,7 +98,7 @@ public class OptionGroups {
|
||||
OPTION_MAP_END_DELAY,
|
||||
OPTION_EPILEPSY_WARNING,
|
||||
}),
|
||||
new OptionTab("INPUT", null),
|
||||
new OptionTab("Input", GameImage.MENU_NAV_INPUT),
|
||||
new OptionTab("KEY MAPPING", new Option[]{
|
||||
OPTION_KEY_LEFT,
|
||||
OPTION_KEY_RIGHT,
|
||||
@@ -105,7 +107,7 @@ public class OptionGroups {
|
||||
OPTION_DISABLE_MOUSE_WHEEL,
|
||||
OPTION_DISABLE_MOUSE_BUTTONS,
|
||||
}),
|
||||
new OptionTab("CUSTOM", null),
|
||||
new OptionTab("Custom", GameImage.MENU_NAV_CUSTOM),
|
||||
new OptionTab("DIFFICULTY", new Option[]{
|
||||
OPTION_FIXED_CS,
|
||||
OPTION_FIXED_HP,
|
||||
@@ -116,7 +118,7 @@ public class OptionGroups {
|
||||
OPTION_CHECKPOINT,
|
||||
OPTION_REPLAY_SEEKING,
|
||||
}),
|
||||
new OptionTab("DANCE", null),
|
||||
new OptionTab("Dance", GameImage.MENU_NAV_DANCE),
|
||||
new OptionTab("MOVER", new Option[]{
|
||||
OPTION_DANCE_MOVER,
|
||||
OPTION_DANCE_EXGON_DELAY,
|
||||
@@ -143,7 +145,7 @@ public class OptionGroups {
|
||||
new OptionTab("MIRROR", new Option[] {
|
||||
OPTION_DANCE_MIRROR,
|
||||
}),
|
||||
new OptionTab("ADVANCED DISPLAY", null),
|
||||
new OptionTab("Advanced Display", GameImage.MENU_NAV_ADVANCED),
|
||||
new OptionTab("OBJECTS", new Option[]{
|
||||
OPTION_DANCE_DRAW_APPROACH,
|
||||
OPTION_DANCE_OBJECT_COLOR_OVERRIDE,
|
||||
@@ -163,7 +165,7 @@ public class OptionGroups {
|
||||
OPTION_DANCE_REMOVE_BG,
|
||||
OPTION_DANCE_ENABLE_SB,
|
||||
}),
|
||||
new OptionTab ("PIPPI", null),
|
||||
new OptionTab ("Pippi", GameImage.MENU_NAV_PIPPI),
|
||||
new OptionTab ("GENERAL", new Option[]{
|
||||
OPTION_PIPPI_ENABLE,
|
||||
OPTION_PIPPI_RADIUS_PERCENT,
|
||||
|
||||
@@ -17,15 +17,25 @@
|
||||
*/
|
||||
package yugecin.opsudance.options;
|
||||
|
||||
import itdelatrisu.opsu.GameImage;
|
||||
|
||||
public class OptionTab {
|
||||
|
||||
public final String name;
|
||||
public final Option[] options;
|
||||
public final GameImage icon;
|
||||
public boolean filtered;
|
||||
|
||||
public OptionTab(String name, GameImage icon) {
|
||||
this.name = name;
|
||||
this.icon = icon;
|
||||
this.options = null;
|
||||
}
|
||||
|
||||
public OptionTab(String name, Option[] options) {
|
||||
this.name = name;
|
||||
this.options = options;
|
||||
this.icon = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,118 +23,101 @@ import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.ui.Fonts;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.openal.SoundStore;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.*;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.movers.factories.ExgonMoverFactory;
|
||||
import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory;
|
||||
import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.utils.CachedVariable;
|
||||
import yugecin.opsudance.utils.CachedVariable.Getter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
|
||||
*/
|
||||
public class Options {
|
||||
|
||||
// TODO remove this?
|
||||
public static int width;
|
||||
public static int height;
|
||||
|
||||
static {
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
if (event.width > 0) {
|
||||
width = event.width;
|
||||
height = event.height;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// internal options (not displayed in-game)
|
||||
public static final Option OPTION_BEATMAP_DIRECTORY = new Option("BeatmapDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.BEATMAP_DIR.getAbsolutePath();
|
||||
}
|
||||
static {
|
||||
new Option("BeatmapDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.BEATMAP_DIR.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.beatmapDir = new File(s);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.beatmapDir = new File(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Option OPTION_OSZ_DIRECTORY = new Option("OSZDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.oszDir.getAbsolutePath();
|
||||
}
|
||||
new Option("OSZDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.oszDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.oszDir = new File(s);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.oszDir = new File(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Option OPTION_SCREENSHOT_DIRECTORY = new Option("ScreenshotDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.screenshotDir.getAbsolutePath();
|
||||
}
|
||||
new Option("ScreenshotDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.screenshotDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.screenshotDir = new File(s);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.screenshotDir = new File(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Option OPTION_REPLAY_DIRECTORY = new Option("ReplayDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.replayDir.getAbsolutePath();
|
||||
}
|
||||
new Option("ReplayDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.replayDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.replayDir = new File(s);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.replayDir = new File(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Option OPTION_REPLAY_IMPORT_DIRECTORY = new Option("ReplayImportDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.replayImportDir.getAbsolutePath();
|
||||
}
|
||||
new Option("ReplayImportDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.replayImportDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.replayImportDir = new File(s);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.replayImportDir = new File(s);
|
||||
}
|
||||
};
|
||||
|
||||
public static final Option OPTION_SKIN_DIRECTORY = new Option("SkinDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.skinRootDir.getAbsolutePath();
|
||||
}
|
||||
new Option("SkinDirectory") {
|
||||
@Override
|
||||
public String write() {
|
||||
return config.skinRootDir.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.skinRootDir = new File(s);
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void read(String s) {
|
||||
config.skinRootDir = new File(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final NumericOption OPTION_PORT = new NumericOption("-", "Port", "-", 49250, 1024, 65535) {
|
||||
@Override
|
||||
@@ -146,7 +129,7 @@ public class Options {
|
||||
public static final ToggleOption OPTION_NOSINGLEINSTANCE = new ToggleOption("-", "NoSingleInstance", "-", false);
|
||||
|
||||
// in-game options
|
||||
public static final Option OPTION_SCREEN_RESOLUTION = new ListOption("Screen Resolution", "ScreenResolution", "Change the size of the game.") {
|
||||
public static final ListOption OPTION_SCREEN_RESOLUTION = new ListOption("Screen Resolution", "ScreenResolution", "Change the size of the game.") {
|
||||
private final String[] resolutions = {
|
||||
null,
|
||||
"800x600",
|
||||
@@ -188,7 +171,6 @@ public class Options {
|
||||
|
||||
@Override
|
||||
public void read (String s){
|
||||
resolutions[0] = displayContainer.nativeDisplayMode.getWidth() + "x" + displayContainer.nativeDisplayMode.getHeight();
|
||||
try {
|
||||
idx = Integer.parseInt(s);
|
||||
} catch (Exception ignored) {
|
||||
@@ -205,37 +187,31 @@ public class Options {
|
||||
public static final ToggleOption OPTION_ALLOW_LARGER_RESOLUTIONS = new ToggleOption("Allow large resolutions", "AllowLargeRes", "Allow resolutions larger than the native resolution", false);
|
||||
public static final ToggleOption OPTION_FULLSCREEN = new ToggleOption("Fullscreen Mode", "Fullscreen", "Restart to apply changes.", false);
|
||||
public static final ListOption OPTION_SKIN = new ListOption("Skin", "Skin", "Change how the game looks.") {
|
||||
private CachedVariable<SkinService> skinService = new CachedVariable<>(new Getter<SkinService>() {
|
||||
@Override
|
||||
public SkinService get() {
|
||||
return instanceContainer.provide(SkinService.class);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public String getValueString () {
|
||||
return skinService.get().usedSkinName;
|
||||
return skinservice.usedSkinName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getListItems () {
|
||||
return skinService.get().availableSkinDirectories;
|
||||
return skinservice.availableSkinDirectories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clickListItem(int index){
|
||||
skinService.get().usedSkinName = skinService.get().availableSkinDirectories[index];
|
||||
skinService.get().reloadSkin();
|
||||
skinservice.usedSkinName = skinservice.availableSkinDirectories[index];
|
||||
skinservice.reloadSkin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read (String s){
|
||||
skinService.get().usedSkinName = s;
|
||||
skinservice.usedSkinName = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String write() {
|
||||
return skinService.get().usedSkinName;
|
||||
return skinservice.usedSkinName;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -418,7 +394,7 @@ public class Options {
|
||||
};
|
||||
|
||||
public static final ToggleOption OPTION_DISABLE_SOUNDS = new ToggleOption("Disable All Sound Effects", "DisableSound", "May resolve Linux sound driver issues. Requires a restart.", (System.getProperty("os.name").toLowerCase().contains("linux")));
|
||||
public static final GenericOption OPTION_KEY_LEFT = new GenericOption("Left Game Key", "keyOsuLeft", "Select this option to input a key.", Input.KEY_Z, null, false) {
|
||||
public static final GenericOption OPTION_KEY_LEFT = new GenericOption("Left Game Key", "keyOsuLeft", "Select this option to input a key.", Keyboard.KEY_Z, null, false) {
|
||||
@Override
|
||||
public String getValueString () {
|
||||
return Keyboard.getKeyName(intval);
|
||||
@@ -433,12 +409,12 @@ public class Options {
|
||||
public void read(String s){
|
||||
intval = Keyboard.getKeyIndex(s);
|
||||
if (intval == Keyboard.KEY_NONE) {
|
||||
intval = Input.KEY_Y;
|
||||
intval = Keyboard.KEY_Y;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static final GenericOption OPTION_KEY_RIGHT = new GenericOption("Right Game Key", "keyOsuRight", "Select this option to input a key.", Input.KEY_X, null, false) {
|
||||
public static final GenericOption OPTION_KEY_RIGHT = new GenericOption("Right Game Key", "keyOsuRight", "Select this option to input a key.", Keyboard.KEY_X, null, false) {
|
||||
@Override
|
||||
public String getValueString () {
|
||||
return Keyboard.getKeyName(intval);
|
||||
@@ -453,7 +429,7 @@ public class Options {
|
||||
public void read(String s){
|
||||
intval = Keyboard.getKeyIndex(s);
|
||||
if (intval == Keyboard.KEY_NONE) {
|
||||
intval = Input.KEY_X;
|
||||
intval = Keyboard.KEY_X;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -463,7 +439,8 @@ public class Options {
|
||||
public static final ToggleOption OPTION_DISABLE_MOUSE_BUTTONS = new ToggleOption("Disable mouse buttons in play mode", "MouseDisableButtons", "This option will disable all mouse buttons. Specifically for people who use their keyboard to click.", false) {
|
||||
@Override
|
||||
public void toggle() {
|
||||
EventBus.post(new BarNotificationEvent(state ? "Mouse buttons are disabled." : "Mouse buttons are enabled."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(state ?
|
||||
"Mouse buttons are disabled." : "Mouse buttons are enabled.");
|
||||
}
|
||||
};
|
||||
public static final ToggleOption OPTION_DISABLE_CURSOR = new ToggleOption("Disable Cursor", "DisableCursor", "Hide the cursor sprite.", false);
|
||||
@@ -503,7 +480,6 @@ public class Options {
|
||||
|
||||
public static final ToggleOption OPTION_SHOW_HIT_LIGHTING = new ToggleOption("Show Hit Lighting", "HitLighting", "Adds an effect behind hit explosions.", true);
|
||||
public static final ToggleOption OPTION_SHOW_HIT_ANIMATIONS = new ToggleOption("Show Hit Animations", "HitAnimations", "Fade out circles and curves.", true);
|
||||
public static final ToggleOption OPTION_SHOW_REVERSEARROW_ANIMATIONS = new ToggleOption("Show reverse arrow animations", "ReverseArrowAnimations", "Fade out reverse arrows after passing.", true);
|
||||
public static final ToggleOption OPTION_SHOW_COMBO_BURSTS = new ToggleOption("Show Combo Bursts", "ComboBurst", "A character image is displayed at combo milestones.", true);
|
||||
public static final ToggleOption OPTION_SHOW_PERFECT_HIT = new ToggleOption("Show Perfect Hits", "PerfectHit", "Whether to show perfect hit result bursts (300s, slider ticks).", true);
|
||||
public static final ToggleOption OPTION_SHOW_FOLLOW_POINTS = new ToggleOption("Show Follow Points", "FollowPoints", "Whether to show follow points between hit objects.", true);
|
||||
@@ -632,7 +608,7 @@ public class Options {
|
||||
public void clickListItem(int index){
|
||||
if (Game.isInGame && Dancer.moverFactories[index] instanceof PolyMoverFactory) {
|
||||
// TODO remove this when #79 is fixed
|
||||
EventBus.post(new BarNotificationEvent("This mover is disabled in the storyboard right now"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("This mover is disabled in the storyboard right now");
|
||||
return;
|
||||
}
|
||||
Dancer.instance.setMoverFactoryIndex(index);
|
||||
|
||||
@@ -17,39 +17,37 @@
|
||||
*/
|
||||
package yugecin.opsudance.options;
|
||||
|
||||
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.events.BubNotifListener;
|
||||
|
||||
import java.io.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
|
||||
* @author itdelatrisu (https://github.com/itdelatrisu)
|
||||
* most functions are copied from itdelatrisu.opsu.Options.java
|
||||
*/
|
||||
public class OptionsService {
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
public final HashMap<String, Option> optionMap;
|
||||
|
||||
public static final HashMap<String, Option> optionMap = new HashMap<>();
|
||||
|
||||
@Inject
|
||||
public OptionsService(InstanceContainer instanceContainer) {
|
||||
Option.setInstanceContainer(instanceContainer);
|
||||
public OptionsService() {
|
||||
optionMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public static void registerOption(Option option) {
|
||||
public void registerOption(Option option) {
|
||||
optionMap.put(option.configurationName, option);
|
||||
}
|
||||
|
||||
public void loadOptions() {
|
||||
// if no config file, use default settings
|
||||
if (!config.OPTIONS_FILE.isFile()) {
|
||||
config.loadDirectories();
|
||||
saveOptions();
|
||||
return;
|
||||
}
|
||||
@@ -82,7 +80,7 @@ public class OptionsService {
|
||||
} catch (IOException e) {
|
||||
String err = String.format("Failed to read option file '%s'.", config.OPTIONS_FILE.getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
config.loadDirectories();
|
||||
}
|
||||
@@ -111,7 +109,7 @@ public class OptionsService {
|
||||
} catch (IOException e) {
|
||||
String err = String.format("Failed to write to file '%s'.", config.OPTIONS_FILE.getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,33 +26,21 @@ import itdelatrisu.opsu.ui.Colors;
|
||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Image;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class GameObjectRenderer {
|
||||
|
||||
@Inject
|
||||
private DisplayContainer displayContainer;
|
||||
public GameData gameData;
|
||||
|
||||
private GameData gameData;
|
||||
|
||||
private float circleDiameter;
|
||||
private int circleDiameterInt;
|
||||
public float circleDiameter;
|
||||
public int circleDiameterInt;
|
||||
|
||||
private Image hitcircle;
|
||||
private Image hitcircleOverlay;
|
||||
private Image approachCircle;
|
||||
|
||||
@Deprecated
|
||||
public static GameObjectRenderer instance;
|
||||
|
||||
public GameObjectRenderer() {
|
||||
instance = this; // TODO get rid of this
|
||||
}
|
||||
|
||||
public void initForGame(GameData gameData, float circleDiameter) {
|
||||
this.gameData = gameData;
|
||||
this.circleDiameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480)
|
||||
@@ -65,14 +53,6 @@ public class GameObjectRenderer {
|
||||
approachCircle = GameImage.APPROACHCIRCLE.getImage();
|
||||
}
|
||||
|
||||
public float getCircleDiameter() {
|
||||
return circleDiameter;
|
||||
}
|
||||
|
||||
public void setGameData(GameData gameData) {
|
||||
this.gameData = gameData;
|
||||
}
|
||||
|
||||
public void initForFrame() {
|
||||
if (!OPTION_DANCING_CIRCLES.state) {
|
||||
return;
|
||||
|
||||
@@ -24,9 +24,8 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.state.OverlayOpsuState;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.sbv2.movers.CubicStoryboardMover;
|
||||
import yugecin.opsudance.sbv2.movers.LinearStoryboardMover;
|
||||
import yugecin.opsudance.sbv2.movers.QuadraticStoryboardMover;
|
||||
@@ -186,7 +185,7 @@ public class MoveStoryboard extends OverlayOpsuState{
|
||||
|
||||
private StoryboardMove getCurrentMoveOrCreateNew() {
|
||||
if (gameObjects[objectIndex].isSlider() && trackPosition > gameObjects[objectIndex].getTime() && trackPosition < gameObjects[objectIndex].getEndTime()) {
|
||||
EventBus.post(new BarNotificationEvent("Wait until the slider ended"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Wait until the slider ended");
|
||||
return dummyMove;
|
||||
}
|
||||
if (moves[objectIndex] == null) {
|
||||
|
||||
@@ -23,33 +23,24 @@ import itdelatrisu.opsu.skins.SkinLoader;
|
||||
import org.newdawn.slick.util.ClasspathLocation;
|
||||
import org.newdawn.slick.util.FileSystemLocation;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.SkinChangedListener;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
/**
|
||||
* @author itdelatrisu (https://github.com/itdelatrisu) most functions are copied from itdelatrisu.opsu.Options.java
|
||||
*/
|
||||
public class SkinService {
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
public String[] availableSkinDirectories;
|
||||
public String usedSkinName = "Default";
|
||||
public static Skin skin;
|
||||
|
||||
@Inject
|
||||
public SkinService() {
|
||||
}
|
||||
|
||||
public void reloadSkin() {
|
||||
loadSkin();
|
||||
SoundController.init();
|
||||
EventBus.post(new ResolutionOrSkinChangedEvent(usedSkinName, -1, -1));
|
||||
SkinChangedListener.EVENT.make().onSkinChanged(usedSkinName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package yugecin.opsudance.spinners;
|
||||
|
||||
import yugecin.opsudance.options.Options;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class ApproachCircleSpinner extends Spinner {
|
||||
|
||||
@@ -38,10 +38,10 @@ public class ApproachCircleSpinner extends Spinner {
|
||||
ang += 15;
|
||||
}
|
||||
|
||||
double rad = Options.width / 4.0f * (1d - Spinner.PROGRESS);
|
||||
double rad = displayContainer.width / 4.0f * (1d - Spinner.PROGRESS);
|
||||
|
||||
point[0] = Options.width / 2.0f + rad * Math.sin(ang / 180d * Math.PI);
|
||||
point[1] = Options.height / 2.0f - rad * Math.cos(ang / 180d * Math.PI);
|
||||
point[0] = displayContainer.width / 2.0f + rad * Math.sin(ang / 180d * Math.PI);
|
||||
point[1] = displayContainer.height / 2.0f - rad * Math.cos(ang / 180d * Math.PI);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package yugecin.opsudance.spinners;
|
||||
|
||||
import yugecin.opsudance.options.Options;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class BeamSpinner extends Spinner {
|
||||
|
||||
@@ -26,16 +26,14 @@ public class BeamSpinner extends Spinner {
|
||||
private int index;
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
public void init() {
|
||||
ang = 0;
|
||||
index = 0;
|
||||
point = new double[2];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getPoint()
|
||||
{
|
||||
public double[] getPoint() {
|
||||
if (!waitForDelay()) {
|
||||
return point;
|
||||
}
|
||||
@@ -43,26 +41,19 @@ public class BeamSpinner extends Spinner {
|
||||
index = ++index % 4;
|
||||
final int MOD = 60;
|
||||
|
||||
point[0] = Options.width / 2d;
|
||||
point[1] = Options.height / 2d;
|
||||
point[0] = displayContainer.width / 2d;
|
||||
point[1] = displayContainer.height / 2d;
|
||||
|
||||
if( index == 0 )
|
||||
{
|
||||
if( index == 0 ) {
|
||||
add( MOD, 90 );
|
||||
add( MOD, 180 );
|
||||
}
|
||||
else if( index == 1 )
|
||||
{
|
||||
} else if( index == 1 ) {
|
||||
add( MOD, 90 );
|
||||
add( Options.height / 2 * 0.8d, 0 );
|
||||
}
|
||||
else if( index == 2 )
|
||||
{
|
||||
add( displayContainer.height / 2 * 0.8d, 0 );
|
||||
} else if( index == 2 ) {
|
||||
add( MOD, -90 );
|
||||
add( Options.height / 2 * 0.8d, 0 );
|
||||
}
|
||||
else if( index == 3 )
|
||||
{
|
||||
add( displayContainer.height / 2 * 0.8d, 0 );
|
||||
} else if( index == 3 ) {
|
||||
add( MOD, -90 );
|
||||
add( MOD, 180 );
|
||||
ang += 0.3;
|
||||
@@ -71,8 +62,7 @@ public class BeamSpinner extends Spinner {
|
||||
return point;
|
||||
}
|
||||
|
||||
private void add( double rad, double ang )
|
||||
{
|
||||
private void add( double rad, double ang ) {
|
||||
point[0] += rad * Math.cos( (this.ang + ang) / 180d * Math.PI);
|
||||
point[1] -= rad * Math.sin( (this.ang + ang) / 180d * Math.PI);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package yugecin.opsudance.spinners;
|
||||
|
||||
import yugecin.opsudance.options.Options;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class CircleSpinner extends Spinner {
|
||||
|
||||
@@ -26,22 +26,20 @@ public class CircleSpinner extends Spinner {
|
||||
private double[] point = new double[2];
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
public void init() {
|
||||
ang = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getPoint()
|
||||
{
|
||||
public double[] getPoint() {
|
||||
if (waitForDelay()) {
|
||||
ang += 15;
|
||||
}
|
||||
|
||||
double rad = Options.width / 4.0f;
|
||||
double rad = displayContainer.width / 4.0f;
|
||||
|
||||
point[0] = Options.width / 2.0f + rad * Math.sin(ang / 180d * Math.PI);
|
||||
point[1] = Options.height / 2.0f - rad * Math.cos(ang / 180d * Math.PI);
|
||||
point[0] = displayContainer.width / 2.0f + rad * Math.sin(ang / 180d * Math.PI);
|
||||
point[1] = displayContainer.height / 2.0f - rad * Math.cos(ang / 180d * Math.PI);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package yugecin.opsudance.spinners;
|
||||
|
||||
import yugecin.opsudance.options.Options;
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
public class CubeSpinner extends Spinner {
|
||||
|
||||
@@ -90,10 +90,10 @@ public class CubeSpinner extends Spinner {
|
||||
x *= 3.0d / ( z + 3.0d + 5.0d + 0.5 );
|
||||
y *= 3.0d / ( z + 3.0d + 5.0d + 0.5 );
|
||||
|
||||
double scale = Options.width / (3.0f + 0.5f * Math.cos(size / 180f * Math.PI));
|
||||
double scale = displayContainer.width / (3.0f + 0.5f * Math.cos(size / 180f * Math.PI));
|
||||
//double scale = Options.width / (3.0f + -1f * ((float)(Options.s.ElapsedMilliseconds % Options.beatTimeMs)/(float)Options.beatTimeMs));
|
||||
point[0] = (int) ( Options.width / 2.0f + scale * x );
|
||||
point[1] = (int) ( Options.height / 2.0f - scale * y );
|
||||
point[0] = (int) ( displayContainer.width / 2.0f + scale * x );
|
||||
point[1] = (int) ( displayContainer.height / 2.0f - scale * y );
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package yugecin.opsudance.spinners;
|
||||
|
||||
import yugecin.opsudance.options.Options;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class DonutSpinner extends Spinner {
|
||||
|
||||
@@ -38,10 +38,10 @@ public class DonutSpinner extends Spinner {
|
||||
ang += 15;
|
||||
}
|
||||
|
||||
double rad = Options.width / 4.0f;
|
||||
double rad = displayContainer.width / 4.0f;
|
||||
|
||||
point[0] = Options.width / 2.0f + rad * Math.sin(ang);
|
||||
point[1] = Options.height / 2.0f - rad * Math.cos(ang);
|
||||
point[0] = displayContainer.width / 2.0f + rad * Math.sin(ang);
|
||||
point[1] = displayContainer.height / 2.0f - rad * Math.cos(ang);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
package yugecin.opsudance.spinners;
|
||||
|
||||
import yugecin.opsudance.options.Options;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class FivePointStarApproachSpinner extends Spinner {
|
||||
|
||||
@@ -39,12 +39,12 @@ public class FivePointStarApproachSpinner extends Spinner {
|
||||
odd = !odd;
|
||||
}
|
||||
|
||||
double rad = Options.width / 4.0f * (1d - Spinner.PROGRESS);
|
||||
double rad = displayContainer.width / 4.0f * (1d - Spinner.PROGRESS);
|
||||
if (!odd) {
|
||||
rad /= 3d;
|
||||
}
|
||||
point[0] = Options.width / 2d + Math.cos(ang) * rad;
|
||||
point[1] = Options.height / 2d + Math.sin(ang) * rad;
|
||||
point[0] = displayContainer.width / 2d + Math.cos(ang) * rad;
|
||||
point[1] = displayContainer.height / 2d + Math.sin(ang) * rad;
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user