diff --git a/.gitignore b/.gitignore index 6348415d..a0d778b0 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,8 @@ build/ Thumbs.db -/target \ No newline at end of file +.DS_STORE +/target +/out/ +/lib/ +/mvnlibs/ diff --git a/CREDITS.md b/CREDITS.md index 6cee6517..d528d86e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -20,6 +20,7 @@ The images included in opsu! belong to their respective authors. * sherrie__fay * kouyang * teinecthel +* Font Awesome by Dave Gandy - http://fontawesome.io Projects -------- @@ -31,6 +32,5 @@ The following projects were referenced in creating opsu!: Theme Song ---------- -Rainbows - Kevin MacLeod (incompetech.com) -Licensed under Creative Commons: By Attribution 3.0 License -http://creativecommons.org/licenses/by/3.0/ +The theme song is "On the Bach" by Jingle Punks, from the [YouTube Audio Library] +(https://www.youtube.com/audiolibrary/music). diff --git a/README.md b/README.md index 18de2c1b..b16118d5 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,69 @@ # opsu!dance -[example video](https://www.youtube.com/watch?v=tqZqn7nx8N0) - -Originally started as a fork of [opsu!](https://github.com/itdelatrisu/opsu) with cursordance stuff. I made a cursordancing bot in C# for osu!, and by adding it into this clone, it allows me to do even more stuff with it. This way I can also provide this client to other players so they can play with it too, as I will not give my bot to people because I don't want to endorse cheating in any way. + +**Table of contents** + +* [What](#What) - [Why](#why) - [Downloads](#downloads) - [Running](#running) - [Building a JAR](#building-a-jar) - [Credits](#credits) - [License](#license) + +What +---- +Fork of [opsu!](https://github.com/itdelatrisu/opsu), which is a clone of the [osu!](https://osu.ppy.sh/) rythm game. + +* [example video: Cursor Dance | MOMOIRO CLOVER Z - SANTA SAN](https://youtu.be/tqZqn7nx8N0) +* [example video: osu! 50 top replays | Getty vs. DJ DiA - Fox4-Raize- [Extreme]](https://youtu.be/T2AiGn2xOQo) As of 2017 some major changes were made in this fork which changed the inner workings of opsu. This was done in an attempt to get more control over the base system and allowed a.o. changing resolution and skin at runtime without the need to restart the whole system. This fork was pretty even to opsu! before this change, but now there are way more differences. -My goal is to to add cool cursordancing things to this fork, but also make it possible to play the normal way. - -### Downloads -Click on the releases link (scroll up) to go to the downloadpage with prebuilt jars. +Why +--- +I made a cursordancing bot in C# for osu!, and by adding it into this clone, it allows me to do even more stuff with it. This way I can also provide this client to other players so they can play with it too, as I will not give my bot to people because I don't want to endorse cheating in any way. -### Building -You can find general (run/build) instructions in the original [opsu! README](README-OPSU.md). -Please note that I am only using maven, gradle scripts are not being updated. +My goal is to to add cool cursordancing things to this fork, but also make it possible to play the normal way. In the meantime I'm also adding various improvements to opsu! while I make a mess here, like the option menu, default back button, slider stuff, ... -### Credits -opsu! was made by Jeffrey Han ([@itdelatrisu](https://github.com/itdelatrisu)). All game concepts and designs are based on work by osu! developer Dean Herbert. Other opsu! credits can be found [here](CREDITS.md). -opsu!dance (everything in the src package yugecin.opsudance) was made by me ([@yugecin](https://github.com/yugecin)). Edits were made in the opsu! sources, too. +Downloads +--------- +You can find prebuilt jars on [the releases page](https://github.com/yugecin/opsu-dance/releases). -### License +Running +------- + +If you don't need to edit the source, just download a jar from [the releases page](https://github.com/yugecin/opsu-dance/releases). + +Using an IDE is recommended because it is usually faster than the other options and provides debugging. + +### Using your favorite IDE +You should know how to do this. It's recommended to use a working directory like `out` to not pollute the project directory with config/db files. + +### Using apache maven +`mvn compile` + +### Using apache ant + +Resolve dependencies first, use either: + +* `ant ivyresolve` to download dependencies using apache ivy +* `ant mvnresolve` to download dependencies using apache mvn + +Then do `ant run` + +Building a JAR +-------------- + +Using ant is recommended. Ant is used since release 0.5.0 + +### Using apache maven +`mvn package -Djar`, find it in the `target` folder. + +### Using apache ant +`ant jar`, find it in the `bin` folder + + +Credits +------- +opsu! was made by Jeffrey Han ([@itdelatrisu](https://github.com/itdelatrisu)). All game concepts and designs are based on work by osu! developer Dean Herbert. Other opsu! credits can be found [here](CREDITS.md). + +opsu!dance (everything in the src package yugecin.opsudance) was made by me ([@yugecin](https://github.com/yugecin)). Lots of edits were made in the opsu! sources, too. + +License +------- **This software is licensed under GNU GPL version 3.** -You can find the full text of the license [here](LICENSE). +You can find the full text of the license in [the LICENSE file](LICENSE). diff --git a/build.xml b/build.xml new file mode 100644 index 00000000..b24b89de --- /dev/null +++ b/build.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + +ant clean --> clean the ant working dir +ant cleanlib --> clean the lib folder +ant ivyresolve --> resolve dependencies using ivy +ant mvnresolve --> resolve dependencies using mvn +ant compile --> compile the code +ant run --> prepare to run and run +ant jar --> package a jar + +resolve dependencies first +(using either mvnresolve or ivyresolve), +then run (code is compiled automatically when you run) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ivy.xml b/ivy.xml new file mode 100644 index 00000000..1573a486 --- /dev/null +++ b/ivy.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8062f357..9a19f00a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,14 @@ - + + 4.0.0 yugecin opsu-dance 0.5.0-SNAPSHOT + UTF-8 ${project.version} ${maven.build.timestamp} yyyy-MM-dd HH:mm @@ -20,6 +24,7 @@ **/Thumbs.db **/version + **.pdn @@ -31,13 +36,40 @@ + + org.apache.maven.plugins + maven-clean-plugin + 2.4.1 + + + + ${project.basedir}/mvnlibs + true + + + + + + maven-dependency-plugin + + + initialize + + copy-dependencies + + + ${project.basedir}/mvnlibs + + + + org.apache.maven.plugins maven-compiler-plugin 3.2 - 1.7 - 1.7 + 1.8 + 1.8 UTF-8 @@ -74,6 +106,7 @@ ${mainClassName} + ${project.build.outputDirectory}/../ @@ -92,18 +125,32 @@ org/newdawn/slick/Music.* org/newdawn/slick/Input.* org/newdawn/slick/Input$NullOutputStream.* + org/newdawn/slick/MouseListener.* + org/newdawn/slick/KeyListener.* + org/newdawn/slick/InputListener.* org/newdawn/slick/gui/TextField.* org/newdawn/slick/openal/AudioInputStream* org/newdawn/slick/openal/OpenALStreamPlayer* org/newdawn/slick/openal/SoundStore* + + + *:sqlite-jdbc + + **/*.java + **/*.c + + ${mainClassName} ${XDG} + OpenAL32.dll,OpenAL64.dll,lwjgl.dll,lwjgl64.dll + liblwjgl.so,liblwjgl64.so,libopenal.so,libopenal64.so + liblwjgl.dylib,openal.dylib @@ -142,6 +189,10 @@ org.lwjgl.lwjgl lwjgl + + javax.jnlp + jnlp-api + @@ -154,20 +205,16 @@ zip4j 1.3.2 - - com.googlecode.soundlibs - jlayer - 1.0.1-1 - com.googlecode.soundlibs mp3spi - 1.9.5-1 - - - com.googlecode.soundlibs - tritonus-share - 0.3.7-2 + 1.9.5.4 + + + junit + junit + + org.xerial @@ -209,10 +256,11 @@ lzma-java 1.3 - - gov.nist.math - jama - 1.0.3 - + + gov.nist.math + jama + 1.0.3 + + \ No newline at end of file diff --git a/res/menu-nav-advanced.png b/res/menu-nav-advanced.png new file mode 100644 index 00000000..22479e9b Binary files /dev/null and b/res/menu-nav-advanced.png differ diff --git a/res/menu-nav-audio.png b/res/menu-nav-audio.png new file mode 100644 index 00000000..b8881e70 Binary files /dev/null and b/res/menu-nav-audio.png differ diff --git a/res/menu-nav-custom.png b/res/menu-nav-custom.png new file mode 100644 index 00000000..a830bba3 Binary files /dev/null and b/res/menu-nav-custom.png differ diff --git a/res/menu-nav-dance.png b/res/menu-nav-dance.png new file mode 100644 index 00000000..21d50cf8 Binary files /dev/null and b/res/menu-nav-dance.png differ diff --git a/res/menu-nav-gameplay.png b/res/menu-nav-gameplay.png new file mode 100644 index 00000000..c81d92d5 Binary files /dev/null and b/res/menu-nav-gameplay.png differ diff --git a/res/menu-nav-general.png b/res/menu-nav-general.png new file mode 100644 index 00000000..bd42c489 Binary files /dev/null and b/res/menu-nav-general.png differ diff --git a/res/menu-nav-graphics.png b/res/menu-nav-graphics.png new file mode 100644 index 00000000..76cdfe6b Binary files /dev/null and b/res/menu-nav-graphics.png differ diff --git a/res/menu-nav-input.png b/res/menu-nav-input.png new file mode 100644 index 00000000..2347d907 Binary files /dev/null and b/res/menu-nav-input.png differ diff --git a/res/menu-nav-pippi.png b/res/menu-nav-pippi.png new file mode 100644 index 00000000..949789c3 Binary files /dev/null and b/res/menu-nav-pippi.png differ diff --git a/res/menu-nav-skin.png b/res/menu-nav-skin.png new file mode 100644 index 00000000..0fed5cc1 Binary files /dev/null and b/res/menu-nav-skin.png differ diff --git a/res/theme.mp3 b/res/theme.mp3 deleted file mode 100644 index b75ad2bf..00000000 Binary files a/res/theme.mp3 and /dev/null differ diff --git a/res/theme.ogg b/res/theme.ogg new file mode 100644 index 00000000..8057f70d Binary files /dev/null and b/res/theme.ogg differ diff --git a/src/awlex/ospu/FakeGameObject.java b/src/awlex/ospu/FakeGameObject.java index bcb5c8a0..9781285d 100644 --- a/src/awlex/ospu/FakeGameObject.java +++ b/src/awlex/ospu/FakeGameObject.java @@ -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) { diff --git a/src/awlex/ospu/movers/CombinedSpiralMover.java b/src/awlex/ospu/movers/CombinedSpiralMover.java index d0406e15..04729047 100644 --- a/src/awlex/ospu/movers/CombinedSpiralMover.java +++ b/src/awlex/ospu/movers/CombinedSpiralMover.java @@ -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; } } diff --git a/src/awlex/ospu/movers/factories/SpiralMoverFactory.java b/src/awlex/ospu/movers/factories/SpiralMoverFactory.java index b2ce532f..f24a527c 100644 --- a/src/awlex/ospu/movers/factories/SpiralMoverFactory.java +++ b/src/awlex/ospu/movers/factories/SpiralMoverFactory.java @@ -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 diff --git a/src/awlex/ospu/spinners/SpiralSpinner.java b/src/awlex/ospu/spinners/SpiralSpinner.java index aa4fb3a5..50fa9295 100644 --- a/src/awlex/ospu/spinners/SpiralSpinner.java +++ b/src/awlex/ospu/spinners/SpiralSpinner.java @@ -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)); } diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 2f5b3b01..5e72fdd5 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -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 diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 4281003f..68002fc5 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -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 list = new ArrayList(); - 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 list = new ArrayList(); + 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); } } diff --git a/src/itdelatrisu/opsu/GameMod.java b/src/itdelatrisu/opsu/GameMod.java index 60c7c492..8449db60 100644 --- a/src/itdelatrisu/opsu/GameMod.java +++ b/src/itdelatrisu/opsu/GameMod.java @@ -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. */ diff --git a/src/itdelatrisu/opsu/NativeLoader.java b/src/itdelatrisu/opsu/NativeLoader.java index 4f6853ca..840fc9b5 100644 --- a/src/itdelatrisu/opsu/NativeLoader.java +++ b/src/itdelatrisu/opsu/NativeLoader.java @@ -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 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; } + } \ No newline at end of file diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index ff2648db..cbebead9 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -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(); + } + } diff --git a/src/itdelatrisu/opsu/audio/MultiClip.java b/src/itdelatrisu/opsu/audio/MultiClip.java index d314815f..e22cd4cf 100644 --- a/src/itdelatrisu/opsu/audio/MultiClip.java +++ b/src/itdelatrisu/opsu/audio/MultiClip.java @@ -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); } } } diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index d30cea6f..eee4135a 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -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); } } diff --git a/src/itdelatrisu/opsu/audio/SoundController.java b/src/itdelatrisu/opsu/audio/SoundController.java index b32162a6..659b9fbb 100644 --- a/src/itdelatrisu/opsu/audio/SoundController.java +++ b/src/itdelatrisu/opsu/audio/SoundController.java @@ -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 { diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java index 19e8f54f..7550d0af 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java @@ -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 stringdb = new HashMap(); @@ -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); + } + } \ No newline at end of file diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java index 334b5b06..1cb1d72c 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java @@ -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(); diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java index 86313d3d..b49acd37 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java @@ -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. diff --git a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java index c6f3491f..05e7182a 100644 --- a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java +++ b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java @@ -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); } } diff --git a/src/itdelatrisu/opsu/db/BeatmapDB.java b/src/itdelatrisu/opsu/db/BeatmapDB.java index 20f7037f..745271db 100644 --- a/src/itdelatrisu/opsu/db/BeatmapDB.java +++ b/src/itdelatrisu/opsu/db/BeatmapDB.java @@ -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); } } } diff --git a/src/itdelatrisu/opsu/db/DBController.java b/src/itdelatrisu/opsu/db/DBController.java index d6223a9e..87ecfbec 100644 --- a/src/itdelatrisu/opsu/db/DBController.java +++ b/src/itdelatrisu/opsu/db/DBController.java @@ -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; } } diff --git a/src/itdelatrisu/opsu/db/ScoreDB.java b/src/itdelatrisu/opsu/db/ScoreDB.java index a195a87d..1736e9ef 100644 --- a/src/itdelatrisu/opsu/db/ScoreDB.java +++ b/src/itdelatrisu/opsu/db/ScoreDB.java @@ -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); } } } diff --git a/src/itdelatrisu/opsu/downloads/Download.java b/src/itdelatrisu/opsu/downloads/Download.java index 378fda08..1b65d5d3 100644 --- a/src/itdelatrisu/opsu/downloads/Download.java +++ b/src/itdelatrisu/opsu/downloads/Download.java @@ -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); } } } diff --git a/src/itdelatrisu/opsu/downloads/DownloadNode.java b/src/itdelatrisu/opsu/downloads/DownloadNode.java index d632a29b..e5625306 100644 --- a/src/itdelatrisu/opsu/downloads/DownloadNode.java +++ b/src/itdelatrisu/opsu/downloads/DownloadNode.java @@ -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; } diff --git a/src/itdelatrisu/opsu/downloads/Updater.java b/src/itdelatrisu/opsu/downloads/Updater.java index 96ff228d..f0d95efd 100644 --- a/src/itdelatrisu/opsu/downloads/Updater.java +++ b/src/itdelatrisu/opsu/downloads/Updater.java @@ -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); } } } diff --git a/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java b/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java index 641360c6..628cd417 100644 --- a/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java @@ -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; } diff --git a/src/itdelatrisu/opsu/downloads/servers/HexideServer.java b/src/itdelatrisu/opsu/downloads/servers/HexideServer.java index a4661510..9b504f04 100644 --- a/src/itdelatrisu/opsu/downloads/servers/HexideServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/HexideServer.java @@ -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; } diff --git a/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java b/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java index 907b2fda..ff615f6c 100644 --- a/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java @@ -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; } diff --git a/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java b/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java index e851a35d..75e497c6 100644 --- a/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java @@ -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; } diff --git a/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java b/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java index 98d3fef1..7ba31aec 100644 --- a/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java @@ -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 idTable = new HashMap(); - @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; } diff --git a/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java b/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java index 2ba683b6..d732ed87 100644 --- a/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java @@ -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); } diff --git a/src/itdelatrisu/opsu/objects/Circle.java b/src/itdelatrisu/opsu/objects/Circle.java index 66f05181..729e095c 100644 --- a/src/itdelatrisu/opsu/objects/Circle.java +++ b/src/itdelatrisu/opsu/objects/Circle.java @@ -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); diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index a55efb6d..eca527e4 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -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(); diff --git a/src/itdelatrisu/opsu/render/CurveRenderState.java b/src/itdelatrisu/opsu/render/CurveRenderState.java index c6f06308..ebf365e3 100644 --- a/src/itdelatrisu/opsu/render/CurveRenderState.java +++ b/src/itdelatrisu/opsu/render/CurveRenderState.java @@ -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 { diff --git a/src/itdelatrisu/opsu/replay/Replay.java b/src/itdelatrisu/opsu/replay/Replay.java index 825d60c0..9296f55e 100644 --- a/src/itdelatrisu/opsu/replay/Replay.java +++ b/src/itdelatrisu/opsu/replay/Replay.java @@ -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(); diff --git a/src/itdelatrisu/opsu/replay/ReplayImporter.java b/src/itdelatrisu/opsu/replay/ReplayImporter.java index 120c564f..84b0a44e 100644 --- a/src/itdelatrisu/opsu/replay/ReplayImporter.java +++ b/src/itdelatrisu/opsu/replay/ReplayImporter.java @@ -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); } } diff --git a/src/itdelatrisu/opsu/skins/SkinLoader.java b/src/itdelatrisu/opsu/skins/SkinLoader.java index 69781404..799a2da2 100644 --- a/src/itdelatrisu/opsu/skins/SkinLoader.java +++ b/src/itdelatrisu/opsu/skins/SkinLoader.java @@ -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; diff --git a/src/itdelatrisu/opsu/states/ButtonMenu.java b/src/itdelatrisu/opsu/states/ButtonMenu.java index 77cfc95d..acc66611 100644 --- a/src/itdelatrisu/opsu/states/ButtonMenu.java +++ b/src/itdelatrisu/opsu/states/ButtonMenu.java @@ -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. *

@@ -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; } diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index 4003f7f0..23fe14b8 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -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; } } diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index c951e95f..9227ff26 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -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; diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java index 0c8bb9bd..dc92a060 100644 --- a/src/itdelatrisu/opsu/states/GamePauseMenu.java +++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java @@ -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; } diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index 17383502..eb069a0e 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -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 } diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 0411ba5d..c711e05b 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -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 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); } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 12a23d85..3bb48625 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -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(); - 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(); + 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); } } diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java index 71a7703c..eba0f109 100644 --- a/src/itdelatrisu/opsu/states/Splash.java +++ b/src/itdelatrisu/opsu/states/Splash.java @@ -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) { diff --git a/src/itdelatrisu/opsu/ui/Colors.java b/src/itdelatrisu/opsu/ui/Colors.java index 3b133d9c..cd17f0fd 100644 --- a/src/itdelatrisu/opsu/ui/Colors.java +++ b/src/itdelatrisu/opsu/ui/Colors.java @@ -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. diff --git a/src/itdelatrisu/opsu/ui/DropdownMenu.java b/src/itdelatrisu/opsu/ui/DropdownMenu.java index 474e36ae..ec56dfd4 100644 --- a/src/itdelatrisu/opsu/ui/DropdownMenu.java +++ b/src/itdelatrisu/opsu/ui/DropdownMenu.java @@ -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 extends Component { @Override public void keyPressed(int key, char c) { - if (key == Input.KEY_ESCAPE) { + if (key == Keyboard.KEY_ESCAPE) { this.expanded = false; } } diff --git a/src/itdelatrisu/opsu/ui/Fonts.java b/src/itdelatrisu/opsu/ui/Fonts.java index a11831d6..78b9439f 100644 --- a/src/itdelatrisu/opsu/ui/Fonts.java +++ b/src/itdelatrisu/opsu/ui/Fonts.java @@ -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)); diff --git a/src/itdelatrisu/opsu/ui/KineticScrolling.java b/src/itdelatrisu/opsu/ui/KineticScrolling.java index b373d893..da39c534 100644 --- a/src/itdelatrisu/opsu/ui/KineticScrolling.java +++ b/src/itdelatrisu/opsu/ui/KineticScrolling.java @@ -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; diff --git a/src/org/newdawn/slick/Input.java b/src/org/newdawn/slick/Input.java index 64ece8de..b340588b 100644 --- a/src/org/newdawn/slick/Input.java +++ b/src/org/newdawn/slick/Input.java @@ -28,283 +28,24 @@ package org.newdawn.slick; -import java.io.IOException; -import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import org.lwjgl.LWJGLException; -import org.lwjgl.input.Controller; -import org.lwjgl.input.Controllers; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.Display; -import org.newdawn.slick.util.Log; + +import static org.lwjgl.input.Keyboard.*; /** * A wrapped for all keyboard, mouse and controller input + * Edited for opsu! * * @author kevin */ @SuppressWarnings({"rawtypes", "unchecked", "unused"}) public class Input { - /** The controller index to pass to check all controllers */ - public static final int ANY_CONTROLLER = -1; - - /** The maximum number of buttons on controllers */ - private static final int MAX_BUTTONS = 100; - - /** */ - public static final int KEY_ESCAPE = 0x01; - /** */ - public static final int KEY_1 = 0x02; - /** */ - public static final int KEY_2 = 0x03; - /** */ - public static final int KEY_3 = 0x04; - /** */ - public static final int KEY_4 = 0x05; - /** */ - public static final int KEY_5 = 0x06; - /** */ - public static final int KEY_6 = 0x07; - /** */ - public static final int KEY_7 = 0x08; - /** */ - public static final int KEY_8 = 0x09; - /** */ - public static final int KEY_9 = 0x0A; - /** */ - public static final int KEY_0 = 0x0B; - /** */ - public static final int KEY_MINUS = 0x0C; /* - on main keyboard */ - /** */ - public static final int KEY_EQUALS = 0x0D; - /** */ - public static final int KEY_BACK = 0x0E; /* backspace */ - /** */ - public static final int KEY_TAB = 0x0F; - /** */ - public static final int KEY_Q = 0x10; - /** */ - public static final int KEY_W = 0x11; - /** */ - public static final int KEY_E = 0x12; - /** */ - public static final int KEY_R = 0x13; - /** */ - public static final int KEY_T = 0x14; - /** */ - public static final int KEY_Y = 0x15; - /** */ - public static final int KEY_U = 0x16; - /** */ - public static final int KEY_I = 0x17; - /** */ - public static final int KEY_O = 0x18; - /** */ - public static final int KEY_P = 0x19; - /** */ - public static final int KEY_LBRACKET = 0x1A; - /** */ - public static final int KEY_RBRACKET = 0x1B; - /** */ - public static final int KEY_RETURN = 0x1C; /* Enter on main keyboard */ - /** */ - public static final int KEY_ENTER = 0x1C; /* Enter on main keyboard */ - /** */ - public static final int KEY_LCONTROL = 0x1D; - /** */ - public static final int KEY_A = 0x1E; - /** */ - public static final int KEY_S = 0x1F; - /** */ - public static final int KEY_D = 0x20; - /** */ - public static final int KEY_F = 0x21; - /** */ - public static final int KEY_G = 0x22; - /** */ - public static final int KEY_H = 0x23; - /** */ - public static final int KEY_J = 0x24; - /** */ - public static final int KEY_K = 0x25; - /** */ - public static final int KEY_L = 0x26; - /** */ - public static final int KEY_SEMICOLON = 0x27; - /** */ - public static final int KEY_APOSTROPHE = 0x28; - /** */ - public static final int KEY_GRAVE = 0x29; /* accent grave */ - /** */ - public static final int KEY_LSHIFT = 0x2A; - /** */ - public static final int KEY_BACKSLASH = 0x2B; - /** */ - public static final int KEY_Z = 0x2C; - /** */ - public static final int KEY_X = 0x2D; - /** */ - public static final int KEY_C = 0x2E; - /** */ - public static final int KEY_V = 0x2F; - /** */ - public static final int KEY_B = 0x30; - /** */ - public static final int KEY_N = 0x31; - /** */ - public static final int KEY_M = 0x32; - /** */ - public static final int KEY_COMMA = 0x33; - /** */ - public static final int KEY_PERIOD = 0x34; /* . on main keyboard */ - /** */ - public static final int KEY_SLASH = 0x35; /* / on main keyboard */ - /** */ - public static final int KEY_RSHIFT = 0x36; - /** */ - public static final int KEY_MULTIPLY = 0x37; /* * on numeric keypad */ - /** */ - public static final int KEY_LMENU = 0x38; /* left Alt */ - /** */ - public static final int KEY_SPACE = 0x39; - /** */ - public static final int KEY_CAPITAL = 0x3A; - /** */ - public static final int KEY_F1 = 0x3B; - /** */ - public static final int KEY_F2 = 0x3C; - /** */ - public static final int KEY_F3 = 0x3D; - /** */ - public static final int KEY_F4 = 0x3E; - /** */ - public static final int KEY_F5 = 0x3F; - /** */ - public static final int KEY_F6 = 0x40; - /** */ - public static final int KEY_F7 = 0x41; - /** */ - public static final int KEY_F8 = 0x42; - /** */ - public static final int KEY_F9 = 0x43; - /** */ - public static final int KEY_F10 = 0x44; - /** */ - public static final int KEY_NUMLOCK = 0x45; - /** */ - public static final int KEY_SCROLL = 0x46; /* Scroll Lock */ - /** */ - public static final int KEY_NUMPAD7 = 0x47; - /** */ - public static final int KEY_NUMPAD8 = 0x48; - /** */ - public static final int KEY_NUMPAD9 = 0x49; - /** */ - public static final int KEY_SUBTRACT = 0x4A; /* - on numeric keypad */ - /** */ - public static final int KEY_NUMPAD4 = 0x4B; - /** */ - public static final int KEY_NUMPAD5 = 0x4C; - /** */ - public static final int KEY_NUMPAD6 = 0x4D; - /** */ - public static final int KEY_ADD = 0x4E; /* + on numeric keypad */ - /** */ - public static final int KEY_NUMPAD1 = 0x4F; - /** */ - public static final int KEY_NUMPAD2 = 0x50; - /** */ - public static final int KEY_NUMPAD3 = 0x51; - /** */ - public static final int KEY_NUMPAD0 = 0x52; - /** */ - public static final int KEY_DECIMAL = 0x53; /* . on numeric keypad */ - /** */ - public static final int KEY_F11 = 0x57; - /** */ - public static final int KEY_F12 = 0x58; - /** */ - public static final int KEY_F13 = 0x64; /* (NEC PC98) */ - /** */ - public static final int KEY_F14 = 0x65; /* (NEC PC98) */ - /** */ - public static final int KEY_F15 = 0x66; /* (NEC PC98) */ - /** */ - public static final int KEY_KANA = 0x70; /* (Japanese keyboard) */ - /** */ - public static final int KEY_CONVERT = 0x79; /* (Japanese keyboard) */ - /** */ - public static final int KEY_NOCONVERT = 0x7B; /* (Japanese keyboard) */ - /** */ - public static final int KEY_YEN = 0x7D; /* (Japanese keyboard) */ - /** */ - public static final int KEY_NUMPADEQUALS = 0x8D; /* = on numeric keypad (NEC PC98) */ - /** */ - public static final int KEY_CIRCUMFLEX = 0x90; /* (Japanese keyboard) */ - /** */ - public static final int KEY_AT = 0x91; /* (NEC PC98) */ - /** */ - public static final int KEY_COLON = 0x92; /* (NEC PC98) */ - /** */ - public static final int KEY_UNDERLINE = 0x93; /* (NEC PC98) */ - /** */ - public static final int KEY_KANJI = 0x94; /* (Japanese keyboard) */ - /** */ - public static final int KEY_STOP = 0x95; /* (NEC PC98) */ - /** */ - public static final int KEY_AX = 0x96; /* (Japan AX) */ - /** */ - public static final int KEY_UNLABELED = 0x97; /* (J3100) */ - /** */ - public static final int KEY_NUMPADENTER = 0x9C; /* Enter on numeric keypad */ - /** */ - public static final int KEY_RCONTROL = 0x9D; - /** */ - public static final int KEY_NUMPADCOMMA = 0xB3; /* , on numeric keypad (NEC PC98) */ - /** */ - public static final int KEY_DIVIDE = 0xB5; /* / on numeric keypad */ - /** */ - public static final int KEY_SYSRQ = 0xB7; - /** */ - public static final int KEY_RMENU = 0xB8; /* right Alt */ - /** */ - public static final int KEY_PAUSE = 0xC5; /* Pause */ - /** */ - public static final int KEY_HOME = 0xC7; /* Home on arrow keypad */ - /** */ - public static final int KEY_UP = 0xC8; /* UpArrow on arrow keypad */ - /** */ - public static final int KEY_PRIOR = 0xC9; /* PgUp on arrow keypad */ - /** */ - public static final int KEY_LEFT = 0xCB; /* LeftArrow on arrow keypad */ - /** */ - public static final int KEY_RIGHT = 0xCD; /* RightArrow on arrow keypad */ - /** */ - public static final int KEY_END = 0xCF; /* End on arrow keypad */ - /** */ - public static final int KEY_DOWN = 0xD0; /* DownArrow on arrow keypad */ - /** */ - public static final int KEY_NEXT = 0xD1; /* PgDn on arrow keypad */ - /** */ - public static final int KEY_INSERT = 0xD2; /* Insert on arrow keypad */ - /** */ - public static final int KEY_DELETE = 0xD3; /* Delete on arrow keypad */ - /** */ - public static final int KEY_LWIN = 0xDB; /* Left Windows key */ - /** */ - public static final int KEY_RWIN = 0xDC; /* Right Windows key */ - /** */ - public static final int KEY_APPS = 0xDD; /* AppMenu key */ - /** */ - public static final int KEY_POWER = 0xDE; - /** */ - public static final int KEY_SLEEP = 0xDF; - + /** A helper for left ALT */ public static final int KEY_LALT = KEY_LMENU; /** A helper for right ALT */ @@ -346,20 +87,13 @@ public class Input { /** The middle mouse button indicator */ public static final int MOUSE_MIDDLE_BUTTON = 2; - /** True if the controllers system has been initialised */ - private static boolean controllersInited = false; - /** The list of controllers */ - private static ArrayList controllers = new ArrayList(); - /** The last recorded mouse x position */ private int lastMouseX; /** The last recorded mouse y position */ private int lastMouseY; /** THe state of the mouse buttons */ protected boolean[] mousePressed = new boolean[10]; - /** THe state of the controller buttons */ - private boolean[][] controllerPressed = new boolean[100][MAX_BUTTONS]; - + /** The character values representing the pressed keys */ protected char[] keys = new char[1024]; /** True if the key has been pressed since last queries */ @@ -367,22 +101,10 @@ public class Input { /** The time since the next key repeat to be fired for the key */ protected long[] nextRepeat = new long[1024]; - /** The control states from the controllers */ - private boolean[][] controls = new boolean[10][MAX_BUTTONS+10]; - /** True if the event has been consumed */ - protected boolean consumed = false; - /** A list of listeners to be notified of input events */ - protected HashSet allListeners = new HashSet(); /** The listeners to notify of key events */ - protected ArrayList keyListeners = new ArrayList(); + protected ArrayList keyListeners = new ArrayList<>(); /** The listener to add */ - protected ArrayList keyListenersToAdd = new ArrayList(); - /** The listeners to notify of mouse events */ - protected ArrayList mouseListeners = new ArrayList(); - /** The listener to add */ - protected ArrayList mouseListenersToAdd = new ArrayList(); - /** The listener to nofiy of controller events */ - protected ArrayList controllerListeners = new ArrayList(); + protected ArrayList mouseListeners = new ArrayList<>(); /** The current value of the wheel */ private int wheel; /** The height of the display */ @@ -398,46 +120,9 @@ public class Input { /** The interval of key repeat */ private int keyRepeatInterval; - /** True if the input is currently paused */ - private boolean paused; - /** The scale to apply to screen coordinates */ - private float scaleX = 1; - /** The scale to apply to screen coordinates */ - private float scaleY = 1; - /** The offset to apply to screen coordinates */ - private float xoffset = 0; - /** The offset to apply to screen coordinates */ - private float yoffset = 0; - - /** The delay before determining a single or double click */ - private int doubleClickDelay = 250; - /** The timer running out for a single click */ - private long doubleClickTimeout = 0; - - /** The clicked x position */ - private int clickX; - /** The clicked y position */ - private int clickY; /** The clicked button */ private int clickButton; - /** The x position location the mouse was pressed */ - private int pressedX = -1; - - /** The x position location the mouse was pressed */ - private int pressedY = -1; - - /** The pixel distance the mouse can move to accept a mouse click */ - private int mouseClickTolerance = 5; - - /** - * Disables support for controllers. This means the jinput JAR and native libs - * are not required. - */ - public static void disableControllers() { - controllersInited = true; - } - /** * Create a new input with the height of the screen * @@ -446,58 +131,7 @@ public class Input { public Input(int height) { init(height); } - - /** - * Set the double click interval, the time between the first - * and second clicks that should be interpreted as a - * double click. - * - * @param delay The delay between clicks - */ - public void setDoubleClickInterval(int delay) { - doubleClickDelay = delay; - } - /** - * Set the pixel distance the mouse can move to accept a mouse click. - * Default is 5. - * - * @param mouseClickTolerance The number of pixels. - */ - public void setMouseClickTolerance (int mouseClickTolerance) { - this.mouseClickTolerance = mouseClickTolerance; - } - - /** - * Set the scaling to apply to screen coordinates - * - * @param scaleX The scaling to apply to the horizontal axis - * @param scaleY The scaling to apply to the vertical axis - */ - public void setScale(float scaleX, float scaleY) { - this.scaleX = scaleX; - this.scaleY = scaleY; - } - - /** - * Set the offset to apply to the screen coodinates - * - * @param xoffset The offset on the x-axis - * @param yoffset The offset on the y-axis - */ - public void setOffset(float xoffset, float yoffset) { - this.xoffset = xoffset; - this.yoffset = yoffset; - } - - /** - * Reset the transformation being applied to the input to the default - */ - public void resetInputTransform() { - setOffset(0, 0); - setScale(1, 1); - } - /** * Add a listener to be notified of input events * @@ -506,7 +140,6 @@ public class Input { public void addListener(InputListener listener) { addKeyListener(listener); addMouseListener(listener); - addControllerListener(listener); } /** @@ -515,55 +148,20 @@ public class Input { * @param listener The listener to be notified */ public void addKeyListener(KeyListener listener) { - keyListenersToAdd.add(listener); + if (!keyListeners.contains(listener)) { + keyListeners.add(listener); + } } - /** - * Add a key listener to be notified of key input events - * - * @param listener The listener to be notified - */ - private void addKeyListenerImpl(KeyListener listener) { - if (keyListeners.contains(listener)) { - return; - } - keyListeners.add(listener); - allListeners.add(listener); - } - /** * Add a mouse listener to be notified of mouse input events * * @param listener The listener to be notified */ public void addMouseListener(MouseListener listener) { - mouseListenersToAdd.add(listener); - } - - /** - * Add a mouse listener to be notified of mouse input events - * - * @param listener The listener to be notified - */ - private void addMouseListenerImpl(MouseListener listener) { - if (mouseListeners.contains(listener)) { - return; + if (!mouseListeners.contains(listener)) { + mouseListeners.add(listener); } - mouseListeners.add(listener); - allListeners.add(listener); - } - - /** - * Add a controller listener to be notified of controller input events - * - * @param listener The listener to be notified - */ - public void addControllerListener(ControllerListener listener) { - if (controllerListeners.contains(listener)) { - return; - } - controllerListeners.add(listener); - allListeners.add(listener); } /** @@ -572,14 +170,12 @@ public class Input { public void removeAllListeners() { removeAllKeyListeners(); removeAllMouseListeners(); - removeAllControllerListeners(); } /** * Remove all the key listeners from this input */ public void removeAllKeyListeners() { - allListeners.removeAll(keyListeners); keyListeners.clear(); } @@ -587,18 +183,9 @@ public class Input { * Remove all the mouse listeners from this input */ public void removeAllMouseListeners() { - allListeners.removeAll(mouseListeners); mouseListeners.clear(); } - /** - * Remove all the controller listeners from this input - */ - public void removeAllControllerListeners() { - allListeners.removeAll(controllerListeners); - controllerListeners.clear(); - } - /** * Add a listener to be notified of input events. This listener * will get events before others that are currently registered @@ -610,9 +197,6 @@ public class Input { keyListeners.add(0, listener); mouseListeners.add(0, listener); - controllerListeners.add(0, listener); - - allListeners.add(listener); } /** @@ -623,7 +207,6 @@ public class Input { public void removeListener(InputListener listener) { removeKeyListener(listener); removeMouseListener(listener); - removeControllerListener(listener); } /** @@ -633,23 +216,6 @@ public class Input { */ public void removeKeyListener(KeyListener listener) { keyListeners.remove(listener); - - if (!mouseListeners.contains(listener) && !controllerListeners.contains(listener)) { - allListeners.remove(listener); - } - } - - /** - * Remove a controller listener that will no longer be notified - * - * @param listener The listen to be removed - */ - public void removeControllerListener(ControllerListener listener) { - controllerListeners.remove(listener); - - if (!mouseListeners.contains(listener) && !keyListeners.contains(listener)) { - allListeners.remove(listener); - } } /** @@ -659,10 +225,6 @@ public class Input { */ public void removeMouseListener(MouseListener listener) { mouseListeners.remove(listener); - - if (!controllerListeners.contains(listener) && !keyListeners.contains(listener)) { - allListeners.remove(listener); - } } /** @@ -675,17 +237,7 @@ public class Input { lastMouseX = getMouseX(); lastMouseY = getMouseY(); } - - /** - * Get the character representation of the key identified by the specified code - * - * @param code The key code of the key to retrieve the name of - * @return The name or character representation of the key requested - */ - public static String getKeyName(int code) { - return Keyboard.getKeyName(code); - } - + /** * Check if a particular key has been pressed since this method * was last called for the specified key @@ -716,45 +268,7 @@ public class Input { return false; } - - /** - * Check if a controller button has been pressed since last - * time - * - * @param button The button to check for (note that this includes directional controls first) - * @return True if the button has been pressed since last time - */ - public boolean isControlPressed(int button) { - return isControlPressed(button, 0); - } - /** - * Check if a controller button has been pressed since last - * time - * - * @param controller The index of the controller to check - * @param button The button to check for (note that this includes directional controls first) - * @return True if the button has been pressed since last time - */ - public boolean isControlPressed(int button, int controller) { - if (controllerPressed[controller][button]) { - controllerPressed[controller][button] = false; - return true; - } - - return false; - } - - /** - * Clear the state for isControlPressed method. This will reset all - * controls to not pressed - */ - public void clearControlPressedRecord() { - for (int i=0;iisKeyPressed method. This will * resort in all keys returning that they haven't been pressed, until @@ -772,42 +286,14 @@ public class Input { public void clearMousePressedRecord() { Arrays.fill(mousePressed, false); } - - /** - * Check if a particular key is down - * - * @param code The key code of the key to check - * @return True if the key is down - */ - public boolean isKeyDown(int code) { - return Keyboard.isKeyDown(code); - } - /** - * Get the absolute x position of the mouse cursor within the container - * - * @return The absolute x position of the mouse cursor - */ - public int getAbsoluteMouseX() { - return Mouse.getX(); - } - - /** - * Get the absolute y position of the mouse cursor within the container - * - * @return The absolute y position of the mouse cursor - */ - public int getAbsoluteMouseY() { - return height - Mouse.getY(); - } - /** * Get the x position of the mouse cursor * * @return The x position of the mouse cursor */ public int getMouseX() { - return (int) ((Mouse.getX() * scaleX)+xoffset); + return Mouse.getX(); } /** @@ -816,25 +302,15 @@ public class Input { * @return The y position of the mouse cursor */ public int getMouseY() { - return (int) (((height-Mouse.getY()) * scaleY)+yoffset); + return height - Mouse.getY(); } - - /** - * Check if a given mouse button is down - * - * @param button The index of the button to check (starting at 0) - * @return True if the mouse button is down - */ - public boolean isMouseButtonDown(int button) { - return Mouse.isButtonDown(button); - } - + /** * Check if any mouse button is down * * @return True if any mouse button is down */ - private boolean anyMouseDown() { + public boolean anyMouseDown() { for (int i=0;i<3;i++) { if (Mouse.isButtonDown(i)) { return true; @@ -843,312 +319,11 @@ public class Input { return false; } - - /** - * Get a count of the number of controlles available - * - * @return The number of controllers available - */ - public int getControllerCount() { - try { - initControllers(); - } catch (SlickException e) { - throw new RuntimeException("Failed to initialise controllers"); - } - - return controllers.size(); - } - - /** - * Get the number of axis that are avaiable on a given controller - * - * @param controller The index of the controller to check - * @return The number of axis available on the controller - */ - public int getAxisCount(int controller) { - return ((Controller) controllers.get(controller)).getAxisCount(); - } - - /** - * Get the value of the axis with the given index - * - * @param controller The index of the controller to check - * @param axis The index of the axis to read - * @return The axis value at time of reading - */ - public float getAxisValue(int controller, int axis) { - return ((Controller) controllers.get(controller)).getAxisValue(axis); + + public boolean isControlDown() { + return Keyboard.isKeyDown(KEY_RCONTROL) || Keyboard.isKeyDown(KEY_LCONTROL); } - /** - * Get the name of the axis with the given index - * - * @param controller The index of the controller to check - * @param axis The index of the axis to read - * @return The name of the specified axis - */ - public String getAxisName(int controller, int axis) { - return ((Controller) controllers.get(controller)).getAxisName(axis); - } - - /** - * Check if the controller has the left direction pressed - * - * @param controller The index of the controller to check - * @return True if the controller is pressed to the left - */ - public boolean isControllerLeft(int controller) { - if (controller >= getControllerCount()) { - return false; - } - - if (controller == ANY_CONTROLLER) { - for (int i=0;i= getControllerCount()) { - return false; - } - - if (controller == ANY_CONTROLLER) { - for (int i=0;i 0.5f - || ((Controller) controllers.get(controller)).getPovX() > 0.5f; - } - - /** - * Check if the controller has the up direction pressed - * - * @param controller The index of the controller to check - * @return True if the controller is pressed to the up - */ - public boolean isControllerUp(int controller) { - if (controller >= getControllerCount()) { - return false; - } - - if (controller == ANY_CONTROLLER) { - for (int i=0;i= getControllerCount()) { - return false; - } - - if (controller == ANY_CONTROLLER) { - for (int i=0;i 0.5f - || ((Controller) controllers.get(controller)).getPovY() > 0.5f; - - } - - /** - * Check if controller button is pressed - * - * @param controller The index of the controller to check - * @param index The index of the button to check - * @return True if the button is pressed - */ - public boolean isButtonPressed(int index, int controller) { - if (controller >= getControllerCount()) { - return false; - } - - if (controller == ANY_CONTROLLER) { - for (int i=0;i= 3) && (controller.getButtonCount() < MAX_BUTTONS)) { - controllers.add(controller); - } - } - - Log.info("Found "+controllers.size()+" controllers"); - for (int i=0;i doubleClickTimeout) { - doubleClickTimeout = 0; - } - } - this.height = height; - Iterator allStarts = allListeners.iterator(); - while (allStarts.hasNext()) { - ControlledInputReciever listener = (ControlledInputReciever) allStarts.next(); - listener.inputStarted(); - } - while (Keyboard.next()) { if (Keyboard.getEventKeyState()) { - int eventKey = resolveEventKey(Keyboard.getEventKey(), Keyboard.getEventCharacter()); - + int eventKey = Keyboard.getEventKey(); + keys[eventKey] = Keyboard.getEventCharacter(); pressed[eventKey] = true; nextRepeat[eventKey] = System.currentTimeMillis() + keyRepeatInitial; - consumed = false; - for (int i=0;i= 0 && Mouse.getEventButton() < mousePressed.length) { if (Mouse.getEventButtonState()) { - consumed = false; mousePressed[Mouse.getEventButton()] = true; - pressedX = (int) (xoffset + (Mouse.getEventX() * scaleX)); - pressedY = (int) (yoffset + ((height-Mouse.getEventY()) * scaleY)); - lastMouseX = pressedX; - lastMouseY = pressedY; + lastMouseX = Mouse.getEventX(); + lastMouseY = height - Mouse.getEventY(); - for (int i=0;i nextRepeat[i]) { nextRepeat[i] = System.currentTimeMillis() + keyRepeatInterval; - consumed = false; - for (int j=0;j= BUTTON1) { - return isButtonPressed((index-BUTTON1), controllerIndex); - } - - throw new RuntimeException("Unknown control index"); - } - - - /** - * Pauses the polling and sending of input events. - */ - public void pause() { - paused = true; - - // Reset all polling arrays - clearKeyPressedRecord(); - clearMousePressedRecord(); - clearControlPressedRecord(); - } - - /** - * Resumes the polling and sending of input events. - */ - public void resume() { - paused = false; - } - - /** - * Notify listeners that the mouse button has been clicked - * - * @param button The button that has been clicked - * @param x The location at which the button was clicked - * @param y The location at which the button was clicked - * @param clickCount The number of times the button was clicked (single or double click) - */ - private void fireMouseClicked(int button, int x, int y, int clickCount) { - consumed = false; - for (int i=0;i 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(); } diff --git a/src/org/newdawn/slick/state/transition/DelayedFadeOutTransition.java b/src/org/newdawn/slick/state/transition/DelayedFadeOutTransition.java deleted file mode 100644 index b6f9b2db..00000000 --- a/src/org/newdawn/slick/state/transition/DelayedFadeOutTransition.java +++ /dev/null @@ -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) {} -} diff --git a/src/org/newdawn/slick/state/transition/EasedFadeOutTransition.java b/src/org/newdawn/slick/state/transition/EasedFadeOutTransition.java deleted file mode 100644 index 8a904fd3..00000000 --- a/src/org/newdawn/slick/state/transition/EasedFadeOutTransition.java +++ /dev/null @@ -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) {} -} diff --git a/src/yugecin/opsudance/Dancer.java b/src/yugecin/opsudance/Dancer.java index beadcd0b..944df3d1 100644 --- a/src/yugecin/opsudance/Dancer.java +++ b/src/yugecin/opsudance/Dancer.java @@ -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() { diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index 99cbcb3c..9bcc9895 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -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); } diff --git a/src/yugecin/opsudance/Pippi.java b/src/yugecin/opsudance/Pippi.java index 3567910c..21fac876 100644 --- a/src/yugecin/opsudance/Pippi.java +++ b/src/yugecin/opsudance/Pippi.java @@ -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; } } diff --git a/src/yugecin/opsudance/PreStartupInitializer.java b/src/yugecin/opsudance/PreStartupInitializer.java deleted file mode 100644 index 678d0c3d..00000000 --- a/src/yugecin/opsudance/PreStartupInitializer.java +++ /dev/null @@ -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 . - */ -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/"))); - } - -} diff --git a/src/yugecin/opsudance/core/state/transitions/FadeTransitionState.java b/src/yugecin/opsudance/core/Constants.java similarity index 52% rename from src/yugecin/opsudance/core/state/transitions/FadeTransitionState.java rename to src/yugecin/opsudance/core/Constants.java index ced62278..fb501798 100644 --- a/src/yugecin/opsudance/core/state/transitions/FadeTransitionState.java +++ b/src/yugecin/opsudance/core/Constants.java @@ -15,28 +15,18 @@ * You should have received a copy of the GNU General Public License * along with opsu!dance. If not, see . */ -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"; } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index a185910b..f9ee69a4 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -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() { - @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 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 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 newState) { - switchState(newState, FadeOutTransitionState.class, 200, FadeInTransitionState.class, 300); - } - - public void switchStateNow(Class newState) { - switchState(newState, EmptyTransitionState.class, 0, FadeInTransitionState.class, 300); - } - - public void switchStateInstantly(Class newState) { - state.leave(); - state = instanceContainer.provide(newState); - state.enter(); - } - - public void switchState(Class newState, Class outTransition, int outTime, Class 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() { } - } diff --git a/src/yugecin/opsudance/core/Entrypoint.java b/src/yugecin/opsudance/core/Entrypoint.java index dfba2245..440ff72b 100644 --- a/src/yugecin/opsudance/core/Entrypoint.java +++ b/src/yugecin/opsudance/core/Entrypoint.java @@ -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)); } } diff --git a/src/yugecin/opsudance/core/Environment.java b/src/yugecin/opsudance/core/Environment.java new file mode 100644 index 00000000..3a615116 --- /dev/null +++ b/src/yugecin/opsudance/core/Environment.java @@ -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 . + */ +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(); + } + } + +} diff --git a/src/yugecin/opsudance/core/GlobalInputListener.java b/src/yugecin/opsudance/core/GlobalInputListener.java new file mode 100644 index 00000000..4e57f1b2 --- /dev/null +++ b/src/yugecin/opsudance/core/GlobalInputListener.java @@ -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 . + */ +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; + } + +} diff --git a/src/yugecin/opsudance/core/InstanceContainer.java b/src/yugecin/opsudance/core/InstanceContainer.java new file mode 100644 index 00000000..a2cb6c75 --- /dev/null +++ b/src/yugecin/opsudance/core/InstanceContainer.java @@ -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 . + */ +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); + } + } + +} diff --git a/src/yugecin/opsudance/core/state/transitions/EmptyTransitionState.java b/src/yugecin/opsudance/core/NotNull.java similarity index 80% rename from src/yugecin/opsudance/core/state/transitions/EmptyTransitionState.java rename to src/yugecin/opsudance/core/NotNull.java index fec4c716..be9e7a68 100644 --- a/src/yugecin/opsudance/core/state/transitions/EmptyTransitionState.java +++ b/src/yugecin/opsudance/core/NotNull.java @@ -15,13 +15,9 @@ * You should have received a copy of the GNU General Public License * along with opsu!dance. If not, see . */ -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 {} diff --git a/src/yugecin/opsudance/core/events/EventListener.java b/src/yugecin/opsudance/core/Nullable.java similarity index 80% rename from src/yugecin/opsudance/core/events/EventListener.java rename to src/yugecin/opsudance/core/Nullable.java index e4249347..0e2b79c0 100644 --- a/src/yugecin/opsudance/core/events/EventListener.java +++ b/src/yugecin/opsudance/core/Nullable.java @@ -15,10 +15,9 @@ * You should have received a copy of the GNU General Public License * along with opsu!dance. If not, see . */ -package yugecin.opsudance.core.events; +package yugecin.opsudance.core; -public interface EventListener { +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; - void onEvent(T event); - -} +@Retention(RetentionPolicy.SOURCE) public @interface Nullable {} diff --git a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java index 4369913b..2a3ef34f 100644 --- a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java +++ b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java @@ -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; - } - } diff --git a/src/yugecin/opsudance/core/events/EventBus.java b/src/yugecin/opsudance/core/events/Event.java similarity index 52% rename from src/yugecin/opsudance/core/events/EventBus.java rename to src/yugecin/opsudance/core/events/Event.java index 1a7b4df8..63160e02 100644 --- a/src/yugecin/opsudance/core/events/EventBus.java +++ b/src/yugecin/opsudance/core/events/Event.java @@ -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 { - private EventBus() { + private final Class type; + private final LinkedList listeners; + + public Event(Class type) { + this.type = type; + this.listeners = new LinkedList<>(); } - private static final List subscribers = new LinkedList<>(); - - public static void subscribe(Class eventType, EventListener 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 { - - private final Class eventType; - private final EventListener listener; - - private Subscriber(Class eventType, EventListener 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; + } + }); } } diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 3129ded8..ba100f31 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -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 . */ 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(); diff --git a/src/yugecin/opsudance/core/state/BaseOpsuState.java b/src/yugecin/opsudance/core/state/BaseOpsuState.java index 0ff6c63d..893a4853 100644 --- a/src/yugecin/opsudance/core/state/BaseOpsuState.java +++ b/src/yugecin/opsudance/core/state/BaseOpsuState.java @@ -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 { - - @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 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; diff --git a/src/yugecin/opsudance/core/state/OpsuState.java b/src/yugecin/opsudance/core/state/OpsuState.java index 0a0a65ca..204ce8cf 100644 --- a/src/yugecin/opsudance/core/state/OpsuState.java +++ b/src/yugecin/opsudance/core/state/OpsuState.java @@ -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); - } diff --git a/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java b/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java index 06ccb746..dfb24d2c 100644 --- a/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java +++ b/src/yugecin/opsudance/core/state/specialstates/BarNotificationState.java @@ -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 { +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 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() { - @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 } @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(); + } + } diff --git a/src/yugecin/opsudance/core/state/specialstates/BubbleNotificationState.java b/src/yugecin/opsudance/core/state/specialstates/BubNotifState.java similarity index 81% rename from src/yugecin/opsudance/core/state/specialstates/BubbleNotificationState.java rename to src/yugecin/opsudance/core/state/specialstates/BubNotifState.java index 8cdfb083..34cefd0f 100644 --- a/src/yugecin/opsudance/core/state/specialstates/BubbleNotificationState.java +++ b/src/yugecin/opsudance/core/state/specialstates/BubNotifState.java @@ -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 { +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 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() { - @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 BubbleNotificationState.TOTAL_TIME; + return timeShown > BubNotifState.TOTAL_TIME; } private void processAnimations(boolean mouseHovered, int delta) { @@ -218,17 +233,17 @@ public class BubbleNotificationState implements EventListener 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 { +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. - */ -package yugecin.opsudance.core.state.transitions; - -public class FadeOutTransitionState extends FadeTransitionState { - - @Override - protected float getMaskAlphaLevel(float fadeProgress) { - return fadeProgress; - } - -} diff --git a/src/yugecin/opsudance/core/state/transitions/TransitionFinishedListener.java b/src/yugecin/opsudance/core/state/transitions/TransitionFinishedListener.java deleted file mode 100644 index 3838884b..00000000 --- a/src/yugecin/opsudance/core/state/transitions/TransitionFinishedListener.java +++ /dev/null @@ -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 . - */ -package yugecin.opsudance.core.state.transitions; - -public interface TransitionFinishedListener { - - void onFinish(); - -} diff --git a/src/yugecin/opsudance/core/state/transitions/TransitionState.java b/src/yugecin/opsudance/core/state/transitions/TransitionState.java deleted file mode 100644 index 9ea38cf1..00000000 --- a/src/yugecin/opsudance/core/state/transitions/TransitionState.java +++ /dev/null @@ -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 . - */ -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); - } - -} diff --git a/src/yugecin/opsudance/events/BarNotificationEvent.java b/src/yugecin/opsudance/events/BarNotifListener.java similarity index 80% rename from src/yugecin/opsudance/events/BarNotificationEvent.java rename to src/yugecin/opsudance/events/BarNotifListener.java index f3fc6182..ed798e32 100644 --- a/src/yugecin/opsudance/events/BarNotificationEvent.java +++ b/src/yugecin/opsudance/events/BarNotifListener.java @@ -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 EVENT = new Event<>(BarNotifListener.class); + + void onBarNotif(String message); } diff --git a/src/yugecin/opsudance/events/BubNotifListener.java b/src/yugecin/opsudance/events/BubNotifListener.java new file mode 100644 index 00000000..2990d676 --- /dev/null +++ b/src/yugecin/opsudance/events/BubNotifListener.java @@ -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 . + */ +package yugecin.opsudance.events; + +import org.newdawn.slick.Color; +import yugecin.opsudance.core.events.Event; + +@SuppressWarnings({"UnnecessaryInterfaceModifier", "unused"}) +public interface BubNotifListener { + + Event EVENT = new Event<>(BubNotifListener.class); + + void onBubNotif(String message, Color borderColor); + +} diff --git a/src/yugecin/opsudance/events/BubbleNotificationEvent.java b/src/yugecin/opsudance/events/BubbleNotificationEvent.java deleted file mode 100644 index 8ae2b1de..00000000 --- a/src/yugecin/opsudance/events/BubbleNotificationEvent.java +++ /dev/null @@ -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 . - */ -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; - } - -} diff --git a/src/yugecin/opsudance/events/ResolutionOrSkinChangedEvent.java b/src/yugecin/opsudance/events/ResolutionChangedListener.java similarity index 74% rename from src/yugecin/opsudance/events/ResolutionOrSkinChangedEvent.java rename to src/yugecin/opsudance/events/ResolutionChangedListener.java index 2b9a1692..c0311f0d 100644 --- a/src/yugecin/opsudance/events/ResolutionOrSkinChangedEvent.java +++ b/src/yugecin/opsudance/events/ResolutionChangedListener.java @@ -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 EVENT = new Event<>(ResolutionChangedListener.class); + + void onResolutionChanged(int w, int h); } diff --git a/src/yugecin/opsudance/core/state/transitions/FadeInTransitionState.java b/src/yugecin/opsudance/events/SkinChangedListener.java similarity index 75% rename from src/yugecin/opsudance/core/state/transitions/FadeInTransitionState.java rename to src/yugecin/opsudance/events/SkinChangedListener.java index 5ca1e6c1..273fa1b6 100644 --- a/src/yugecin/opsudance/core/state/transitions/FadeInTransitionState.java +++ b/src/yugecin/opsudance/events/SkinChangedListener.java @@ -15,13 +15,14 @@ * You should have received a copy of the GNU General Public License * along with opsu!dance. If not, see . */ -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 EVENT = new Event<>(SkinChangedListener.class); + + void onSkinChanged(String stringName); } diff --git a/src/yugecin/opsudance/movers/CircleMover.java b/src/yugecin/opsudance/movers/CircleMover.java index a2e36ee9..e9e3bda4 100644 --- a/src/yugecin/opsudance/movers/CircleMover.java +++ b/src/yugecin/opsudance/movers/CircleMover.java @@ -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; } diff --git a/src/yugecin/opsudance/movers/ExgonMover.java b/src/yugecin/opsudance/movers/ExgonMover.java index 93aca718..6c7f200b 100644 --- a/src/yugecin/opsudance/movers/ExgonMover.java +++ b/src/yugecin/opsudance/movers/ExgonMover.java @@ -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; diff --git a/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java b/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java index ecff7fec..333a894a 100644 --- a/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java +++ b/src/yugecin/opsudance/movers/factories/AutoMoverFactory.java @@ -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 diff --git a/src/yugecin/opsudance/options/Configuration.java b/src/yugecin/opsudance/options/Configuration.java index 393725ad..989d99fc 100644 --- a/src/yugecin/opsudance/options/Configuration.java +++ b/src/yugecin/opsudance/options/Configuration.java @@ -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(); diff --git a/src/yugecin/opsudance/options/NumericOption.java b/src/yugecin/opsudance/options/NumericOption.java index 84466f11..84a83dc2 100644 --- a/src/yugecin/opsudance/options/NumericOption.java +++ b/src/yugecin/opsudance/options/NumericOption.java @@ -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); } } diff --git a/src/yugecin/opsudance/options/Option.java b/src/yugecin/opsudance/options/Option.java index cb379138..76acf4f0 100644 --- a/src/yugecin/opsudance/options/Option.java +++ b/src/yugecin/opsudance/options/Option.java @@ -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. diff --git a/src/yugecin/opsudance/options/OptionGroups.java b/src/yugecin/opsudance/options/OptionGroups.java index 089865e9..0df29f34 100644 --- a/src/yugecin/opsudance/options/OptionGroups.java +++ b/src/yugecin/opsudance/options/OptionGroups.java @@ -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, diff --git a/src/yugecin/opsudance/options/OptionTab.java b/src/yugecin/opsudance/options/OptionTab.java index 7db8dcd4..4c9b66c4 100644 --- a/src/yugecin/opsudance/options/OptionTab.java +++ b/src/yugecin/opsudance/options/OptionTab.java @@ -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; } } diff --git a/src/yugecin/opsudance/options/Options.java b/src/yugecin/opsudance/options/Options.java index 6e696d87..17f3cf92 100644 --- a/src/yugecin/opsudance/options/Options.java +++ b/src/yugecin/opsudance/options/Options.java @@ -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() { - @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 = new CachedVariable<>(new Getter() { - @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); diff --git a/src/yugecin/opsudance/options/OptionsService.java b/src/yugecin/opsudance/options/OptionsService.java index 01c05d9e..b4fe3ee9 100644 --- a/src/yugecin/opsudance/options/OptionsService.java +++ b/src/yugecin/opsudance/options/OptionsService.java @@ -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 optionMap; - public static final HashMap 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); } } diff --git a/src/yugecin/opsudance/render/GameObjectRenderer.java b/src/yugecin/opsudance/render/GameObjectRenderer.java index 25b6b211..04edeaa1 100644 --- a/src/yugecin/opsudance/render/GameObjectRenderer.java +++ b/src/yugecin/opsudance/render/GameObjectRenderer.java @@ -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; diff --git a/src/yugecin/opsudance/sbv2/MoveStoryboard.java b/src/yugecin/opsudance/sbv2/MoveStoryboard.java index b9e1c3cf..d7fd084e 100644 --- a/src/yugecin/opsudance/sbv2/MoveStoryboard.java +++ b/src/yugecin/opsudance/sbv2/MoveStoryboard.java @@ -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) { diff --git a/src/yugecin/opsudance/skinning/SkinService.java b/src/yugecin/opsudance/skinning/SkinService.java index 7b7fe64b..814f736d 100644 --- a/src/yugecin/opsudance/skinning/SkinService.java +++ b/src/yugecin/opsudance/skinning/SkinService.java @@ -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); } /** diff --git a/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java b/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java index b210bc03..f25e5d4b 100644 --- a/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java +++ b/src/yugecin/opsudance/spinners/ApproachCircleSpinner.java @@ -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; } diff --git a/src/yugecin/opsudance/spinners/BeamSpinner.java b/src/yugecin/opsudance/spinners/BeamSpinner.java index 36c02558..d0908bae 100644 --- a/src/yugecin/opsudance/spinners/BeamSpinner.java +++ b/src/yugecin/opsudance/spinners/BeamSpinner.java @@ -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); } diff --git a/src/yugecin/opsudance/spinners/CircleSpinner.java b/src/yugecin/opsudance/spinners/CircleSpinner.java index 1f654318..b014d406 100644 --- a/src/yugecin/opsudance/spinners/CircleSpinner.java +++ b/src/yugecin/opsudance/spinners/CircleSpinner.java @@ -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; } diff --git a/src/yugecin/opsudance/spinners/CubeSpinner.java b/src/yugecin/opsudance/spinners/CubeSpinner.java index 15e7780e..622cbf0f 100644 --- a/src/yugecin/opsudance/spinners/CubeSpinner.java +++ b/src/yugecin/opsudance/spinners/CubeSpinner.java @@ -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; } diff --git a/src/yugecin/opsudance/spinners/DonutSpinner.java b/src/yugecin/opsudance/spinners/DonutSpinner.java index 18241079..2d65fec2 100644 --- a/src/yugecin/opsudance/spinners/DonutSpinner.java +++ b/src/yugecin/opsudance/spinners/DonutSpinner.java @@ -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; } diff --git a/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java b/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java index 5d223104..b1f55d48 100644 --- a/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java +++ b/src/yugecin/opsudance/spinners/FivePointStarApproachSpinner.java @@ -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; } diff --git a/src/yugecin/opsudance/spinners/FivePointStarSpinner.java b/src/yugecin/opsudance/spinners/FivePointStarSpinner.java index a905b583..d9eb8377 100644 --- a/src/yugecin/opsudance/spinners/FivePointStarSpinner.java +++ b/src/yugecin/opsudance/spinners/FivePointStarSpinner.java @@ -17,18 +17,18 @@ */ package yugecin.opsudance.spinners; -import yugecin.opsudance.options.Options; +import static yugecin.opsudance.core.InstanceContainer.*; public class FivePointStarSpinner extends Spinner { @Override public void init() { double[][] points = new double[10][]; - double midx = Options.width / 2d; - double midy = Options.height / 2d; + double midx = displayContainer.width / 2d; + double midy = displayContainer.height / 2d; double angleIncRads = Math.PI * 36d / 180d; double ang = -Math.PI / 2d; - double maxrad = Options.width / 4d; + double maxrad = displayContainer.width / 4d; double minrad = maxrad / 3d; for (int i = 0; i < 10; i++) { double rad = maxrad; diff --git a/src/yugecin/opsudance/spinners/HalfCircleSpinner.java b/src/yugecin/opsudance/spinners/HalfCircleSpinner.java index fb6a7d46..18d08597 100644 --- a/src/yugecin/opsudance/spinners/HalfCircleSpinner.java +++ b/src/yugecin/opsudance/spinners/HalfCircleSpinner.java @@ -19,6 +19,8 @@ package yugecin.opsudance.spinners; import yugecin.opsudance.options.Options; +import static yugecin.opsudance.core.InstanceContainer.displayContainer; + public class HalfCircleSpinner extends Spinner { private int ang = 0; @@ -45,8 +47,8 @@ public class HalfCircleSpinner extends Spinner { skipang += 359; } - point[0] = Options.width / 2.0d + Options.height / 2 * 0.8d * Math.cos(ang/180d*Math.PI); - point[1] = Options.height / 2.0d + Options.height / 2 * 0.8d * Math.sin(ang/180d*Math.PI); + point[0] = displayContainer.width / 2.0d + displayContainer.height / 2 * 0.8d * Math.cos(ang/180d*Math.PI); + point[1] = displayContainer.height / 2.0d + displayContainer.height / 2 * 0.8d * Math.sin(ang/180d*Math.PI); return point; } diff --git a/src/yugecin/opsudance/spinners/IlluminatiSpinner.java b/src/yugecin/opsudance/spinners/IlluminatiSpinner.java index 97d1b459..e4c946bd 100644 --- a/src/yugecin/opsudance/spinners/IlluminatiSpinner.java +++ b/src/yugecin/opsudance/spinners/IlluminatiSpinner.java @@ -17,17 +17,16 @@ */ package yugecin.opsudance.spinners; -import yugecin.opsudance.options.Options; +import static yugecin.opsudance.core.InstanceContainer.*; public class IlluminatiSpinner extends Spinner { @Override - public void init() - { + public void init() { init( new double[][] { - new double[] { Options.width / 2d - 120, Options.height / 2d + 80 }, - new double[] { Options.width / 2d, Options.height / 2d - 160 }, - new double[] { Options.width / 2d + 120, Options.height / 2d + 80 } + new double[] { displayContainer.width / 2d - 120, displayContainer.height / 2d + 80 }, + new double[] { displayContainer.width / 2d, displayContainer.height / 2d - 160 }, + new double[] { displayContainer.width / 2d + 120, displayContainer.height / 2d + 80 } } ); } diff --git a/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java b/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java index b5ce0264..4f099583 100644 --- a/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java +++ b/src/yugecin/opsudance/spinners/LessThanThreeSpinner.java @@ -17,7 +17,7 @@ */ package yugecin.opsudance.spinners; -import yugecin.opsudance.options.Options; +import static yugecin.opsudance.core.InstanceContainer.*; public class LessThanThreeSpinner extends Spinner { @@ -38,8 +38,8 @@ public class LessThanThreeSpinner extends Spinner { if( angle > 360 ) angle = 0; double theta = angle / 180d * Math.PI; double[] pos = new double[] { - Options.width / 2d, - Options.height / 2d + displayContainer.width / 2d, + displayContainer.height / 2d }; double r = 2 - 2 * Math.sin( theta ) + Math.sin( theta ) * Math.sqrt( Math.abs( Math.cos( theta ) ) ) / ( Math.sin( theta ) + 1.4 ); diff --git a/src/yugecin/opsudance/spinners/RektCircleSpinner.java b/src/yugecin/opsudance/spinners/RektCircleSpinner.java index 161b4cbd..c8c2341a 100644 --- a/src/yugecin/opsudance/spinners/RektCircleSpinner.java +++ b/src/yugecin/opsudance/spinners/RektCircleSpinner.java @@ -17,7 +17,7 @@ */ package yugecin.opsudance.spinners; -import yugecin.opsudance.options.Options; +import static yugecin.opsudance.core.InstanceContainer.*; public class RektCircleSpinner extends Spinner { @@ -25,51 +25,39 @@ public class RektCircleSpinner extends Spinner { private int index; private int pos; private double size; - private int delay = 0; @Override - public void init() - { + public void init() { index = 0; - size = Options.height * 0.8d; + size = displayContainer.height * 0.8d; point = new double[2]; } @Override - public double[] getPoint() - { + public double[] getPoint() { if (!waitForDelay()) { return point; } - delay = 0; final int INC = 50; - if( index == 0 ) - { - point[0] = Options.width / 2d + size / 2d - pos; - point[1] = Options.height / 2d - size / 2d; + if( index == 0 ) { + point[0] = displayContainer.width / 2d + size / 2d - pos; + point[1] = displayContainer.height / 2d - size / 2d; index++; - } - else if( index == 1 ) - { - point[0] = Options.width / 2 - size / 2; - point[1] = Options.height / 2 - size / 2 + pos; + } else if( index == 1 ) { + point[0] = displayContainer.width / 2 - size / 2; + point[1] = displayContainer.height / 2 - size / 2 + pos; index++; - } - else if( index == 2 ) - { - point[0] = Options.width / 2 - size / 2 + pos; - point[1] = Options.height / 2 + size / 2; + } else if( index == 2 ) { + point[0] = displayContainer.width / 2 - size / 2 + pos; + point[1] = displayContainer.height / 2 + size / 2; index++; - } - else if( index == 3 ) - { - point[0] = Options.width / 2 + size / 2; - point[1] = Options.height / 2 + size / 2 - pos; + } else if( index == 3 ) { + point[0] = displayContainer.width / 2 + size / 2; + point[1] = displayContainer.height / 2 + size / 2 - pos; pos += INC; - if( pos > size ) - { + if( pos > size ) { pos = INC; } index = 0; diff --git a/src/yugecin/opsudance/spinners/RektSpinner.java b/src/yugecin/opsudance/spinners/RektSpinner.java index 26bc5ddd..d1f75ca0 100644 --- a/src/yugecin/opsudance/spinners/RektSpinner.java +++ b/src/yugecin/opsudance/spinners/RektSpinner.java @@ -17,7 +17,7 @@ */ package yugecin.opsudance.spinners; -import yugecin.opsudance.options.Options; +import static yugecin.opsudance.core.InstanceContainer.*; public class RektSpinner extends Spinner { @@ -25,11 +25,11 @@ public class RektSpinner extends Spinner { public void init() { init(new double[][] { { 10, 10 }, - { Options.width / 2d, 10 }, - { Options.width - 10, 10 }, - { Options.width - 10, Options.height - 10 }, - { Options.width / 2d, Options.height - 10 }, - { 10, Options.height - 10 } + { displayContainer.width / 2d, 10 }, + { displayContainer.width - 10, 10 }, + { displayContainer.width - 10, displayContainer.height - 10 }, + { displayContainer.width / 2d, displayContainer.height - 10 }, + { 10, displayContainer.height - 10 } }); } diff --git a/src/yugecin/opsudance/ui/OptionsOverlay.java b/src/yugecin/opsudance/ui/OptionsOverlay.java index 7bb3bde2..331191ac 100644 --- a/src/yugecin/opsudance/ui/OptionsOverlay.java +++ b/src/yugecin/opsudance/ui/OptionsOverlay.java @@ -23,6 +23,7 @@ import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.ui.*; import itdelatrisu.opsu.ui.animations.AnimationEquation; +import org.lwjgl.input.Keyboard; import org.newdawn.slick.*; import org.newdawn.slick.gui.TextField; import yugecin.opsudance.core.DisplayContainer; @@ -32,6 +33,7 @@ import yugecin.opsudance.utils.FontUtil; import java.util.HashMap; import java.util.LinkedList; +import java.util.Random; import static yugecin.opsudance.options.Options.*; @@ -48,6 +50,12 @@ public class OptionsOverlay extends OverlayOpsuState { private static final Color COL_GREY = new Color(55, 55, 57); private static final Color COL_BLUE = new Color(Colors.BLUE_BACKGROUND); private static final Color COL_COMBOBOX_HOVER = new Color(185, 19, 121); + private static final Color COL_NAV_BG = new Color(COL_BG); + private static final Color COL_NAV_INDICATOR = new Color(COL_PINK); + private static final Color COL_NAV_WHITE = new Color(COL_WHITE); + private static final Color COL_NAV_FILTERED = new Color(37, 37, 37); + private static final Color COL_NAV_INACTIVE = new Color(153, 153, 153); + private static final Color COL_NAV_FILTERED_HOVERED = new Color(58, 58, 58); private static final float INDICATOR_ALPHA = 0.8f; private static final Color COL_INDICATOR = new Color(Color.black); @@ -75,6 +83,8 @@ public class OptionsOverlay extends OverlayOpsuState { /** Selected option indicator hide animation time past. */ private int indicatorHideAnimationTime; + private float showHideProgress; + private Listener listener; private Image sliderBallImg; @@ -83,6 +93,8 @@ public class OptionsOverlay extends OverlayOpsuState { private Image searchImg; private OptionTab[] sections; + private OptionTab activeSection; + private OptionTab hoveredNavigationEntry; private Option hoverOption; private Option selectedOption; @@ -97,10 +109,17 @@ public class OptionsOverlay extends OverlayOpsuState { private DropdownMenu openDropdownMenu; private int openDropdownVirtualY; - private int finalWidth; + private int targetWidth; private int width; private int height; + private int navButtonSize; + private int navStartY; + private int navTargetWidth; + private int navWidth; + private int navHoverTime; + private int navIndicatorSize; + private int optionWidth; private int optionStartX; private int optionStartY; @@ -137,6 +156,10 @@ public class OptionsOverlay extends OverlayOpsuState { private final TextField searchField; private String lastSearchText; + private int invalidSearchImgRotation; + private int invalidSearchTextRotation; + private int invalidSearchAnimationProgress; + private final int INVALID_SEARCH_ANIMATION_TIME = 500; public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] sections) { this.displayContainer = displayContainer; @@ -146,7 +169,7 @@ public class OptionsOverlay extends OverlayOpsuState { dropdownMenus = new HashMap<>(); visibleDropdownMenus = new LinkedList<>(); - searchField = new TextField(displayContainer, null, 0, 0, 0, 0); + searchField = new TextField(null, 0, 0, 0, 0); searchField.setMaxLength(20); scrollHandler = new KineticScrolling(); @@ -161,12 +184,18 @@ public class OptionsOverlay extends OverlayOpsuState { public void revalidate() { super.revalidate(); - finalWidth = Math.max((int) (displayContainer.width * 0.36f), 340); // 0.321f + boolean isWidescreen = displayContainer.isWidescreen(); + targetWidth = (int) (displayContainer.width * (isWidescreen ? 0.4f : 0.5f)); height = displayContainer.height; // calculate positions + float navIconWidthRatio = isWidescreen ? 0.046875f : 0.065f; + // non-widescreen ratio is not accurate + navButtonSize = (int) (displayContainer.width * navIconWidthRatio); + navIndicatorSize = navButtonSize / 10; + navTargetWidth = (int) (targetWidth * 0.45f) - navButtonSize; paddingRight = (int) (displayContainer.width * 0.009375f); // not so accurate - paddingLeft = (int) (displayContainer.width * 0.0180f); // not so accurate + paddingLeft = navButtonSize + (int) (displayContainer.width * 0.0180f); // not so accurate paddingTextLeft = paddingLeft + LINEWIDTH + (int) (displayContainer.width * 0.00625f); // not so accurate optionStartX = paddingTextLeft; textOptionsY = Fonts.LARGE.getLineHeight() * 2; @@ -177,7 +206,7 @@ public class OptionsOverlay extends OverlayOpsuState { sectionLineHeight = (int) (Fonts.LARGE.getLineHeight() * 1.5f); if (active) { - width = finalWidth; + width = targetWidth; optionWidth = width - optionStartX - paddingRight; } @@ -190,9 +219,11 @@ public class OptionsOverlay extends OverlayOpsuState { checkOnImg = GameImage.CONTROL_CHECK_ON.getImage().getScaledCopy(controlImageSize, controlImageSize); checkOffImg = GameImage.CONTROL_CHECK_OFF.getImage().getScaledCopy(controlImageSize, controlImageSize); + int navTotalHeight = 0; dropdownMenus.clear(); for (OptionTab section : sections) { if (section.options == null) { + navTotalHeight += navButtonSize; continue; } for (final Option option : section.options) { @@ -228,6 +259,7 @@ public class OptionsOverlay extends OverlayOpsuState { dropdownMenus.put(listOption, menu); } } + navStartY = (height - navTotalHeight) / 2; int searchImgSize = (int) (Fonts.LARGE.getLineHeight() * 0.75f); searchImg = GameImage.SEARCH.getImage().getScaledCopy(searchImgSize, searchImgSize); @@ -235,11 +267,11 @@ public class OptionsOverlay extends OverlayOpsuState { @Override public void onRender(Graphics g) { - g.setClip(0, 0, width, height); + g.setClip(navButtonSize, 0, width - navButtonSize, height); // bg g.setColor(COL_BG); - g.fillRect(0, 0, width, height); + g.fillRect(navButtonSize, 0, width, height); // title renderTitle(); @@ -262,6 +294,8 @@ public class OptionsOverlay extends OverlayOpsuState { g.fillRect(width - 5, scrollHandler.getPosition() / maxScrollOffset * (height - 45), 5, 45); g.clearClip(); + renderNavigation(g); + // UI UI.getBackButton().draw(g); @@ -274,6 +308,57 @@ public class OptionsOverlay extends OverlayOpsuState { } } + private void renderNavigation(Graphics g) { + navWidth = navButtonSize; + if (navHoverTime >= 600) { + navWidth += navTargetWidth; + } else if (navHoverTime > 300) { + AnimationEquation anim = AnimationEquation.IN_EXPO; + if (displayContainer.mouseX < navWidth) { + anim = AnimationEquation.OUT_EXPO; + } + float progress = anim.calc((navHoverTime - 300f) / 300f); + navWidth += (int) (progress * navTargetWidth); + } + + g.setClip(0, 0, navWidth, height); + g.setColor(COL_NAV_BG); + g.fillRect(0, 0, navWidth, height); + int y = navStartY; + float iconSize = navButtonSize / 2.5f; + float iconPadding = iconSize * 0.75f; + int fontOffsetX = navButtonSize + navIndicatorSize; + int fontOffsetY = (navButtonSize - Fonts.MEDIUM.getLineHeight()) / 2; + for (OptionTab section : sections) { + if (section.icon == null) { + continue; + } + Color iconCol = COL_NAV_INACTIVE; + Color fontCol = COL_NAV_WHITE; + if (section == activeSection) { + iconCol = COL_NAV_WHITE; + g.fillRect(0, y, navWidth, navButtonSize); + g.setColor(COL_NAV_INDICATOR); + g.fillRect(navWidth - navIndicatorSize, y, navIndicatorSize, navButtonSize); + } else if (section == hoveredNavigationEntry) { + iconCol = COL_NAV_WHITE; + } + if (section.filtered) { + iconCol = fontCol = COL_NAV_FILTERED; + if (section == hoveredNavigationEntry) { + iconCol = COL_NAV_FILTERED_HOVERED; + } + } + section.icon.getImage().draw(iconPadding, y + iconPadding, iconSize, iconSize, iconCol); + if (navHoverTime > 0) { + Fonts.MEDIUM.drawString(fontOffsetX, y + fontOffsetY, section.name, fontCol); + } + y += navButtonSize; + } + + g.clearClip(); + } + private void renderIndicator(Graphics g) { g.setColor(COL_INDICATOR); int indicatorPos = this.indicatorPos; @@ -288,7 +373,7 @@ public class OptionsOverlay extends OverlayOpsuState { indicatorPos += AnimationEquation.OUT_BACK.calc((float) indicatorMoveAnimationTime / INDICATORMOVEANIMATIONTIME) * indicatorOffsetToNextPos; } } - g.fillRect(0, indicatorPos - scrollHandler.getPosition(), width, optionHeight); + g.fillRect(navButtonSize, indicatorPos - scrollHandler.getPosition(), width, optionHeight); } private void renderKeyEntry(Graphics g) { @@ -323,12 +408,17 @@ public class OptionsOverlay extends OverlayOpsuState { continue; } int lineStartY = (int) (y + Fonts.LARGE.getLineHeight() * 0.6f); - if (render) { - if (section.options == null) { - FontUtil.drawRightAligned(Fonts.XLARGE, width, -paddingRight, (int) (y + Fonts.XLARGE.getLineHeight() * 0.3f), section.name, COL_CYAN); - } else { - Fonts.MEDIUMBOLD.drawString(paddingTextLeft, lineStartY, section.name, COL_WHITE); + if (section.options == null) { + float previousAlpha = COL_CYAN.a; + if (section != activeSection) { + COL_CYAN.a *= 0.2f; } + FontUtil.drawRightAligned(Fonts.XLARGE, width, -paddingRight, + (int) (y + Fonts.XLARGE.getLineHeight() * 0.3f), section.name.toUpperCase(), + COL_CYAN); + COL_CYAN.a = previousAlpha; + } else { + Fonts.MEDIUMBOLD.drawString(paddingTextLeft, lineStartY, section.name, COL_WHITE); } y += sectionLineHeight; maxScrollOffset += sectionLineHeight; @@ -341,7 +431,8 @@ public class OptionsOverlay extends OverlayOpsuState { if (!option.showCondition() || option.isFiltered()) { continue; } - if (y > -optionHeight || (openDropdownMenu != null && openDropdownMenu.equals(dropdownMenus.get(option)))) { + if (y > -optionHeight || (option instanceof ListOption && openDropdownMenu != null + && openDropdownMenu.equals(dropdownMenus.get(option)))) { renderOption(g, option, y); } y += optionHeight; @@ -478,8 +569,11 @@ public class OptionsOverlay extends OverlayOpsuState { } private void renderTitle() { - FontUtil.drawCentered(Fonts.LARGE, width, 0, textOptionsY - scrollHandler.getIntPosition(), "Options", COL_WHITE); - FontUtil.drawCentered(Fonts.MEDIUM, width, 0, textChangeY - scrollHandler.getIntPosition(), "Change the way opsu! behaves", COL_PINK); + int textWidth = width - navButtonSize; + FontUtil.drawCentered(Fonts.LARGE, textWidth, navButtonSize, + textOptionsY - scrollHandler.getIntPosition(), "Options", COL_WHITE); + FontUtil.drawCentered(Fonts.MEDIUM, textWidth, navButtonSize, + textChangeY - scrollHandler.getIntPosition(), "Change the way opsu! behaves", COL_PINK); } private void renderSearch(Graphics g) { @@ -487,15 +581,34 @@ public class OptionsOverlay extends OverlayOpsuState { if (scrollHandler.getIntPosition() > posSearchY) { ypos = textSearchYOffset; g.setColor(COL_BG); - g.fillRect(0, 0, width, textSearchYOffset * 2 + Fonts.LARGE.getLineHeight()); + g.fillRect(navButtonSize, 0, width, textSearchYOffset * 2 + Fonts.LARGE.getLineHeight()); + } + Color searchCol = COL_WHITE; + float invalidProgress = 0f; + if (invalidSearchAnimationProgress > 0) { + invalidProgress = 1f - (float) invalidSearchAnimationProgress / INVALID_SEARCH_ANIMATION_TIME; + searchCol = new Color(0f, 0f, 0f, searchCol.a); + searchCol.r = COL_PINK.r + (1f - COL_PINK.r) * invalidProgress; + searchCol.g = COL_PINK.g + (1f - COL_PINK.g) * invalidProgress; + searchCol.b = COL_PINK.b + (1f - COL_PINK.b) * invalidProgress; + invalidProgress = 1f - invalidProgress; } String searchText = "Type to search!"; if (lastSearchText.length() > 0) { searchText = lastSearchText; } - FontUtil.drawCentered(Fonts.LARGE, width, 0, ypos, searchText, COL_WHITE); - int imgPosX = (width - Fonts.LARGE.getWidth(searchText)) / 2 - searchImg.getWidth() - 10; - searchImg.draw(imgPosX, ypos + Fonts.LARGE.getLineHeight() * 0.25f, COL_WHITE); + int textWidth = width - navButtonSize; + if (invalidSearchAnimationProgress > 0) { + g.rotate(navButtonSize + textWidth / 2, ypos, invalidProgress * invalidSearchTextRotation); + } + FontUtil.drawCentered(Fonts.LARGE, textWidth, navButtonSize, ypos, searchText, searchCol); + g.resetTransform(); + int imgPosX = navButtonSize + (textWidth - Fonts.LARGE.getWidth(searchText)) / 2 - searchImg.getWidth() - 10; + if (invalidSearchAnimationProgress > 0) { + g.rotate(imgPosX + searchImg.getWidth() / 2, ypos, invalidProgress * invalidSearchImgRotation); + } + searchImg.draw(imgPosX, ypos + Fonts.LARGE.getLineHeight() * 0.25f, searchCol); + g.resetTransform(); } @Override @@ -509,6 +622,7 @@ public class OptionsOverlay extends OverlayOpsuState { @Override public void show() { + navHoverTime = 0; indicatorPos = -optionHeight; indicatorOffsetToNextPos = 0; indicatorMoveAnimationTime = 0; @@ -525,7 +639,9 @@ public class OptionsOverlay extends OverlayOpsuState { int mouseY = displayContainer.mouseY; int delta = displayContainer.renderDelta; + int prevscrollpos = scrollHandler.getIntPosition(); scrollHandler.update(delta); + boolean scrollPositionChanged = prevscrollpos != scrollHandler.getIntPosition(); if (openDropdownMenu == null) { for (DropdownMenu menu : visibleDropdownMenus) { @@ -535,6 +651,10 @@ public class OptionsOverlay extends OverlayOpsuState { openDropdownMenu.updateHover(mouseX, mouseY); } + if (invalidSearchAnimationProgress > 0) { + invalidSearchAnimationProgress -= delta; + } + updateShowHideAnimation(delta); if (animationtime <= 0) { active = false; @@ -545,10 +665,21 @@ public class OptionsOverlay extends OverlayOpsuState { sliderSoundDelay -= delta; } - if (mouseX - prevMouseX == 0 && mouseY - prevMouseY == 0) { + if (mouseX < navWidth) { + if (navHoverTime < 600) { + navHoverTime += delta; + } + } else if (navHoverTime > 0) { + navHoverTime -= delta; + } + navHoverTime = Utils.clamp(navHoverTime, 0, 600); + + if (!scrollPositionChanged && (mouseX - prevMouseX == 0 && mouseY - prevMouseY == 0)) { updateIndicatorAlpha(); return; } + updateActiveSection(); + updateHoverNavigation(mouseX, mouseY); prevMouseX = mouseX; prevMouseY = mouseY; updateHoverOption(mouseX, mouseY); @@ -564,6 +695,24 @@ public class OptionsOverlay extends OverlayOpsuState { } } + private void updateHoverNavigation(int mouseX, int mouseY) { + hoveredNavigationEntry = null; + if (mouseX >= navWidth) { + return; + } + int y = navStartY; + for (OptionTab section : sections) { + if (section.options != null) { + continue; + } + int nextY = y + navButtonSize; + if (y <= mouseY && mouseY < nextY) { + hoveredNavigationEntry = section; + } + y = nextY; + } + } + private void updateIndicatorAlpha() { if (hoverOption == null) { if (indicatorHideAnimationTime < INDICATORHIDEANIMATIONTIME) { @@ -571,50 +720,59 @@ public class OptionsOverlay extends OverlayOpsuState { if (indicatorHideAnimationTime > INDICATORHIDEANIMATIONTIME) { indicatorHideAnimationTime = INDICATORHIDEANIMATIONTIME; } - float progress = AnimationEquation.IN_CUBIC.calc((float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME); - COL_INDICATOR.a = (1f - progress) * INDICATOR_ALPHA; + float progress = AnimationEquation.IN_CUBIC.calc((float) indicatorHideAnimationTime / + INDICATORHIDEANIMATIONTIME); + COL_INDICATOR.a = (1f - progress) * INDICATOR_ALPHA * showHideProgress; } } else if (indicatorHideAnimationTime > 0) { indicatorHideAnimationTime -= displayContainer.renderDelta * 3; if (indicatorHideAnimationTime < 0) { indicatorHideAnimationTime = 0; } - COL_INDICATOR.a = (1f - (float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME) * INDICATOR_ALPHA; + COL_INDICATOR.a = (1f - (float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME) * + INDICATOR_ALPHA * showHideProgress; } } private void updateShowHideAnimation(int delta) { if (acceptInput && animationtime >= SHOWANIMATIONTIME) { // animation already finished - width = finalWidth; + width = targetWidth; + showHideProgress = 1f; return; } optionWidth = width - optionStartX - paddingRight; + // navigation elemenst fade out with a different animation + float navProgress; // if acceptInput is false, it means that we're currently hiding ourselves - float progress; if (acceptInput) { animationtime += delta; if (animationtime >= SHOWANIMATIONTIME) { animationtime = SHOWANIMATIONTIME; } - progress = AnimationEquation.OUT_EXPO.calc((float) animationtime / SHOWANIMATIONTIME); + showHideProgress = (float) animationtime / SHOWANIMATIONTIME; + navProgress = Utils.clamp(showHideProgress * 10f, 0f, 1f); + showHideProgress = AnimationEquation.OUT_EXPO.calc(showHideProgress); } else { animationtime -= delta; if (animationtime < 0) { animationtime = 0; } - progress = hideAnimationStartProgress * AnimationEquation.IN_EXPO.calc((float) animationtime / hideAnimationTime); + showHideProgress = (float) animationtime / hideAnimationTime; + navProgress = hideAnimationStartProgress * AnimationEquation.IN_CIRC.calc(showHideProgress); + showHideProgress = hideAnimationStartProgress * AnimationEquation.IN_EXPO.calc(showHideProgress); } - width = (int) (progress * finalWidth); - COL_BG.a = BG_ALPHA * progress; - COL_WHITE.a = progress; - COL_PINK.a = progress; - COL_CYAN.a = progress; - COL_GREY.a = progress * LINEALPHA; - COL_BLUE.a = progress; - COL_COMBOBOX_HOVER.a = progress; - COL_INDICATOR.a = progress * (1f - (float) indicatorHideAnimationTime / INDICATORHIDEANIMATIONTIME) * INDICATOR_ALPHA; + width = navButtonSize + (int) (showHideProgress * (targetWidth - navButtonSize)); + COL_NAV_FILTERED.a = COL_NAV_INACTIVE.a = COL_NAV_FILTERED_HOVERED.a = COL_NAV_INDICATOR.a = + COL_NAV_WHITE.a = COL_NAV_BG.a = navProgress; + COL_BG.a = BG_ALPHA * showHideProgress; + COL_WHITE.a = showHideProgress; + COL_PINK.a = showHideProgress; + COL_CYAN.a = showHideProgress; + COL_GREY.a = showHideProgress * LINEALPHA; + COL_BLUE.a = showHideProgress; + COL_COMBOBOX_HOVER.a = showHideProgress; } @Override @@ -652,15 +810,17 @@ public class OptionsOverlay extends OverlayOpsuState { isAdjustingSlider = false; sliderOptionLength = 0; - if (openDropdownMenu != null) { - openDropdownMenu.mouseReleased(button); - updateHoverOption(x, y); - return true; - } else { - for (DropdownMenu menu : visibleDropdownMenus) { - menu.mouseReleased(button); - if (menu.isOpen()) { - return true; + if (x > navWidth) { + if (openDropdownMenu != null) { + openDropdownMenu.mouseReleased(button); + updateHoverOption(x, y); + return true; + } else { + for (DropdownMenu menu : visibleDropdownMenus) { + menu.mouseReleased(button); + if (menu.isOpen()) { + return true; + } } } } @@ -672,7 +832,7 @@ public class OptionsOverlay extends OverlayOpsuState { return true; } - if (x > finalWidth) { + if (x > targetWidth) { return false; } @@ -687,10 +847,33 @@ public class OptionsOverlay extends OverlayOpsuState { } else if (hoverOption == OPTION_KEY_LEFT) { keyEntryLeft = true; } else if (hoverOption == OPTION_KEY_RIGHT) { - keyEntryLeft = true; + keyEntryRight = true; } } + if (hoveredNavigationEntry != null && !hoveredNavigationEntry.filtered) { + int sectionPosition = 0; + for (OptionTab section : sections) { + if (section == hoveredNavigationEntry) { + break; + } + if (section.filtered) { + continue; + } + sectionPosition += sectionLineHeight; + if (section.options == null) { + continue; + } + for (Option option : section.options) { + if (!option.isFiltered() && option.showCondition()) { + sectionPosition += optionHeight; + } + } + } + sectionPosition = Utils.clamp(sectionPosition, (int) scrollHandler.min, (int) scrollHandler.max); + scrollHandler.scrollToPosition(sectionPosition); + } + if (UI.getBackButton().contains(x, y)){ hide(); if (listener != null) { @@ -716,7 +899,6 @@ public class OptionsOverlay extends OverlayOpsuState { if (!isAdjustingSlider) { scrollHandler.scrollOffset(-delta); } - updateHoverOption(prevMouseX, prevMouseY); return true; } @@ -738,7 +920,7 @@ public class OptionsOverlay extends OverlayOpsuState { return true; } - if (key == Input.KEY_ESCAPE) { + if (key == Keyboard.KEY_ESCAPE) { if (openDropdownMenu != null) { openDropdownMenu.keyPressed(key, c); return true; @@ -757,8 +939,23 @@ public class OptionsOverlay extends OverlayOpsuState { searchField.keyPressed(key, c); if (!searchField.getText().equals(lastSearchText)) { - lastSearchText = searchField.getText().toLowerCase(); - updateSearch(); + String newSearchText = searchField.getText().toLowerCase(); + if (!hasSearchResults(newSearchText)) { + searchField.setText(lastSearchText); + invalidSearchAnimationProgress = INVALID_SEARCH_ANIMATION_TIME; + Random rand = new Random(); + invalidSearchImgRotation = 10 + rand.nextInt(10); + invalidSearchTextRotation = 10 + rand.nextInt(10); + if (rand.nextBoolean()) { + invalidSearchImgRotation = -invalidSearchImgRotation; + } + if (rand.nextBoolean()) { + invalidSearchTextRotation = -invalidSearchTextRotation; + } + } else { + lastSearchText = newSearchText; + updateSearch(); + } } return true; @@ -775,7 +972,37 @@ public class OptionsOverlay extends OverlayOpsuState { o.setValue(Utils.clamp(value, o.min, o.max)); } + private void updateActiveSection() { + // active section is the one that is visible in the top half of the screen + activeSection = sections[0]; + int virtualY = optionStartY; + for (OptionTab section : sections) { + if (section.filtered) { + continue; + } + virtualY += sectionLineHeight; + if (virtualY > scrollHandler.getPosition() + height / 2) { + return; + } + if (section.options == null) { + activeSection = section; + continue; + } + for (int optionIndex = 0; optionIndex < section.options.length; optionIndex++) { + Option option = section.options[optionIndex]; + if (option.isFiltered() || !option.showCondition()) { + continue; + } + virtualY += optionHeight; + } + } + } + private void updateHoverOption(int mouseX, int mouseY) { + if (mouseX < navWidth) { + hoverOption = null; + return; + } if (openDropdownMenu != null || keyEntryLeft || keyEntryRight) { return; } @@ -842,7 +1069,7 @@ public class OptionsOverlay extends OverlayOpsuState { if (section.options == null) { lastBigSectionMatches = sectionMatches; lastBigSection = section; - section.filtered = true; + section.filtered = !lastBigSectionMatches; continue; } section.filtered = true; @@ -854,11 +1081,37 @@ public class OptionsOverlay extends OverlayOpsuState { } if (!option.filter(lastSearchText)) { section.filtered = false; + //noinspection ConstantConditions lastBigSection.filtered = false; } } } updateHoverOption(prevMouseX, prevMouseY); + updateActiveSection(); + if (openDropdownMenu != null) { + openDropdownMenu.reset(); + openDropdownMenu = null; + } + } + + private boolean hasSearchResults(String searchText) { + for (OptionTab section : sections) { + if (section.name.toLowerCase().contains(searchText)) { + return true; + } + if (section.options == null) { + continue; + } + for (Option option : section.options) { + boolean wasFiltered = option.isFiltered(); + boolean isFiltered = option.filter(searchText); + option.setFiltered(wasFiltered); + if (!isFiltered) { + return true; + } + } + } + return false; } public interface Listener { diff --git a/src/yugecin/opsudance/ui/StoryboardOverlay.java b/src/yugecin/opsudance/ui/StoryboardOverlay.java index 14fb1dd6..a9f540ce 100644 --- a/src/yugecin/opsudance/ui/StoryboardOverlay.java +++ b/src/yugecin/opsudance/ui/StoryboardOverlay.java @@ -25,7 +25,6 @@ import yugecin.opsudance.options.OptionGroups; import itdelatrisu.opsu.ui.Fonts; import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; -import org.newdawn.slick.Input; import yugecin.opsudance.ObjectColorOverrides; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.state.OverlayOpsuState; @@ -34,6 +33,7 @@ import yugecin.opsudance.sbv2.MoveStoryboard; import java.util.*; +import static org.lwjgl.input.Keyboard.*; import static yugecin.opsudance.options.Options.*; @SuppressWarnings("unchecked") @@ -108,7 +108,7 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla @Override public boolean onKeyPressed(int key, char c) { - if (key == Input.KEY_C) { + if (key == KEY_C) { if (speed > 0) { speed -= 1; } @@ -117,24 +117,24 @@ public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverla } else { MusicController.setPitch(speed / 10f); } - } else if (key == Input.KEY_V && speed < 21) { + } else if (key == KEY_V && speed < 21) { if (speed == 0) { MusicController.resume(); } speed += 1; MusicController.setPitch(speed / 10f); - } else if (key == Input.KEY_H) { + } else if (key == KEY_H) { hide = !hide; - } else if (key == Input.KEY_N) { + } else if (key == KEY_N) { optionsOverlay.show(); if (speed != 0) { MusicController.pause(); } - } else if (key == Input.KEY_J && index > 0) { + } else if (key == KEY_J && index > 0) { index--; goBackOneSBIndex(); setMusicPosition(); - } else if (key == Input.KEY_K && index < gameObjects.length - 1) { + } else if (key == KEY_K && index < gameObjects.length - 1) { index++; updateIndex(index); setMusicPosition(); diff --git a/src/yugecin/opsudance/utils/GLHelper.java b/src/yugecin/opsudance/utils/GLHelper.java index 66db778b..c43de64b 100644 --- a/src/yugecin/opsudance/utils/GLHelper.java +++ b/src/yugecin/opsudance/utils/GLHelper.java @@ -28,11 +28,12 @@ import org.newdawn.slick.opengl.LoadableImageData; import org.newdawn.slick.opengl.TGAImageData; import org.newdawn.slick.util.Log; import org.newdawn.slick.util.ResourceLoader; -import yugecin.opsudance.core.errorhandling.ErrorHandler; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import static yugecin.opsudance.core.errorhandling.ErrorHandler.*; + public class GLHelper { /** @@ -96,7 +97,7 @@ public class GLHelper { IntBuffer tmp = BufferUtils.createIntBuffer(min * min); Mouse.setNativeCursor(new Cursor(min, min, min / 2, min / 2, 1, tmp, null)); } catch (LWJGLException e) { - ErrorHandler.error("Cannot hide native cursor", e).show(); + explode("Cannot hide native cursor", e, DEFAULT_OPTIONS); } } @@ -104,7 +105,7 @@ public class GLHelper { try { Mouse.setNativeCursor(null); } catch (LWJGLException e) { - ErrorHandler.error("Cannot show native cursor", e).show(); + explode("Cannot show native cursor", e, DEFAULT_OPTIONS); } } diff --git a/src/yugecin/opsudance/utils/ManifestWrapper.java b/src/yugecin/opsudance/utils/ManifestWrapper.java new file mode 100644 index 00000000..b02804c8 --- /dev/null +++ b/src/yugecin/opsudance/utils/ManifestWrapper.java @@ -0,0 +1,54 @@ +/* + * 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 . + */ +package yugecin.opsudance.utils; + +import yugecin.opsudance.core.NotNull; +import yugecin.opsudance.core.Nullable; + +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +public class ManifestWrapper { + + @Nullable + public final Manifest manifest; + + public ManifestWrapper(@Nullable Manifest manifest) { + this.manifest = manifest; + } + + /** + * @param attribute attribute in jarfile or null for default attributes + */ + public String valueOrDefault(@Nullable String attribute, @NotNull String key, @Nullable String dfault) { + if (manifest == null) { + return dfault; + } + Attributes attributes = + attribute == null ? manifest.getMainAttributes() : manifest.getAttributes(attribute); + if (attributes == null) { + return dfault; + } + String val = attributes.getValue(key); + if (val == null) { + return dfault; + } + return val; + } + +} diff --git a/src/yugecin/opsudance/utils/MiscUtils.java b/src/yugecin/opsudance/utils/MiscUtils.java index c66e5801..36344297 100644 --- a/src/yugecin/opsudance/utils/MiscUtils.java +++ b/src/yugecin/opsudance/utils/MiscUtils.java @@ -17,9 +17,9 @@ */ package yugecin.opsudance.utils; -import itdelatrisu.opsu.Options; import org.newdawn.slick.util.Log; import org.newdawn.slick.util.ResourceLoader; +import yugecin.opsudance.core.Constants; import java.io.IOException; import java.util.Properties; @@ -31,7 +31,7 @@ public class MiscUtils { public Properties get() { Properties props = new Properties(); try { - props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE)); + props.load(ResourceLoader.getResourceAsStream(Constants.VERSION_FILE)); } catch (IOException e) { Log.error("Could not read version file", e); } diff --git a/src/yugecin/opsudance/utils/SyntacticSugar.java b/src/yugecin/opsudance/utils/SyntacticSugar.java new file mode 100644 index 00000000..6368086a --- /dev/null +++ b/src/yugecin/opsudance/utils/SyntacticSugar.java @@ -0,0 +1,34 @@ +/* + * 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 . + */ +package yugecin.opsudance.utils; + +import java.io.Closeable; +import java.io.IOException; + +public class SyntacticSugar { + + /** + * close the closeable and swallow exceptions, if any + */ + public static void closeAndSwallow(Closeable closable) { + try { + closable.close(); + } catch (IOException ignored) {} + } + +}