From 5e09a1d24a2ccf59d1c331b8e448a1214afa0531 Mon Sep 17 00:00:00 2001 From: yugecin Date: Tue, 17 Jan 2017 22:26:19 +0100 Subject: [PATCH 01/38] attempt to correct the fps counter target values --- .../opsudance/core/state/specialstates/FpsRenderState.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java b/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java index 89055d22..d8a52f37 100644 --- a/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java +++ b/src/yugecin/opsudance/core/state/specialstates/FpsRenderState.java @@ -43,16 +43,16 @@ public class FpsRenderState implements EventListener { public void render(Graphics g) { int x = this.x; - int target = displayContainer.targetRenderInterval - (displayContainer.targetUpdateInterval % displayContainer.targetRenderInterval); + int target = displayContainer.targetRenderInterval + (displayContainer.targetUpdateInterval % displayContainer.targetRenderInterval); x = drawText(g, getColor(target, displayContainer.renderDelta), (1000 / displayContainer.renderDelta) + " fps", x, this.y); drawText(g, getColor(displayContainer.targetUpdateInterval, displayContainer.delta), (1000 / displayContainer.delta) + " ups", x, this.y); } private Color getColor(int targetValue, int realValue) { - if (realValue >= targetValue) { + if (realValue <= targetValue) { return GREEN; } - if (realValue >= targetValue * 0.9f) { + if (realValue <= targetValue * 1.15f) { return ORANGE; } return DARKORANGE; From 8b226f3afc463f68864531476065d4e50bb2f194 Mon Sep 17 00:00:00 2001 From: yugecin Date: Tue, 17 Jan 2017 23:18:12 +0100 Subject: [PATCH 02/38] working splash state --- src/itdelatrisu/opsu/Opsu.java | 4 +- src/itdelatrisu/opsu/Options.java | 19 ++--- src/itdelatrisu/opsu/Utils.java | 45 ++++-------- .../opsu/audio/MusicController.java | 9 +++ src/itdelatrisu/opsu/states/Splash.java | 51 ++++++------- src/itdelatrisu/opsu/ui/Cursor.java | 21 +++--- src/itdelatrisu/opsu/ui/UI.java | 71 ++++++------------- src/yugecin/opsudance/OpsuDance.java | 4 +- .../opsudance/core/DisplayContainer.java | 7 +- .../core/inject/OpsuDanceInjector.java | 3 + .../opsudance/core/state/BaseOpsuState.java | 13 ++++ 11 files changed, 114 insertions(+), 133 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 485210a9..29f7c4ee 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -85,7 +85,7 @@ public class Opsu extends StateBasedGame { @Override public void initStatesList(GameContainer container) throws SlickException { - addState(new Splash(STATE_SPLASH)); + //addState(new Splash(STATE_SPLASH)); addState(new MainMenu(STATE_MAINMENU)); addState(new ButtonMenu(STATE_BUTTONMENU)); addState(new SongMenu(STATE_SONGMENU)); @@ -206,7 +206,7 @@ public class Opsu extends StateBasedGame { Container app = new Container(opsu); // basic game settings - Options.setDisplayMode(app); + //Options.setDisplayMode(app); String[] icons = { "icon16.png", "icon32.png" }; try { app.setIcons(icons); diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index 19db44b0..dcf2da73 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -59,6 +59,8 @@ import com.sun.jna.platform.win32.Advapi32Util; import com.sun.jna.platform.win32.Win32Exception; import com.sun.jna.platform.win32.WinReg; import yugecin.opsudance.*; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.movers.factories.ExgonMoverFactory; import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory; import yugecin.opsudance.movers.slidermovers.DefaultSliderMoverController; @@ -1294,10 +1296,9 @@ public class Options { /** * Sets the master volume level (if within valid range). - * @param container the game container * @param volume the volume [0, 1] */ - public static void setMasterVolume(GameContainer container, float volume) { + public static void setMasterVolume(float volume) { if (volume >= 0f && volume <= 1f) { GameOption.MASTER_VOLUME.setValue((int) (volume * 100f)); MusicController.setVolume(getMasterVolume() * getMusicVolume()); @@ -1346,11 +1347,10 @@ public class Options { *

* If the configured resolution is larger than the screen size, the smallest * available resolution will be used. - * @param app the game container */ - public static void setDisplayMode(Container app) { - int screenWidth = app.getScreenWidth(); - int screenHeight = app.getScreenHeight(); + public static void setDisplayMode(DisplayContainer container) { + int screenWidth = container.nativeDisplayMode.getWidth(); + int screenHeight = container.nativeDisplayMode.getHeight(); resolutions[0] = screenWidth + "x" + screenHeight; if (resolutionIdx < 0 || resolutionIdx > resolutions.length) { @@ -1370,9 +1370,10 @@ public class Options { } try { - app.setDisplayMode(width, height, isFullscreen()); - } catch (SlickException e) { - ErrorHandler.error("Failed to set display mode.", e, true); + container.setDisplayMode(width, height, isFullscreen()); + } catch (Exception e) { + container.eventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED)); + Log.error("Failed to set display mode.", e); } if (!isFullscreen()) { diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index 930b4eac..a66e320d 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -18,6 +18,7 @@ package itdelatrisu.opsu; +import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.beatmap.HitObject; @@ -71,6 +72,7 @@ import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.util.Log; import com.sun.jna.platform.FileUtils; +import yugecin.opsudance.core.DisplayContainer; /** * Contains miscellaneous utilities. @@ -89,40 +91,18 @@ public class Utils { Arrays.sort(illegalChars); } - // game-related variables - private static Input input; - // This class should not be instantiated. private Utils() {} /** * Initializes game settings and class data. - * @param container the game container - * @param game the game object */ - public static void init(GameContainer container, StateBasedGame game) { - input = container.getInput(); - int width = container.getWidth(); - int height = container.getHeight(); + public static void init(DisplayContainer displayContainer) { + // TODO clean this up // game settings - container.setTargetFrameRate(Options.getTargetFPS()); - container.setVSync(Options.getTargetFPS() == 60); - container.setMusicVolume(Options.getMusicVolume() * Options.getMasterVolume()); - container.setShowFPS(false); - container.getInput().enableKeyRepeat(); - container.setAlwaysRender(true); - container.setUpdateOnlyWhenVisible(false); - - // calculate UI scale - GameImage.init(width, height); - - // create fonts - try { - Fonts.init(); - } catch (Exception e) { - ErrorHandler.error("Failed to load fonts.", e, true); - } + displayContainer.setFPS(Options.getTargetFPS()); // TODO move this elsewhere + MusicController.setMusicVolume(Options.getMusicVolume() * Options.getMasterVolume()); // load skin Options.loadSkin(); @@ -134,19 +114,19 @@ public class Utils { } // initialize game mods - GameMod.init(width, height); + GameMod.init(displayContainer.width, displayContainer.height); // initialize playback buttons - PlaybackSpeed.init(width, height); + PlaybackSpeed.init(displayContainer.width, displayContainer.height); // initialize hit objects - HitObject.init(width, height); + HitObject.init(displayContainer.width, displayContainer.height); // initialize download nodes - DownloadNode.init(width, height); + DownloadNode.init(displayContainer.width, displayContainer.height); // initialize UI components - UI.init(container, game); + UI.init(displayContainer); } /** @@ -246,12 +226,15 @@ 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; } /** diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index c5e24e7b..ba4ec00a 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -578,4 +578,13 @@ public class MusicController { ErrorHandler.error("Failed to destroy OpenAL.", e, true); } } + + /** + * Set the default volume for music + * @param volume the new default value for music volume + */ + public static void setMusicVolume(float volume) { + SoundStore.get().setMusicVolume(volume); + } + } diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java index a0ea9963..03154422 100644 --- a/src/itdelatrisu/opsu/states/Splash.java +++ b/src/itdelatrisu/opsu/states/Splash.java @@ -19,7 +19,6 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GameImage; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.audio.MusicController; @@ -36,19 +35,18 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation; import java.io.File; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.state.BaseOpsuState; /** * "Splash Screen" state. *

* Loads game resources and enters "Main Menu" state. */ -public class Splash extends BasicGameState { +public class Splash extends BaseOpsuState { + /** Minimum time, in milliseconds, to display the splash screen (and fade in the logo). */ private static final int MIN_SPLASH_TIME = 400; @@ -71,18 +69,15 @@ public class Splash extends BasicGameState { private AnimatedValue logoAlpha; // game-related variables - private final int state; - private GameContainer container; private boolean init = false; - public Splash(int state) { - this.state = state; + public Splash(DisplayContainer displayContainer) { + super(displayContainer); } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; + protected void revalidate() { + super.revalidate(); // check if skin changed if (Options.getSkin() != null) @@ -92,7 +87,7 @@ public class Splash extends BasicGameState { this.watchServiceChange = Options.isWatchServiceEnabled() && BeatmapWatchService.get() == null; // load Utils class first (needed in other 'init' methods) - Utils.init(container, game); + Utils.init(displayContainer); // fade in logo this.logoAlpha = new AnimatedValue(MIN_SPLASH_TIME, 0f, 1f, AnimationEquation.LINEAR); @@ -100,16 +95,14 @@ public class Splash extends BasicGameState { } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { + public void render(Graphics g) { g.setBackground(Color.black); - GameImage.MENU_LOGO.getImage().drawCentered(container.getWidth() / 2, container.getHeight() / 2); + GameImage.MENU_LOGO.getImage().drawCentered(displayContainer.width / 2, displayContainer.height / 2); UI.drawLoadingProgress(g); } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void update() { if (!init) { init = true; @@ -165,7 +158,7 @@ public class Splash extends BasicGameState { } // fade in logo - if (logoAlpha.update(delta)) + if (logoAlpha.update(displayContainer.delta)) GameImage.MENU_LOGO.getImage().setAlpha(logoAlpha.getValue()); // change states when loading complete @@ -176,30 +169,32 @@ public class Splash extends BasicGameState { if (Options.isThemeSongEnabled()) MusicController.playThemeSong(); else - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); + //((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); + System.out.println(("todo")); + // TODO } // play the theme song else MusicController.playThemeSong(); - game.enterState(Opsu.STATE_MAINMENU); + //game.enterState(Opsu.STATE_MAINMENU); + } } @Override - public int getID() { return state; } - - @Override - public void keyPressed(int key, char c) { + public boolean keyPressed(int key, char c) { if (key == Input.KEY_ESCAPE) { // close program - if (++escapeCount >= 3) - container.exit(); + if (++escapeCount >= 3) System.out.println("hi"); + //container.exit(); // TODO // stop parsing beatmaps by sending interrupt to BeatmapParser else if (thread != null) thread.interrupt(); + return true; } + return false; } } diff --git a/src/itdelatrisu/opsu/ui/Cursor.java b/src/itdelatrisu/opsu/ui/Cursor.java index 7ad8171d..c3025ab7 100644 --- a/src/itdelatrisu/opsu/ui/Cursor.java +++ b/src/itdelatrisu/opsu/ui/Cursor.java @@ -36,6 +36,7 @@ import org.lwjgl.LWJGLException; import org.newdawn.slick.*; import org.newdawn.slick.state.StateBasedGame; import yugecin.opsudance.Dancer; +import yugecin.opsudance.core.DisplayContainer; /** * Updates and draws the cursor. @@ -68,9 +69,7 @@ public class Cursor { private boolean newStyle; // game-related variables - private static GameContainer container; - private static StateBasedGame game; - private static Input input; + private static DisplayContainer displayContainer; public static Color lastObjColor = Color.white; public static Color lastMirroredObjColor = Color.white; @@ -82,13 +81,9 @@ public class Cursor { /** * Initializes the class. - * @param container the game container - * @param game the game object */ - public static void init(GameContainer container, StateBasedGame game) { - Cursor.container = container; - Cursor.game = game; - Cursor.input = container.getInput(); + public static void init(DisplayContainer displayContainer) { + Cursor.displayContainer = displayContainer; // create empty cursor to simulate hiding the cursor try { @@ -116,12 +111,14 @@ public class Cursor { * Draws the cursor. */ public void draw() { + /* int state = game.getCurrentStateID(); boolean mousePressed = (((state == Opsu.STATE_GAME || state == Opsu.STATE_GAMEPAUSEMENU) && Utils.isGameKeyPressed()) || ((input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) && !(state == Opsu.STATE_GAME && Options.isMouseDisabled()))); draw(input.getMouseX(), input.getMouseY(), mousePressed); + */ } /** @@ -215,7 +212,7 @@ public class Cursor { public void setCursorPosition(int mouseX, int mouseY) { // TODO: use an image buffer int removeCount = 0; - float FPSmod = Math.max(container.getFPS(), 1) / 30f; + float FPSmod = Math.max(1000 / displayContainer.renderDelta, 1) / 30f; // TODO if (newStyle) { // new style: add all points between cursor movements if ((lastPosition.x == 0 && lastPosition.y == 0) || !addCursorPoints(lastPosition.x, lastPosition.y, mouseX, mouseY)) { @@ -349,11 +346,13 @@ public class Cursor { */ public void hide() { if (emptyCursor != null) { + /* try { container.setMouseCursor(emptyCursor, 0, 0); } catch (SlickException e) { ErrorHandler.error("Failed to hide the cursor.", e, true); } + */ } } @@ -361,6 +360,6 @@ public class Cursor { * Unhides the cursor. */ public void show() { - container.setDefaultMouseCursor(); + //container.setDefaultMouseCursor(); } } diff --git a/src/itdelatrisu/opsu/ui/UI.java b/src/itdelatrisu/opsu/ui/UI.java index b58b7002..6fe0e50b 100644 --- a/src/itdelatrisu/opsu/ui/UI.java +++ b/src/itdelatrisu/opsu/ui/UI.java @@ -39,6 +39,7 @@ import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; import org.newdawn.slick.state.StateBasedGame; +import yugecin.opsudance.core.DisplayContainer; /** * Draws common UI components. @@ -75,7 +76,7 @@ public class UI { private static AnimatedValue tooltipAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR); // game-related variables - private static GameContainer container; + private static DisplayContainer displayContainer; private static Input input; // This class should not be instantiated. @@ -83,24 +84,21 @@ public class UI { /** * Initializes UI data. - * @param container the game container - * @param game the game object */ - public static void init(GameContainer container, StateBasedGame game) { - UI.container = container; - UI.input = container.getInput(); + public static void init(DisplayContainer displayContainer) { + UI.displayContainer = displayContainer; // initialize cursor - Cursor.init(container, game); + Cursor.init(displayContainer); cursor.hide(); // back button if (GameImage.MENU_BACK.getImages() != null) { Animation back = GameImage.MENU_BACK.getAnimation(120); - backButton = new MenuButton(back, back.getWidth() / 2f, container.getHeight() - (back.getHeight() / 2f)); + backButton = new MenuButton(back, back.getWidth() / 2f, displayContainer.height - (back.getHeight() / 2f)); } else { Image back = GameImage.MENU_BACK.getImage(); - backButton = new MenuButton(back, back.getWidth() / 2f, container.getHeight() - (back.getHeight() / 2f)); + backButton = new MenuButton(back, back.getWidth() / 2f, displayContainer.height - (back.getHeight() / 2f)); } backButton.setHoverAnimationDuration(350); backButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK); @@ -125,7 +123,6 @@ public class UI { public static void draw(Graphics g) { drawBarNotification(g); drawVolume(g); - drawFPS(); cursor.draw(); drawTooltip(g); } @@ -140,7 +137,6 @@ public class UI { public static void draw(Graphics g, int mouseX, int mouseY, boolean mousePressed) { drawBarNotification(g); drawVolume(g); - drawFPS(); cursor.draw(mouseX, mouseY, mousePressed); drawTooltip(g); } @@ -189,27 +185,6 @@ public class UI { Fonts.MEDIUM.drawString(tabTextX, tabTextY, text, textColor); } - /** - * Draws the FPS at the bottom-right corner of the game container. - * If the option is not activated, this will do nothing. - */ - public static void drawFPS() { - if (!Options.isFPSCounterEnabled()) - return; - - String fps = String.format("%dFPS", container.getFPS()); - Fonts.BOLD.drawString( - container.getWidth() * 0.997f - Fonts.BOLD.getWidth(fps), - container.getHeight() * 0.997f - Fonts.BOLD.getHeight(fps), - Integer.toString(container.getFPS()), Color.white - ); - Fonts.DEFAULT.drawString( - container.getWidth() * 0.997f - Fonts.BOLD.getWidth("FPS"), - container.getHeight() * 0.997f - Fonts.BOLD.getHeight("FPS"), - "FPS", Color.white - ); - } - /** * Draws the volume bar on the middle right-hand side of the game container. * Only draws if the volume has recently been changed using with {@link #changeVolume(int)}. @@ -219,7 +194,6 @@ public class UI { if (volumeDisplay == -1) return; - int width = container.getWidth(), height = container.getHeight(); Image img = GameImage.VOLUME.getImage(); // move image in/out @@ -230,13 +204,13 @@ public class UI { else if (ratio >= 0.9f) xOffset = img.getWidth() * (1 - ((1 - ratio) * 10f)); - img.drawCentered(width - img.getWidth() / 2f + xOffset, height / 2f); + img.drawCentered(displayContainer.width - img.getWidth() / 2f + xOffset, displayContainer.height / 2f); float barHeight = img.getHeight() * 0.9f; float volume = Options.getMasterVolume(); g.setColor(Color.white); g.fillRoundRect( - width - (img.getWidth() * 0.368f) + xOffset, - (height / 2f) - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)), + displayContainer.width - (img.getWidth() * 0.368f) + xOffset, + (displayContainer.height / 2f) - (img.getHeight() * 0.47f) + (barHeight * (1 - volume)), img.getWidth() * 0.15f, barHeight * volume, 3 ); } @@ -260,7 +234,7 @@ public class UI { */ public static void changeVolume(int units) { final float UNIT_OFFSET = 0.05f; - Options.setMasterVolume(container, Utils.clamp(Options.getMasterVolume() + (UNIT_OFFSET * units), 0f, 1f)); + Options.setMasterVolume(Utils.clamp(Options.getMasterVolume() + (UNIT_OFFSET * units), 0f, 1f)); if (volumeDisplay == -1) volumeDisplay = 0; else if (volumeDisplay >= VOLUME_DISPLAY_TIME / 10) @@ -294,8 +268,8 @@ public class UI { return; // draw loading info - float marginX = container.getWidth() * 0.02f, marginY = container.getHeight() * 0.02f; - float lineY = container.getHeight() - marginY; + float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f; + float lineY = displayContainer.height - marginY; int lineOffsetY = Fonts.MEDIUM.getLineHeight(); if (Options.isLoadVerbose()) { // verbose: display percentages and file names @@ -308,7 +282,7 @@ public class UI { Fonts.MEDIUM.drawString(marginX, lineY - (lineOffsetY * 2), text, Color.white); g.setColor(Color.white); g.fillRoundRect(marginX, lineY - (lineOffsetY / 2f), - (container.getWidth() - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4 + (displayContainer.width - (marginX * 2f)) * progress / 100f, lineOffsetY / 4f, 4 ); } } @@ -332,7 +306,7 @@ public class UI { float unitBaseX, float unitBaseY, float unitWidth, float scrollAreaHeight, Color bgColor, Color scrollbarColor, boolean right ) { - float scrollbarWidth = container.getWidth() * 0.00347f; + float scrollbarWidth = displayContainer.width * 0.00347f; float scrollbarHeight = scrollAreaHeight * lengthShown / totalLength; float offsetY = (scrollAreaHeight - scrollbarHeight) * (position / (totalLength - lengthShown)); float scrollbarX = unitBaseX + unitWidth - ((right) ? scrollbarWidth : 0); @@ -368,8 +342,7 @@ public class UI { if (tooltipAlpha.getTime() == 0 || tooltip == null) return; - int containerWidth = container.getWidth(), containerHeight = container.getHeight(); - int margin = containerWidth / 100, textMarginX = 2; + int margin = displayContainer.width / 100, textMarginX = 2; int offset = GameImage.CURSOR_MIDDLE.getImage().getWidth() / 2; int lineHeight = Fonts.SMALL.getLineHeight(); int textWidth = textMarginX * 2, textHeight = lineHeight; @@ -388,12 +361,12 @@ public class UI { // get drawing coordinates int x = input.getMouseX() + offset, y = input.getMouseY() + offset; - if (x + textWidth > containerWidth - margin) - x = containerWidth - margin - textWidth; + if (x + textWidth > displayContainer.width - margin) + x = displayContainer.width - margin - textWidth; else if (x < margin) x = margin; - if (y + textHeight > containerHeight - margin) - y = containerHeight - margin - textHeight; + if (y + textHeight > displayContainer.height - margin) + y = displayContainer.height - margin - textHeight; else if (y < margin) y = margin; @@ -467,13 +440,13 @@ public class UI { float alpha = 1f; if (barNotifTimer >= BAR_NOTIFICATION_TIME * 0.9f) alpha -= 1 - ((BAR_NOTIFICATION_TIME - barNotifTimer) / (BAR_NOTIFICATION_TIME * 0.1f)); - int midX = container.getWidth() / 2, midY = container.getHeight() / 2; + int midX = displayContainer.width / 2, midY = displayContainer.height / 2; float barHeight = Fonts.LARGE.getLineHeight() * (1f + 0.6f * Math.min(barNotifTimer * 15f / BAR_NOTIFICATION_TIME, 1f)); float oldAlphaB = Colors.BLACK_ALPHA.a, oldAlphaW = Colors.WHITE_ALPHA.a; Colors.BLACK_ALPHA.a *= alpha; Colors.WHITE_ALPHA.a = alpha; g.setColor(Colors.BLACK_ALPHA); - g.fillRect(0, midY - barHeight / 2f, container.getWidth(), barHeight); + g.fillRect(0, midY - barHeight / 2f, displayContainer.width, barHeight); Fonts.LARGE.drawString( midX - Fonts.LARGE.getWidth(barNotif) / 2f, midY - Fonts.LARGE.getLineHeight() / 2.2f, diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index d0a9da61..f8c72dfb 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -22,6 +22,7 @@ import itdelatrisu.opsu.Utils; 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; @@ -61,7 +62,8 @@ public class OpsuDance { initUpdater(args); sout("database & updater initialized"); - container.init(EmptyState.class); + //container.init(EmptyState.class); + container.init(Splash.class); } catch (Exception e) { errorAndExit("startup failure", e); } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index f1480557..73941d40 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -18,6 +18,7 @@ package yugecin.opsudance.core; import itdelatrisu.opsu.GameImage; +import itdelatrisu.opsu.Options; import itdelatrisu.opsu.ui.Fonts; import org.lwjgl.LWJGLException; import org.lwjgl.Sys; @@ -29,6 +30,7 @@ import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; import org.newdawn.slick.KeyListener; import org.newdawn.slick.MouseListener; +import org.newdawn.slick.openal.SoundStore; import org.newdawn.slick.opengl.InternalTextureLoader; import org.newdawn.slick.opengl.renderer.Renderer; import org.newdawn.slick.opengl.renderer.SGL; @@ -70,7 +72,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen private OpsuState state; - private final DisplayMode nativeDisplayMode; + public final DisplayMode nativeDisplayMode; private Graphics graphics; private Input input; @@ -204,7 +206,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen Display.setDisplayMode(new DisplayMode(100, 100)); Display.create(); GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" }); - setDisplayMode(800, 600, false); + Options.setDisplayMode(this); sout("GL ready"); glVersion = GL11.glGetString(GL11.GL_VERSION); glVendor = GL11.glGetString(GL11.GL_VENDOR); @@ -257,6 +259,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen graphics.setAntiAlias(false); input = new Input(height); + input.enableKeyRepeat(); input.addKeyListener(this); input.addMouseListener(this); diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 0617463c..bcf806bd 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -17,6 +17,7 @@ */ package yugecin.opsudance.core.inject; +import itdelatrisu.opsu.states.Splash; import yugecin.opsudance.PreStartupInitializer; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.events.EventBus; @@ -50,6 +51,8 @@ public class OpsuDanceInjector extends Injector { bind(EmptyRedState.class).asEagerSingleton(); bind(EmptyState.class).asEagerSingleton(); + + bind(Splash.class).asEagerSingleton(); } } diff --git a/src/yugecin/opsudance/core/state/BaseOpsuState.java b/src/yugecin/opsudance/core/state/BaseOpsuState.java index 3777ba3e..72ebc54b 100644 --- a/src/yugecin/opsudance/core/state/BaseOpsuState.java +++ b/src/yugecin/opsudance/core/state/BaseOpsuState.java @@ -17,6 +17,7 @@ */ package yugecin.opsudance.core.state; +import org.newdawn.slick.Graphics; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.events.EventListener; import yugecin.opsudance.events.ResolutionChangedEvent; @@ -41,6 +42,18 @@ public abstract class BaseOpsuState implements OpsuState, EventListener Date: Tue, 17 Jan 2017 23:44:12 +0100 Subject: [PATCH 03/38] converted mainmenu --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/Options.java | 4 +- src/itdelatrisu/opsu/states/ButtonMenu.java | 3 +- .../opsu/states/DownloadsMenu.java | 3 +- src/itdelatrisu/opsu/states/Game.java | 3 +- .../opsu/states/GamePauseMenu.java | 3 +- src/itdelatrisu/opsu/states/GameRanking.java | 3 +- src/itdelatrisu/opsu/states/MainMenu.java | 191 +++++++++--------- src/itdelatrisu/opsu/states/SongMenu.java | 3 +- src/itdelatrisu/opsu/states/Splash.java | 28 +-- .../core/inject/OpsuDanceInjector.java | 2 + 11 files changed, 125 insertions(+), 120 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 29f7c4ee..0b5bbd7c 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -86,7 +86,7 @@ public class Opsu extends StateBasedGame { @Override public void initStatesList(GameContainer container) throws SlickException { //addState(new Splash(STATE_SPLASH)); - addState(new MainMenu(STATE_MAINMENU)); + //addState(new MainMenu(STATE_MAINMENU)); addState(new ButtonMenu(STATE_BUTTONMENU)); addState(new SongMenu(STATE_SONGMENU)); addState(new Game(STATE_GAME)); diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index dcf2da73..2c033336 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -1281,11 +1281,11 @@ public class Options { /** * Sets the target frame rate to the next available option, and sends a * bar notification about the action. - * @param container the game container */ - public static void setNextFPS(GameContainer container) { + public static void setNextFPS(DisplayContainer displayContainer) { GameOption.TARGET_FPS.clickListItem((targetFPSindex + 1) % targetFPS.length); UI.sendBarNotification(String.format("Frame limiter: %s", GameOption.TARGET_FPS.getValueString())); + displayContainer.setFPS(GameOption.TARGET_FPS.val); } /** diff --git a/src/itdelatrisu/opsu/states/ButtonMenu.java b/src/itdelatrisu/opsu/states/ButtonMenu.java index df9e7db1..ff95558c 100644 --- a/src/itdelatrisu/opsu/states/ButtonMenu.java +++ b/src/itdelatrisu/opsu/states/ButtonMenu.java @@ -705,7 +705,8 @@ public class ButtonMenu extends BasicGameState { menuState.leave(container, game); break; case Input.KEY_F7: - Options.setNextFPS(container); + // TODO + //Options.setNextFPS(displayContainer); break; case Input.KEY_F10: Options.toggleMouseDisabled(); diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index 76fd7376..df4435bc 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -911,7 +911,8 @@ public class DownloadsMenu extends BasicGameState { resetSearchTimer(); break; case Input.KEY_F7: - Options.setNextFPS(container); + // TODO d + //Options.setNextFPS(container); break; case Input.KEY_F10: Options.toggleMouseDisabled(); diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 0c29abae..49bb6c95 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -1198,7 +1198,8 @@ public class Game extends BasicGameState { UI.changeVolume(-1); break; case Input.KEY_F7: - Options.setNextFPS(container); + // TODO d + //Options.setNextFPS(container); break; case Input.KEY_F10: Options.toggleMouseDisabled(); diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java index c3c9dec1..a9d5a7ad 100644 --- a/src/itdelatrisu/opsu/states/GamePauseMenu.java +++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java @@ -143,7 +143,8 @@ public class GamePauseMenu extends BasicGameState { } break; case Input.KEY_F7: - Options.setNextFPS(container); + // TODO d + //Options.setNextFPS(container); break; case Input.KEY_F10: Options.toggleMouseDisabled(); diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index fe7450fd..00f1b48f 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -148,7 +148,8 @@ public class GameRanking extends BasicGameState { returnToSongMenu(); break; case Input.KEY_F7: - Options.setNextFPS(container); + // TODO d + //Options.setNextFPS(container); break; case Input.KEY_F10: Options.toggleMouseDisabled(); diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 93fd15e7..568754f2 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -29,7 +29,6 @@ import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.BeatmapSetList; import itdelatrisu.opsu.beatmap.BeatmapSetNode; -import itdelatrisu.opsu.beatmap.TimingPoint; import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.states.ButtonMenu.MenuState; import itdelatrisu.opsu.ui.*; @@ -43,23 +42,26 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Stack; +import org.lwjgl.opengl.Display; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.state.transition.EasedFadeOutTransition; import org.newdawn.slick.state.transition.FadeInTransition; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.BaseOpsuState; /** * "Main Menu" state. *

* Players are able to enter the song menu or downloads menu from this state. */ -public class MainMenu extends BasicGameState { +public class MainMenu extends BaseOpsuState { + + private final InstanceContainer instanceContainer; + /** Idle time, in milliseconds, before returning the logo to its original position. */ private static final short LOGO_IDLE_DELAY = 10000; @@ -123,40 +125,27 @@ public class MainMenu extends BasicGameState { /** The star fountain. */ private StarFountain starFountain; - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - - public MainMenu(int state) { - this.state = state; + public MainMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + this.instanceContainer = instanceContainer; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); - + protected void revalidate() { programStartTime = System.currentTimeMillis(); - previous = new Stack(); - - int width = container.getWidth(); - int height = container.getHeight(); + previous = new Stack<>(); // initialize menu buttons Image logoImg = GameImage.MENU_LOGO.getImage(); Image playImg = GameImage.MENU_PLAY.getImage(); Image exitImg = GameImage.MENU_EXIT.getImage(); float exitOffset = (playImg.getWidth() - exitImg.getWidth()) / 3f; - logo = new MenuButton(logoImg, width / 2f, height / 2f); + logo = new MenuButton(logoImg, displayContainer.width / 2f, displayContainer.height / 2f); playButton = new MenuButton(playImg, - width * 0.75f, (height / 2) - (logoImg.getHeight() / 5f) + displayContainer.width * 0.75f, (displayContainer.height / 2) - (logoImg.getHeight() / 5f) ); exitButton = new MenuButton(exitImg, - width * 0.75f - exitOffset, (height / 2) + (exitImg.getHeight() / 2f) + displayContainer.width * 0.75f - exitOffset, (displayContainer.height / 2) + (exitImg.getHeight() / 2f) ); final int logoAnimationDuration = 350; logo.setHoverAnimationDuration(logoAnimationDuration); @@ -174,30 +163,30 @@ public class MainMenu extends BasicGameState { // initialize music buttons int musicWidth = GameImage.MUSIC_PLAY.getImage().getWidth(); int musicHeight = GameImage.MUSIC_PLAY.getImage().getHeight(); - musicPlay = new MenuButton(GameImage.MUSIC_PLAY.getImage(), width - (2 * musicWidth), musicHeight / 1.5f); - musicPause = new MenuButton(GameImage.MUSIC_PAUSE.getImage(), width - (2 * musicWidth), musicHeight / 1.5f); - musicNext = new MenuButton(GameImage.MUSIC_NEXT.getImage(), width - musicWidth, musicHeight / 1.5f); - musicPrevious = new MenuButton(GameImage.MUSIC_PREVIOUS.getImage(), width - (3 * musicWidth), musicHeight / 1.5f); + musicPlay = new MenuButton(GameImage.MUSIC_PLAY.getImage(), displayContainer.width - (2 * musicWidth), musicHeight / 1.5f); + musicPause = new MenuButton(GameImage.MUSIC_PAUSE.getImage(), displayContainer.width - (2 * musicWidth), musicHeight / 1.5f); + musicNext = new MenuButton(GameImage.MUSIC_NEXT.getImage(), displayContainer.width - musicWidth, musicHeight / 1.5f); + musicPrevious = new MenuButton(GameImage.MUSIC_PREVIOUS.getImage(), displayContainer.width - (3 * musicWidth), musicHeight / 1.5f); musicPlay.setHoverExpand(1.5f); musicPause.setHoverExpand(1.5f); musicNext.setHoverExpand(1.5f); musicPrevious.setHoverExpand(1.5f); // initialize music position bar location - musicBarX = width - musicWidth * 3.5f; + musicBarX = displayContainer.width - musicWidth * 3.5f; musicBarY = musicHeight * 1.25f; musicBarWidth = musicWidth * 3f; musicBarHeight = musicHeight * 0.11f; // initialize downloads button Image dlImg = GameImage.DOWNLOADS.getImage(); - downloadsButton = new MenuButton(dlImg, width - dlImg.getWidth() / 2f, height / 2f); + downloadsButton = new MenuButton(dlImg, displayContainer.width - dlImg.getWidth() / 2f, displayContainer.height / 2f); downloadsButton.setHoverAnimationDuration(350); downloadsButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK); downloadsButton.setHoverExpand(1.03f, Expand.LEFT); // initialize repository button - float startX = width * 0.997f, startY = height * 0.997f; + float startX = displayContainer.width * 0.997f, startY = displayContainer.height * 0.997f; if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { // only if a webpage can be opened Image repoImg; repoImg = GameImage.REPOSITORY.getImage(); @@ -217,7 +206,7 @@ public class MainMenu extends BasicGameState { } // initialize update buttons - float updateX = width / 2f, updateY = height * 17 / 18f; + float updateX = displayContainer.width / 2f, updateY = displayContainer.height * 17 / 18f; Image downloadImg = GameImage.DOWNLOAD.getImage(); updateButton = new MenuButton(downloadImg, updateX, updateY); updateButton.setHoverAnimationDuration(400); @@ -230,10 +219,10 @@ public class MainMenu extends BasicGameState { restartButton.setHoverRotate(360); // initialize star fountain - starFountain = new StarFountain(width, height); + starFountain = new StarFountain(displayContainer.width, displayContainer.height); // logo animations - float centerOffsetX = width / 6.5f; + float centerOffsetX = displayContainer.width / 6.5f; logoOpen = new AnimatedValue(100, 0, centerOffsetX, AnimationEquation.OUT_QUAD); logoClose = new AnimatedValue(2200, centerOffsetX, 0, AnimationEquation.OUT_QUAD); logoButtonAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR); @@ -242,10 +231,9 @@ public class MainMenu extends BasicGameState { } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { - int width = container.getWidth(); - int height = container.getHeight(); + public void render(Graphics g) { + int width = displayContainer.width; + int height = displayContainer.height; // draw background Beatmap beatmap = MusicController.getBeatmap(); @@ -305,7 +293,8 @@ public class MainMenu extends BasicGameState { musicPrevious.draw(); // draw music position bar - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; g.setColor((musicPositionBarContains(mouseX, mouseY)) ? Colors.BLACK_BG_HOVER : Colors.BLACK_BG_NORMAL); g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4); g.setColor(Color.white); @@ -366,12 +355,14 @@ public class MainMenu extends BasicGameState { } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + int delta = displayContainer.renderDelta; + UI.update(delta); if (MusicController.trackEnded()) nextTrack(false); // end of track: go to next track - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; logo.hoverUpdate(delta, mouseX, mouseY, 0.25f); playButton.hoverUpdate(delta, mouseX, mouseY, 0.25f); exitButton.hoverUpdate(delta, mouseX, mouseY, 0.25f); @@ -396,7 +387,7 @@ public class MainMenu extends BasicGameState { // window focus change: increase/decrease theme song volume if (MusicController.isThemePlaying() && - MusicController.isTrackDimmed() == container.hasFocus()) + MusicController.isTrackDimmed() == Display.isActive()) MusicController.toggleTrackDimmed(0.33f); // fade in background @@ -413,7 +404,7 @@ public class MainMenu extends BasicGameState { } // buttons - int centerX = container.getWidth() / 2; + int centerX = displayContainer.width / 2; float currentLogoButtonAlpha; switch (logoState) { case DEFAULT: @@ -468,11 +459,8 @@ public class MainMenu extends BasicGameState { } @Override - public int getID() { return state; } - - @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); UI.enter(); if (!enterNotification) { if (Updater.get().getStatus() == Updater.Status.UPDATE_AVAILABLE) { @@ -489,7 +477,8 @@ public class MainMenu extends BasicGameState { starFountain.clear(); // reset button hover states if mouse is not currently hovering over the button - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; if (!logo.contains(mouseX, mouseY, 0.25f)) logo.resetHover(); if (!playButton.contains(mouseX, mouseY, 0.25f)) @@ -515,17 +504,17 @@ public class MainMenu extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) - throws SlickException { + public void leave() { + super.leave(); if (MusicController.isTrackDimmed()) MusicController.toggleTrackDimmed(1f); } @Override - public void mousePressed(int button, int x, int y) { + public boolean mousePressed(int button, int x, int y) { // check mouse button if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + return false; // music position bar if (MusicController.isPlaying()) { @@ -533,7 +522,7 @@ public class MainMenu extends BasicGameState { lastMeasureProgress = 0f; float pos = (x - musicBarX) / musicBarWidth; MusicController.setPosition((int) (pos * MusicController.getDuration())); - return; + return true; } } @@ -546,29 +535,29 @@ public class MainMenu extends BasicGameState { MusicController.resume(); UI.sendBarNotification("Play"); } - return; + return true; } else if (musicNext.contains(x, y)) { nextTrack(true); UI.sendBarNotification(">> Next"); - return; + return true; } else if (musicPrevious.contains(x, y)) { lastMeasureProgress = 0f; if (!previous.isEmpty()) { - SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU); - menu.setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false); + instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false); if (Options.isDynamicBackgroundEnabled()) bgAlpha.setTime(0); } else MusicController.setPosition(0); UI.sendBarNotification("<< Previous"); - return; + return true; } // downloads button actions if (downloadsButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUHIT); - game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); - return; + // TODO //displayContainer.switchState(DownloadsMenu.class); + //game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); + return true; } // repository button actions @@ -580,7 +569,7 @@ public class MainMenu extends BasicGameState { } catch (IOException e) { ErrorHandler.error("Could not browse to repository URI.", e, false); } - return; + return true; } if (danceRepoButton != null && danceRepoButton.contains(x, y)) { @@ -591,7 +580,7 @@ public class MainMenu extends BasicGameState { } catch (IOException e) { ErrorHandler.error("Could not browse to repository URI.", e, false); } - return; + return true; } // update button actions @@ -604,13 +593,14 @@ public class MainMenu extends BasicGameState { updateButton.setHoverAnimationDuration(800); updateButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_QUAD); updateButton.setHoverFade(0.6f); - return; + return true; } else if (restartButton.contains(x, y) && status == Updater.Status.UPDATE_DOWNLOADED) { SoundController.playSound(SoundEffect.MENUHIT); Updater.get().prepareUpdate(); - container.setForceExit(false); - container.exit(); - return; + // TODO: exit? + //container.setForceExit(false); + //container.exit(); + return true; } } @@ -623,7 +613,7 @@ public class MainMenu extends BasicGameState { playButton.getImage().setAlpha(0f); exitButton.getImage().setAlpha(0f); SoundController.playSound(SoundEffect.MENUHIT); - return; + return true; } } @@ -632,21 +622,24 @@ public class MainMenu extends BasicGameState { if (logo.contains(x, y, 0.25f) || playButton.contains(x, y, 0.25f)) { SoundController.playSound(SoundEffect.MENUHIT); enterSongMenu(); - return; + return true; } else if (exitButton.contains(x, y, 0.25f)) { - container.exit(); - return; + // TODO exit? + //container.exit(); + return true; } } + return false; } @Override - public void mouseWheelMoved(int newValue) { + public boolean mouseWheelMoved(int newValue) { UI.changeVolume((newValue < 0) ? -1 : 1); + return true; } @Override - public void keyPressed(int key, char c) { + public boolean keyPressed(int key, char c) { switch (key) { case Input.KEY_ESCAPE: case Input.KEY_Q: @@ -656,9 +649,10 @@ public class MainMenu extends BasicGameState { logoTimer = 0; break; } - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.EXIT); - game.enterState(Opsu.STATE_BUTTONMENU); - break; + // TODO + //((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.EXIT); + //game.enterState(Opsu.STATE_BUTTONMENU); + return true; case Input.KEY_P: SoundController.playSound(SoundEffect.MENUHIT); if (logoState == LogoState.DEFAULT || logoState == LogoState.CLOSING) { @@ -669,30 +663,32 @@ public class MainMenu extends BasicGameState { exitButton.getImage().setAlpha(0f); } else enterSongMenu(); - break; + return true; case Input.KEY_D: - SoundController.playSound(SoundEffect.MENUHIT); - game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); - break; + // TODO + //SoundController.playSound(SoundEffect.MENUHIT); + //game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); + return true; case Input.KEY_R: nextTrack(true); - break; + return true; case Input.KEY_UP: UI.changeVolume(1); - break; + return true; case Input.KEY_DOWN: UI.changeVolume(-1); - break; + return true; case Input.KEY_F7: - Options.setNextFPS(container); - break; + Options.setNextFPS(displayContainer); + return true; case Input.KEY_F10: Options.toggleMouseDisabled(); - break; + return true; case Input.KEY_F12: Utils.takeScreenShot(); - break; + return true; } + return false; } /** @@ -710,7 +706,7 @@ public class MainMenu extends BasicGameState { */ public void reset() { // reset logo - logo.setX(container.getWidth() / 2); + logo.setX(displayContainer.width / 2); logoOpen.setTime(0); logoClose.setTime(0); logoButtonAlpha.setTime(0); @@ -746,8 +742,7 @@ public class MainMenu extends BasicGameState { MusicController.playAt(0, false); return; } - SongMenu menu = (SongMenu) game.getState(Opsu.STATE_SONGMENU); - BeatmapSetNode node = menu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false); + BeatmapSetNode node = instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false); boolean sameAudio = false; if (node != null) { sameAudio = MusicController.getBeatmap().audioFilename.equals(node.getBeatmapSet().get(0).audioFilename); @@ -764,9 +759,11 @@ public class MainMenu extends BasicGameState { private void enterSongMenu() { int state = Opsu.STATE_SONGMENU; if (BeatmapSetList.get().getMapSetCount() == 0) { - ((DownloadsMenu) game.getState(Opsu.STATE_DOWNLOADSMENU)).notifyOnLoad("Download some beatmaps to get started!"); - state = Opsu.STATE_DOWNLOADSMENU; + // TODO + //((DownloadsMenu) game.getState(Opsu.STATE_DOWNLOADSMENU)).notifyOnLoad("Download some beatmaps to get started!"); + //state = Opsu.STATE_DOWNLOADSMENU; } - game.enterState(state, new EasedFadeOutTransition(), new FadeInTransition()); + // TODO + //game.enterState(state, new EasedFadeOutTransition(), new FadeInTransition()); } } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index a0328350..4178065a 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -1120,7 +1120,8 @@ public class SongMenu extends BasicGameState { } break; case Input.KEY_F7: - Options.setNextFPS(container); + // TODO d + //Options.setNextFPS(container); break; case Input.KEY_F10: Options.toggleMouseDisabled(); diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java index 03154422..5aa82ee6 100644 --- a/src/itdelatrisu/opsu/states/Splash.java +++ b/src/itdelatrisu/opsu/states/Splash.java @@ -38,6 +38,7 @@ import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.state.BaseOpsuState; /** @@ -47,6 +48,8 @@ import yugecin.opsudance.core.state.BaseOpsuState; */ public class Splash extends BaseOpsuState { + private final InstanceContainer instanceContainer; + /** Minimum time, in milliseconds, to display the splash screen (and fade in the logo). */ private static final int MIN_SPLASH_TIME = 400; @@ -71,8 +74,9 @@ public class Splash extends BaseOpsuState { // game-related variables private boolean init = false; - public Splash(DisplayContainer displayContainer) { + public Splash(DisplayContainer displayContainer, InstanceContainer instanceContainer) { super(displayContainer); + this.instanceContainer = instanceContainer; } @Override @@ -102,7 +106,7 @@ public class Splash extends BaseOpsuState { } @Override - public void update() { + public void preRenderUpdate() { if (!init) { init = true; @@ -158,7 +162,7 @@ public class Splash extends BaseOpsuState { } // fade in logo - if (logoAlpha.update(displayContainer.delta)) + if (logoAlpha.update(displayContainer.renderDelta)) GameImage.MENU_LOGO.getImage().setAlpha(logoAlpha.getValue()); // change states when loading complete @@ -166,20 +170,16 @@ public class Splash extends BaseOpsuState { // initialize song list if (BeatmapSetList.get().size() > 0) { BeatmapSetList.get().init(); - if (Options.isThemeSongEnabled()) + if (Options.isThemeSongEnabled()) { MusicController.playThemeSong(); - else - //((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); + } else { + instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); System.out.println(("todo")); - // TODO - } - - // play the theme song - else + } + } else { MusicController.playThemeSong(); - - //game.enterState(Opsu.STATE_MAINMENU); - + } + displayContainer.switchState(MainMenu.class); } } diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index bcf806bd..bf9145bd 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -17,6 +17,7 @@ */ package yugecin.opsudance.core.inject; +import itdelatrisu.opsu.states.MainMenu; import itdelatrisu.opsu.states.Splash; import yugecin.opsudance.PreStartupInitializer; import yugecin.opsudance.core.DisplayContainer; @@ -53,6 +54,7 @@ public class OpsuDanceInjector extends Injector { bind(EmptyState.class).asEagerSingleton(); bind(Splash.class).asEagerSingleton(); + bind(MainMenu.class).asEagerSingleton(); } } From 57b29d7e917c157df6dc632ca6ea7658779cf4ad Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 10:27:40 +0100 Subject: [PATCH 04/38] getting rid of the temp displaymode --- src/yugecin/opsudance/core/DisplayContainer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 73941d40..4eee9338 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -202,12 +202,12 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen width = height = -1; Input.disableControllers(); Display.setTitle("opsu!dance"); - // temp displaymode to not flash the screen with a 1ms black window - Display.setDisplayMode(new DisplayMode(100, 100)); + Options.setDisplayMode(this); Display.create(); GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" }); - Options.setDisplayMode(this); + initGL(); sout("GL ready"); + eventBus.post(new ResolutionChangedEvent(this.width, this.height)); glVersion = GL11.glGetString(GL11.GL_VERSION); glVendor = GL11.glGetString(GL11.GL_VENDOR); } @@ -242,9 +242,11 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen Display.setDisplayMode(displayMode); Display.setFullscreen(fullscreen); - initGL(); + if (Display.isCreated()) { + initGL(); - eventBus.post(new ResolutionChangedEvent(this.width, this.height)); + eventBus.post(new ResolutionChangedEvent(this.width, this.height)); + } if (displayMode.getBitsPerPixel() == 16) { InternalTextureLoader.get().set16BitMode(); From 605dcec605acb8a42b6a95b040adedaee9561c16 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 11:59:30 +0100 Subject: [PATCH 05/38] bubble notif when fullscreen is not supported + changed bubble colors --- src/itdelatrisu/opsu/Options.java | 2 +- src/yugecin/opsudance/core/DisplayContainer.java | 10 ++++++---- .../opsudance/events/BubbleNotificationEvent.java | 3 ++- src/yugecin/opsudance/states/EmptyRedState.java | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index 2c033336..d810feba 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -1372,7 +1372,7 @@ public class Options { try { container.setDisplayMode(width, height, isFullscreen()); } catch (Exception e) { - container.eventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED)); + container.eventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COLOR_RED)); Log.error("Failed to set display mode.", e); } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 4eee9338..c90aa334 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -43,6 +43,7 @@ import yugecin.opsudance.core.state.specialstates.BarNotificationState; import yugecin.opsudance.core.state.specialstates.BubbleNotificationState; import yugecin.opsudance.core.state.specialstates.FpsRenderState; import yugecin.opsudance.core.state.transitions.*; +import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.events.ResolutionChangedEvent; import yugecin.opsudance.utils.GLHelper; @@ -206,8 +207,6 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen Display.create(); GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" }); initGL(); - sout("GL ready"); - eventBus.post(new ResolutionChangedEvent(this.width, this.height)); glVersion = GL11.glGetString(GL11.GL_VERSION); glVendor = GL11.glGetString(GL11.GL_VENDOR); } @@ -233,6 +232,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen 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)); } } @@ -244,8 +244,6 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen if (Display.isCreated()) { initGL(); - - eventBus.post(new ResolutionChangedEvent(this.width, this.height)); } if (displayMode.getBitsPerPixel() == 16) { @@ -265,8 +263,12 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen input.addKeyListener(this); input.addMouseListener(this); + sout("GL ready"); + GameImage.init(width, height); Fonts.init(); + + eventBus.post(new ResolutionChangedEvent(this.width, this.height)); } private int getDelta() { diff --git a/src/yugecin/opsudance/events/BubbleNotificationEvent.java b/src/yugecin/opsudance/events/BubbleNotificationEvent.java index caf5b736..a4abdd51 100644 --- a/src/yugecin/opsudance/events/BubbleNotificationEvent.java +++ b/src/yugecin/opsudance/events/BubbleNotificationEvent.java @@ -21,10 +21,11 @@ import org.newdawn.slick.Color; public class BubbleNotificationEvent { - public static final Color COMMONCOLOR_RED = new Color(138, 72, 51); 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 COLOR_RED = new Color(178, 62, 41); + public static final Color COLOR_ORANGE = new Color(138, 72, 51); public final String message; public final Color borderColor; diff --git a/src/yugecin/opsudance/states/EmptyRedState.java b/src/yugecin/opsudance/states/EmptyRedState.java index fcf52029..a4102ff3 100644 --- a/src/yugecin/opsudance/states/EmptyRedState.java +++ b/src/yugecin/opsudance/states/EmptyRedState.java @@ -74,7 +74,7 @@ public class EmptyRedState implements OpsuState { @Override public boolean keyPressed(int key, char c) { - displayContainer.eventBus.post(new BubbleNotificationEvent("this is a bubble notification... bubbly bubbly bubbly linewraaaaaaaaaap", BubbleNotificationEvent.COMMONCOLOR_RED)); + displayContainer.eventBus.post(new BubbleNotificationEvent("this is a bubble notification... bubbly bubbly bubbly linewraaaaaaaaaap", BubbleNotificationEvent.COLOR_RED)); return false; } From b1ccfe3019a4302a8859ec76896cc0578908140d Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 16:43:35 +0100 Subject: [PATCH 06/38] fix skipping close functions on startup exception --- src/yugecin/opsudance/OpsuDance.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index f8c72dfb..42fa75de 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -79,7 +79,8 @@ public class OpsuDance { try { container.setup(); } catch (Exception e) { - errorAndExit("could not initialize GL", e); + ErrorHandler.error("could not initialize GL", e).preventContinue().show(); + return false; } Exception caughtException = null; try { From 02863de1cf3cc7d7de8e64d1267776f7f3bbefdc Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 16:55:30 +0100 Subject: [PATCH 07/38] add code to exit from code --- src/itdelatrisu/opsu/states/MainMenu.java | 7 ++----- src/itdelatrisu/opsu/states/Splash.java | 18 ++++++++---------- .../opsudance/core/DisplayContainer.java | 5 +++-- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 568754f2..ab901a3f 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -597,9 +597,7 @@ public class MainMenu extends BaseOpsuState { } else if (restartButton.contains(x, y) && status == Updater.Status.UPDATE_DOWNLOADED) { SoundController.playSound(SoundEffect.MENUHIT); Updater.get().prepareUpdate(); - // TODO: exit? - //container.setForceExit(false); - //container.exit(); + displayContainer.exitRequested = true; return true; } } @@ -624,8 +622,7 @@ public class MainMenu extends BaseOpsuState { enterSongMenu(); return true; } else if (exitButton.contains(x, y, 0.25f)) { - // TODO exit? - //container.exit(); + displayContainer.exitRequested = true; return true; } } diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java index 5aa82ee6..35531ea4 100644 --- a/src/itdelatrisu/opsu/states/Splash.java +++ b/src/itdelatrisu/opsu/states/Splash.java @@ -185,16 +185,14 @@ public class Splash extends BaseOpsuState { @Override public boolean keyPressed(int key, char c) { - if (key == Input.KEY_ESCAPE) { - // close program - if (++escapeCount >= 3) System.out.println("hi"); - //container.exit(); // TODO - - // stop parsing beatmaps by sending interrupt to BeatmapParser - else if (thread != null) - thread.interrupt(); - return true; + if (key != Input.KEY_ESCAPE) { + return false; } - return false; + if (++escapeCount >= 3) { + displayContainer.exitRequested = true; + } else if (thread != null) { + thread.interrupt(); + } + return true; } } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index c90aa334..178135ab 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -93,6 +93,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public int renderDelta; public int delta; + public boolean exitRequested; + public int timeSinceLastRender; private long lastFrame; @@ -153,7 +155,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public void run() throws LWJGLException { - while(!(Display.isCloseRequested() && state.onCloseRequest())) { + while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest())) { delta = getDelta(); timeSinceLastRender += delta; @@ -196,7 +198,6 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen Display.processMessages(); Display.sync(targetUpdatesPerSecond); } - teardown(); } public void setup() throws Exception { From 4541b507f286fcdeee7df4f750eb8af976366d1a Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 16:56:12 +0100 Subject: [PATCH 08/38] remove placeholder println --- src/itdelatrisu/opsu/states/Splash.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java index 35531ea4..73445a75 100644 --- a/src/itdelatrisu/opsu/states/Splash.java +++ b/src/itdelatrisu/opsu/states/Splash.java @@ -174,7 +174,6 @@ public class Splash extends BaseOpsuState { MusicController.playThemeSong(); } else { instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); - System.out.println(("todo")); } } else { MusicController.playThemeSong(); From 7004c9ef4d8c5fb8be4f29c258d47852c4bcaead Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 17:31:29 +0100 Subject: [PATCH 09/38] convert songmenu --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/states/MainMenu.java | 11 +- src/itdelatrisu/opsu/states/SongMenu.java | 334 ++++++++++-------- .../opsudance/core/DisplayContainer.java | 7 +- .../core/inject/OpsuDanceInjector.java | 2 + 5 files changed, 200 insertions(+), 156 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 0b5bbd7c..e45b4abe 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -88,7 +88,7 @@ public class Opsu extends StateBasedGame { //addState(new Splash(STATE_SPLASH)); //addState(new MainMenu(STATE_MAINMENU)); addState(new ButtonMenu(STATE_BUTTONMENU)); - addState(new SongMenu(STATE_SONGMENU)); + //addState(new SongMenu(STATE_SONGMENU)); addState(new Game(STATE_GAME)); addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); addState(new GameRanking(STATE_GAMERANKING)); diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index ab901a3f..a2fa86dc 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -52,6 +52,7 @@ import org.newdawn.slick.state.transition.FadeInTransition; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.state.BaseOpsuState; +import yugecin.opsudance.core.state.OpsuState; /** * "Main Menu" state. @@ -754,13 +755,11 @@ public class MainMenu extends BaseOpsuState { * Enters the song menu, or the downloads menu if no beatmaps are loaded. */ private void enterSongMenu() { - int state = Opsu.STATE_SONGMENU; + Class state = SongMenu.class; if (BeatmapSetList.get().getMapSetCount() == 0) { - // TODO - //((DownloadsMenu) game.getState(Opsu.STATE_DOWNLOADSMENU)).notifyOnLoad("Download some beatmaps to get started!"); - //state = Opsu.STATE_DOWNLOADSMENU; + instanceContainer.provide(DownloadsMenu.class).notifyOnLoad("Download some beatmaps to get started!"); + // TODO d state = DownloadsMenu.class; } - // TODO - //game.enterState(state, new EasedFadeOutTransition(), new FadeInTransition()); + displayContainer.switchState(state); } } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 4178065a..455ac4cd 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -72,11 +72,15 @@ import org.newdawn.slick.Input; import org.newdawn.slick.SlickException; import org.newdawn.slick.SpriteSheet; import org.newdawn.slick.gui.TextField; -import org.newdawn.slick.state.BasicGameState; import org.newdawn.slick.state.StateBasedGame; import org.newdawn.slick.state.transition.EasedFadeOutTransition; import org.newdawn.slick.state.transition.EmptyTransition; import org.newdawn.slick.state.transition.FadeInTransition; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.events.EventListener; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.BaseOpsuState; +import yugecin.opsudance.events.ResolutionChangedEvent; /** * "Song Selection" state. @@ -84,7 +88,10 @@ import org.newdawn.slick.state.transition.FadeInTransition; * Players are able to select a beatmap to play, view previous scores, choose game mods, * manage beatmaps, or change game options from this state. */ -public class SongMenu extends BasicGameState { +public class SongMenu extends BaseOpsuState { + + private final InstanceContainer instanceContainer; + /** The max number of song buttons to be shown on each screen. */ public static final int MAX_SONG_BUTTONS = 6; @@ -169,7 +176,8 @@ public class SongMenu extends BasicGameState { private MenuButton selectModsButton, selectRandomButton, selectMapOptionsButton, selectOptionsButton; /** The search textfield. */ - private TextField search; + //private TextField search; + // TODO d recreate textfield /** * Delay timer, in milliseconds, before running another search. @@ -321,47 +329,39 @@ public class SongMenu extends BasicGameState { private boolean isScrollingToFocusNode = false; /** Sort order dropdown menu. */ - private DropdownMenu sortMenu; + // TODO: d remake dropdownmenu + //private DropdownMenu sortMenu; - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - - public SongMenu(int state) { - this.state = state; + public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + this.instanceContainer = instanceContainer; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); - - int width = container.getWidth(); - int height = container.getHeight(); + public void revalidate() { + super.revalidate(); // header/footer coordinates - headerY = height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() + + headerY = displayContainer.height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() + Fonts.BOLD.getLineHeight() + Fonts.DEFAULT.getLineHeight() + Fonts.SMALL.getLineHeight(); - footerY = height - GameImage.SELECTION_MODS.getImage().getHeight(); + footerY = displayContainer.height - GameImage.SELECTION_MODS.getImage().getHeight(); // footer logo coordinates - float footerHeight = height - footerY; + float footerHeight = displayContainer.height - footerY; footerLogoSize = footerHeight * 3.25f; Image logo = GameImage.MENU_LOGO.getImage(); logo = logo.getScaledCopy(footerLogoSize / logo.getWidth()); - footerLogoButton = new MenuButton(logo, width - footerHeight * 0.8f, height - footerHeight * 0.65f); + footerLogoButton = new MenuButton(logo, displayContainer.width - footerHeight * 0.8f, displayContainer.height - footerHeight * 0.65f); footerLogoButton.setHoverAnimationDuration(1); footerLogoButton.setHoverExpand(1.2f); // initialize sorts - int sortWidth = (int) (width * 0.12f); + // TODO d reenable dropdown + /* + int sortWidth = (int) (displayContainer.width * 0.12f); sortMenu = new DropdownMenu(container, BeatmapSortOrder.values(), - width * 0.87f, headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f, sortWidth) { + displayContainer.width * 0.87f, headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f, sortWidth) { @Override public void itemSelected(int index, BeatmapSortOrder item) { BeatmapSortOrder.set(item); @@ -386,36 +386,40 @@ public class SongMenu extends BasicGameState { sortMenu.setBackgroundColor(Colors.BLACK_BG_HOVER); sortMenu.setBorderColor(Colors.BLUE_DIVIDER); sortMenu.setChevronRightColor(Color.white); + */ // initialize group tabs for (BeatmapGroup group : BeatmapGroup.values()) - group.init(width, headerY - DIVIDER_LINE_WIDTH / 2); + group.init(displayContainer.width, headerY - DIVIDER_LINE_WIDTH / 2); // initialize score data buttons - ScoreData.init(width, headerY + height * 0.01f); + ScoreData.init(displayContainer.width, headerY + displayContainer.height * 0.01f); // song button background & graphics context Image menuBackground = GameImage.MENU_BUTTON_BG.getImage(); // song button coordinates - buttonX = width * 0.6f; + buttonX = displayContainer.width * 0.6f; //buttonY = headerY; buttonWidth = menuBackground.getWidth(); buttonHeight = menuBackground.getHeight(); buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS; // search - int textFieldX = (int) (width * 0.7125f + Fonts.BOLD.getWidth("Search: ")); + // TODO d reenable search box + /* + int textFieldX = (int) (displayContainer.width * 0.7125f + Fonts.BOLD.getWidth("Search: ")); int textFieldY = (int) (headerY + Fonts.BOLD.getLineHeight() / 2); search = new TextField( container, Fonts.BOLD, textFieldX, textFieldY, - (int) (width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight() + (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight() ); search.setBackgroundColor(Color.transparent); search.setBorderColor(Color.transparent); search.setTextColor(Color.white); search.setConsumeEvents(false); search.setMaxLength(60); + */ // selection buttons Image selectionMods = GameImage.SELECTION_MODS.getImage(); @@ -427,8 +431,8 @@ public class SongMenu extends BasicGameState { if (selectButtonsWidth < 20) { selectButtonsWidth = 100; } - float selectX = width * 0.183f + selectButtonsWidth / 2f; - float selectY = height - selectButtonsHeight / 2f; + float selectX = displayContainer.width * 0.183f + selectButtonsWidth / 2f; + float selectY = displayContainer.height - selectButtonsHeight / 2f; float selectOffset = selectButtonsWidth * 1.05f; selectModsButton = new MenuButton(GameImage.SELECTION_MODS_OVERLAY.getImage(), selectX, selectY); @@ -449,33 +453,37 @@ public class SongMenu extends BasicGameState { loader = new Animation(spr, 50); // beatmap watch service listener - final StateBasedGame game_ = game; BeatmapWatchService.addListener(new BeatmapWatchServiceListener() { @Override public void eventReceived(Kind kind, Path child) { if (!songFolderChanged && kind != StandardWatchEventKinds.ENTRY_MODIFY) { songFolderChanged = true; - if (game_.getCurrentStateID() == Opsu.STATE_SONGMENU) + if (displayContainer.isInState(SongMenu.class)) { UI.sendBarNotification("Changes in Songs folder detected. Hit F5 to refresh."); + } } } }); // star stream - starStream = new StarStream(width, (height - GameImage.STAR.getImage().getHeight()) / 2, -width, 0, MAX_STREAM_STARS); - starStream.setPositionSpread(height / 20f); + starStream = new StarStream(displayContainer.width, (displayContainer.height - GameImage.STAR.getImage().getHeight()) / 2, -displayContainer.width, 0, MAX_STREAM_STARS); + starStream.setPositionSpread(displayContainer.height / 20f); starStream.setDirectionSpread(10f); } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { + public void render(Graphics g) { + super.render(g); + g.setBackground(Color.black); - int width = container.getWidth(); - int height = container.getHeight(); - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - boolean inDropdownMenu = sortMenu.contains(mouseX, mouseY); + int width = displayContainer.width; + int height = displayContainer.height; + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; + + // TODO d + //boolean inDropdownMenu = sortMenu.contains(mouseX, mouseY); // background if (focusNode != null) { @@ -547,8 +555,11 @@ public class SongMenu extends BasicGameState { g.clearClip(); // scroll bar + // TODO d + /* if (focusScores.length > MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY) && !inDropdownMenu) ScoreData.drawScrollbar(g, startScorePos.getPosition(), focusScores.length * ScoreData.getButtonOffset()); + */ } // top/bottom bars @@ -565,6 +576,8 @@ public class SongMenu extends BasicGameState { Float position = MusicController.getBeatProgress(); if (position == null) // default to 60bpm position = System.currentTimeMillis() % 1000 / 1000f; + // TODO d + /* if (footerLogoButton.contains(mouseX, mouseY, 0.25f) && !inDropdownMenu) { // hovering over logo: stop pulsing footerLogoButton.draw(); @@ -578,6 +591,7 @@ public class SongMenu extends BasicGameState { ghostLogo.drawCentered(footerLogoButton.getX(), footerLogoButton.getY(), Colors.GHOST_LOGO); Colors.GHOST_LOGO.a = oldGhostAlpha; } + */ // header if (focusNode != null) { @@ -658,6 +672,8 @@ public class SongMenu extends BasicGameState { // group tabs BeatmapGroup currentGroup = BeatmapGroup.current(); BeatmapGroup hoverGroup = null; + // TODO d + /* if (!inDropdownMenu) { for (BeatmapGroup group : BeatmapGroup.values()) { if (group.contains(mouseX, mouseY)) { @@ -666,6 +682,7 @@ public class SongMenu extends BasicGameState { } } } + */ for (BeatmapGroup group : BeatmapGroup.VALUES_REVERSED) { if (group != currentGroup) group.draw(false, group == hoverGroup); @@ -673,6 +690,8 @@ public class SongMenu extends BasicGameState { currentGroup.draw(true, false); // search + // TODO d + /* boolean searchEmpty = search.getText().isEmpty(); int searchX = search.getX(), searchY = search.getY(); float searchBaseX = width * 0.7f; @@ -707,6 +726,7 @@ public class SongMenu extends BasicGameState { // sorting options sortMenu.render(container, g); + */ // reloading beatmaps if (reloadThread != null) { @@ -725,8 +745,10 @@ public class SongMenu extends BasicGameState { } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + super.preRenderUpdate(); + + int delta = displayContainer.delta; UI.update(delta); if (reloadThread == null) MusicController.loopTrackIfEnded(true); @@ -742,8 +764,9 @@ public class SongMenu extends BasicGameState { MusicController.playThemeSong(); reloadThread = null; } - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - boolean inDropdownMenu = sortMenu.contains(mouseX, mouseY); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; + boolean inDropdownMenu = false; // TODO d sortMenu.contains(mouseX, mouseY); UI.getBackButton().hoverUpdate(delta, mouseX, mouseY); selectModsButton.hoverUpdate(delta, mouseX, mouseY); selectRandomButton.hoverUpdate(delta, mouseX, mouseY); @@ -759,8 +782,8 @@ public class SongMenu extends BasicGameState { if (focusNode != null) { MenuState state = focusNode.getBeatmapSet().isFavorite() ? MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP; - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(state, focusNode); - game.enterState(Opsu.STATE_BUTTONMENU); + instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode); + // TODO d displayContainer.switchState(ButtonMenu.class); } return; } @@ -782,6 +805,8 @@ public class SongMenu extends BasicGameState { starStream.update(delta); // search + // TODO d + /* search.setFocus(true); searchTimer += delta; if (searchTimer >= SEARCH_DELAY && reloadThread == null && beatmapMenuTimer == -1) { @@ -827,6 +852,7 @@ public class SongMenu extends BasicGameState { if (searchTransitionTimer > SEARCH_TRANSITION_TIME) searchTransitionTimer = SEARCH_TRANSITION_TIME; } + */ // scores if (focusScores != null) { @@ -862,9 +888,11 @@ public class SongMenu extends BasicGameState { } // tooltips + // TODO d + /* if (sortMenu.baseContains(mouseX, mouseY)) UI.updateTooltip(delta, "Sort by...", false); - else if (focusScores != null && ScoreData.areaContains(mouseX, mouseY)) { + else */if (focusScores != null && ScoreData.areaContains(mouseX, mouseY)) { int startScore = (int) (startScorePos.getPosition() / ScoreData.getButtonOffset()); int offset = (int) (-startScorePos.getPosition() + startScore * ScoreData.getButtonOffset()); int scoreButtons = Math.min(focusScores.length - startScore, MAX_SCORE_BUTTONS); @@ -880,66 +908,58 @@ public class SongMenu extends BasicGameState { } @Override - public int getID() { return state; } + public boolean mousePressed(int button, int x, int y) { + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } - @Override - public void mousePressed(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; - - if (isScrollingToFocusNode) - return; + if (isScrollingToFocusNode) { + return true; + } songScrolling.pressed(); startScorePos.pressed(); + return true; } @Override - public void mouseReleased(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + public boolean mouseReleased(int button, int x, int y) { + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } - if (isScrollingToFocusNode) - return; + if (isScrollingToFocusNode) { + return true; + } songScrolling.released(); startScorePos.released(); - } - @Override - public void mouseClicked(int button, int x, int y, int clickCount) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + if (isInputBlocked()) { + return true; + } - // block input - if (isInputBlocked()) - return; - - // back if (UI.getBackButton().contains(x, y)) { SoundController.playSound(SoundEffect.MENUBACK); - ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); - game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); - return; + instanceContainer.provide(MainMenu.class).reset(); // TODO d why is this needed + displayContainer.switchState(MainMenu.class); + return true; } // selection buttons if (selectModsButton.contains(x, y)) { this.keyPressed(Input.KEY_F1, '\0'); - return; + return true; } else if (selectRandomButton.contains(x, y)) { this.keyPressed(Input.KEY_F2, '\0'); - return; + return true; } else if (selectMapOptionsButton.contains(x, y)) { this.keyPressed(Input.KEY_F3, '\0'); - return; + return true; } else if (selectOptionsButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUHIT); - game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition()); - return; + // TODO d displayContainer.switchState(OptionsMenu.class); + return true; } // group tabs @@ -954,7 +974,7 @@ public class SongMenu extends BasicGameState { songInfo = null; scoreMap = null; focusScores = null; - search.setText(""); + // TODO d search.setText(""); searchTimer = SEARCH_DELAY; searchTransitionTimer = SEARCH_TRANSITION_TIME; searchResultString = null; @@ -965,17 +985,18 @@ public class SongMenu extends BasicGameState { if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) UI.sendBarNotification(group.getEmptyMessage()); } - return; + return true; } } - if (focusNode == null) - return; + if (focusNode == null) { + return false; + } // logo: start game if (footerLogoButton.contains(x, y, 0.25f)) { startGame(); - return; + return true; } // song buttons @@ -1014,7 +1035,7 @@ public class SongMenu extends BasicGameState { if (button == Input.MOUSE_RIGHT_BUTTON) beatmapMenuTimer = (node.index == expandedIndex) ? BEATMAP_MENU_DELAY * 4 / 5 : 0; - return; + return true; } // score buttons @@ -1027,28 +1048,33 @@ public class SongMenu extends BasicGameState { SoundController.playSound(SoundEffect.MENUHIT); if (button != Input.MOUSE_RIGHT_BUTTON) { // view score - GameData data = new GameData(focusScores[rank], container.getWidth(), container.getHeight()); - ((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameData(data); - game.enterState(Opsu.STATE_GAMERANKING, new EasedFadeOutTransition(), new FadeInTransition()); + instanceContainer.provide(GameRanking.class).setGameData(new GameData(focusScores[rank], displayContainer.width, displayContainer.height)); + // TODO d displayContainer.switchState(GameRanking.class); } else { // score management - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.SCORE, focusScores[rank]); - game.enterState(Opsu.STATE_BUTTONMENU); + instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.SCORE, focusScores[rank]); + // TODO d displayContainer.switchState(ButtonMenu.class); } - return; + return true; } } } + return true; } @Override - public void keyPressed(int key, char c) { + public boolean keyPressed(int key, char c) { // block input - if ((reloadThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) || beatmapMenuTimer > -1 || isScrollingToFocusNode) - return; + if ((reloadThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) || beatmapMenuTimer > -1 || isScrollingToFocusNode) { + return true; + } + + Input input = displayContainer.input; switch (key) { case Input.KEY_ESCAPE: + // TODO d + /* if (reloadThread != null) { // beatmap reloading: stop parsing beatmaps by sending interrupt to BeatmapParser reloadThread.interrupt(); @@ -1064,12 +1090,13 @@ public class SongMenu extends BasicGameState { ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); } - break; + */ + return true; case Input.KEY_F1: SoundController.playSound(SoundEffect.MENUHIT); - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.MODS); - game.enterState(Opsu.STATE_BUTTONMENU); - break; + instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.MODS); + // TODO d displayContainer.switchState(ButtonMenu.class); + return true; case Input.KEY_F2: if (focusNode == null) break; @@ -1089,25 +1116,25 @@ public class SongMenu extends BasicGameState { randomStack.push(new SongNode(BeatmapSetList.get().getBaseNode(focusNode.index), focusNode.beatmapIndex)); setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); } - break; + return true; case Input.KEY_F3: if (focusNode == null) break; SoundController.playSound(SoundEffect.MENUHIT); MenuState state = focusNode.getBeatmapSet().isFavorite() ? MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP; - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(state, focusNode); - game.enterState(Opsu.STATE_BUTTONMENU); - break; + instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode); + // TODO d displayContainer.switchState(ButtonMenu.class); + return true; case Input.KEY_F5: SoundController.playSound(SoundEffect.MENUHIT); if (songFolderChanged) reloadBeatmaps(false); else { - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.RELOAD); - game.enterState(Opsu.STATE_BUTTONMENU); + instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.RELOAD); + // TODO d displayContainer.switchState(ButtonMenu.class); } - break; + return true; case Input.KEY_DELETE: if (focusNode == null) break; @@ -1115,31 +1142,31 @@ public class SongMenu extends BasicGameState { SoundController.playSound(SoundEffect.MENUHIT); MenuState ms = (focusNode.beatmapIndex == -1 || focusNode.getBeatmapSet().size() == 1) ? MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT; - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, focusNode); - game.enterState(Opsu.STATE_BUTTONMENU); + instanceContainer.provide(ButtonMenu.class).setMenuState(ms, focusNode); + // TODO d displayContainer.switchState(ButtonMenu.class); } - break; + return true; case Input.KEY_F7: // TODO d //Options.setNextFPS(container); - break; + return true; case Input.KEY_F10: Options.toggleMouseDisabled(); - break; + return true; case Input.KEY_F12: Utils.takeScreenShot(); - break; + return true; case Input.KEY_ENTER: if (focusNode == null) break; startGame(); - break; + return true; case Input.KEY_DOWN: changeIndex(1); - break; + return true; case Input.KEY_UP: changeIndex(-1); - break; + return true; case Input.KEY_RIGHT: if (focusNode == null) break; @@ -1155,7 +1182,7 @@ public class SongMenu extends BasicGameState { hoverIndex = oldHoverIndex; } } - break; + return true; case Input.KEY_LEFT: if (focusNode == null) break; @@ -1171,24 +1198,26 @@ public class SongMenu extends BasicGameState { hoverIndex = oldHoverIndex; } } - break; + return true; case Input.KEY_NEXT: changeIndex(MAX_SONG_BUTTONS); - break; + return true; case Input.KEY_PRIOR: changeIndex(-MAX_SONG_BUTTONS); - break; + return true; case Input.KEY_O: if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) { - game.enterState(Opsu.STATE_OPTIONSMENU, new EmptyTransition(), new FadeInTransition()); + // TODO d displayContainer.switchState(OptionsMenu.class); } - break; + return true; default: // 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) { searchTimer = 0; - int textLength = search.getText().length(); + // TODO d + //int textLength = search.getText().length(); + int textLength = 0; if (lastSearchTextLength != textLength) { if (key == Input.KEY_BACK) { if (textLength == 0) @@ -1198,10 +1227,13 @@ public class SongMenu extends BasicGameState { lastSearchTextLength = textLength; } } - break; + return true; } + return true; } + // TODO d + /* @Override public void mouseDragged(int oldx, int oldy, int newx, int newy) { // block input @@ -1229,18 +1261,20 @@ public class SongMenu extends BasicGameState { else songScrolling.dragged(-diff * multiplier); } + */ @Override - public void mouseWheelMoved(int newValue) { - // change volume + public boolean mouseWheelMoved(int newValue) { + Input input = displayContainer.input; + if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) { UI.changeVolume((newValue < 0) ? -1 : 1); - return; + return true; } - // block input - if (isInputBlocked()) - return; + if (isInputBlocked()) { + return true; + } int shift = (newValue < 0) ? 1 : -1; int mouseX = input.getMouseX(), mouseY = input.getMouseY(); @@ -1252,13 +1286,14 @@ public class SongMenu extends BasicGameState { // song buttons else changeIndex(shift); + return false; } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); + UI.enter(); - Display.setTitle(game.getTitle()); selectModsButton.resetHover(); selectRandomButton.resetHover(); selectMapOptionsButton.resetHover(); @@ -1276,8 +1311,9 @@ public class SongMenu extends BasicGameState { songChangeTimer.setTime(songChangeTimer.getDuration()); musicIconBounceTimer.setTime(musicIconBounceTimer.getDuration()); starStream.clear(); - sortMenu.activate(); - sortMenu.reset(); + // TODO d + //sortMenu.activate(); + //sortMenu.reset(); // reset song stack randomStack = new Stack(); @@ -1308,7 +1344,7 @@ public class SongMenu extends BasicGameState { // reset game data if (resetGame) { - ((Game) game.getState(Opsu.STATE_GAME)).resetGameData(); + instanceContainer.provide(Game.class).resetGameData(); // destroy extra Clips MultiClip.destroyExtraClips(); @@ -1441,10 +1477,13 @@ public class SongMenu extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) - throws SlickException { + public void leave() { + super.leave(); + // TODO d + /* search.setFocus(false); sortMenu.deactivate(); + */ } /** @@ -1569,9 +1608,9 @@ public class SongMenu extends BasicGameState { // change the focus node if (changeStartNode || (startNode.index == 0 && startNode.beatmapIndex == -1 && startNode.prev == null)) { - if (startNode == null || game.getCurrentStateID() != Opsu.STATE_SONGMENU) + if (startNode == null || displayContainer.isInState(SongMenu.class)) { songScrolling.setPosition((node.index - 1) * buttonOffset); - else { + } else { isScrollingToFocusNode = true; songScrolling.setSpeedMultiplier(2f); songScrolling.released(); @@ -1704,7 +1743,8 @@ public class SongMenu extends BasicGameState { songInfo = null; hoverOffset.setTime(0); hoverIndex = null; - search.setText(""); + // TODO d + //search.setText(""); searchTimer = SEARCH_DELAY; searchTransitionTimer = SEARCH_TRANSITION_TIME; searchResultString = null; @@ -1785,17 +1825,17 @@ public class SongMenu extends BasicGameState { } // turn on "auto" mod if holding "ctrl" key - if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { + if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) { if (!GameMod.AUTO.isActive()) GameMod.AUTO.toggle(true); } SoundController.playSound(SoundEffect.MENUHIT); MultiClip.destroyExtraClips(); - Game gameState = (Game) game.getState(Opsu.STATE_GAME); + Game gameState = instanceContainer.provide(Game.class); gameState.loadBeatmap(beatmap); gameState.setRestart(Game.Restart.NEW); gameState.setReplay(null); - game.enterState(Opsu.STATE_GAME, new EasedFadeOutTransition(), new FadeInTransition()); + // TODO d displayContainer.switchState(Game.class); } } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 178135ab..a2b70d7f 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -30,7 +30,6 @@ import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; import org.newdawn.slick.KeyListener; import org.newdawn.slick.MouseListener; -import org.newdawn.slick.openal.SoundStore; import org.newdawn.slick.opengl.InternalTextureLoader; import org.newdawn.slick.opengl.renderer.Renderer; import org.newdawn.slick.opengl.renderer.SGL; @@ -76,7 +75,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public final DisplayMode nativeDisplayMode; private Graphics graphics; - private Input input; + public Input input; public int width; public int height; @@ -300,6 +299,10 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen state.writeErrorDump(dump); } + public boolean isInState(Class state) { + return state.isInstance(state); + } + public boolean isTransitioning() { return state instanceof TransitionState; } diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index bf9145bd..8fd39377 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -18,6 +18,7 @@ package yugecin.opsudance.core.inject; import itdelatrisu.opsu.states.MainMenu; +import itdelatrisu.opsu.states.SongMenu; import itdelatrisu.opsu.states.Splash; import yugecin.opsudance.PreStartupInitializer; import yugecin.opsudance.core.DisplayContainer; @@ -55,6 +56,7 @@ public class OpsuDanceInjector extends Injector { bind(Splash.class).asEagerSingleton(); bind(MainMenu.class).asEagerSingleton(); + bind(SongMenu.class).asEagerSingleton(); } } From 54917091de81eab8b4084ae20739d140ed82d56d Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 17:32:40 +0100 Subject: [PATCH 10/38] fix tooltip causing crash --- src/itdelatrisu/opsu/ui/UI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/itdelatrisu/opsu/ui/UI.java b/src/itdelatrisu/opsu/ui/UI.java index 6fe0e50b..1afed82e 100644 --- a/src/itdelatrisu/opsu/ui/UI.java +++ b/src/itdelatrisu/opsu/ui/UI.java @@ -77,7 +77,6 @@ public class UI { // game-related variables private static DisplayContainer displayContainer; - private static Input input; // This class should not be instantiated. private UI() {} @@ -360,7 +359,8 @@ public class UI { textWidth += Fonts.SMALL.getWidth(tooltip); // get drawing coordinates - int x = input.getMouseX() + offset, y = input.getMouseY() + offset; + int x = displayContainer.mouseX + offset; + int y = displayContainer.mouseY + offset; if (x + textWidth > displayContainer.width - margin) x = displayContainer.width - margin - textWidth; else if (x < margin) From db6e4f3b55b7709263a5b4ea07e1d4c38ccdc263 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 17:39:46 +0100 Subject: [PATCH 11/38] fix music not playing (whoops) --- src/yugecin/opsudance/core/DisplayContainer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index a2b70d7f..82b39997 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -26,10 +26,7 @@ import org.lwjgl.openal.AL; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.DisplayMode; import org.lwjgl.opengl.GL11; -import org.newdawn.slick.Graphics; -import org.newdawn.slick.Input; -import org.newdawn.slick.KeyListener; -import org.newdawn.slick.MouseListener; +import org.newdawn.slick.*; import org.newdawn.slick.opengl.InternalTextureLoader; import org.newdawn.slick.opengl.renderer.Renderer; import org.newdawn.slick.opengl.renderer.SGL; @@ -160,6 +157,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen timeSinceLastRender += delta; input.poll(width, height); + Music.poll(delta); mouseX = input.getMouseX(); mouseY = input.getMouseY(); state.update(); From 44164168130a085f4750f3cf881954b600710ada Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 18:20:47 +0100 Subject: [PATCH 12/38] fix songmenu delta --- src/itdelatrisu/opsu/states/SongMenu.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 455ac4cd..4e2557e6 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -748,7 +748,7 @@ public class SongMenu extends BaseOpsuState { public void preRenderUpdate() { super.preRenderUpdate(); - int delta = displayContainer.delta; + int delta = displayContainer.renderDelta; UI.update(delta); if (reloadThread == null) MusicController.loopTrackIfEnded(true); From c03897a47dab980c1118aae640e72c3186c1b231 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 19:06:45 +0100 Subject: [PATCH 13/38] convert buttonmenu --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/states/ButtonMenu.java | 485 ++++++++---------- src/itdelatrisu/opsu/states/MainMenu.java | 8 +- src/itdelatrisu/opsu/states/SongMenu.java | 19 +- .../core/inject/OpsuDanceInjector.java | 2 + 5 files changed, 239 insertions(+), 277 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index e45b4abe..de11aab1 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -87,7 +87,7 @@ public class Opsu extends StateBasedGame { public void initStatesList(GameContainer container) throws SlickException { //addState(new Splash(STATE_SPLASH)); //addState(new MainMenu(STATE_MAINMENU)); - addState(new ButtonMenu(STATE_BUTTONMENU)); + //addState(new ButtonMenu(STATE_BUTTONMENU)); //addState(new SongMenu(STATE_SONGMENU)); addState(new Game(STATE_GAME)); addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); diff --git a/src/itdelatrisu/opsu/states/ButtonMenu.java b/src/itdelatrisu/opsu/states/ButtonMenu.java index ff95558c..8533dbf9 100644 --- a/src/itdelatrisu/opsu/states/ButtonMenu.java +++ b/src/itdelatrisu/opsu/states/ButtonMenu.java @@ -20,7 +20,6 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameMod; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.Utils; @@ -39,114 +38,112 @@ import java.util.ArrayList; import java.util.List; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.EmptyTransition; -import org.newdawn.slick.state.transition.FadeInTransition; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.BaseOpsuState; /** * Generic button menu state. *

* Displays a header and a set of defined options to the player. */ -public class ButtonMenu extends BasicGameState { +public class ButtonMenu extends BaseOpsuState { + /** Menu states. */ public enum MenuState { /** The exit confirmation screen. */ EXIT (new Button[] { Button.YES, Button.NO }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { + public String[] getTitle() { return new String[] { "Are you sure you want to exit opsu!?" }; } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.NO.click(container, game); + public void leave() { + Button.NO.click(); } }, /** The initial beatmap management screen (for a non-"favorite" beatmap). */ BEATMAP (new Button[] { Button.CLEAR_SCORES, Button.FAVORITE_ADD, Button.DELETE, Button.CANCEL }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); + public String[] getTitle() { + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); String beatmapString = (node != null) ? BeatmapSetList.get().getBaseNode(node.index).toString() : ""; return new String[] { beatmapString, "What do you want to do with this beatmap?" }; } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.CANCEL.click(container, game); + public void leave() { + Button.CANCEL.click(); } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - Input input = container.getInput(); - if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) - super.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) { + super.mouseWheelMoved(newValue); + } } }, /** The initial beatmap management screen (for a "favorite" beatmap). */ BEATMAP_FAVORITE (new Button[] { Button.CLEAR_SCORES, Button.FAVORITE_REMOVE, Button.DELETE, Button.CANCEL }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { - return BEATMAP.getTitle(container, game); + public String[] getTitle() { + return BEATMAP.getTitle(); } @Override - public void leave(GameContainer container, StateBasedGame game) { - BEATMAP.leave(container, game); + public void leave() { + BEATMAP.leave(); } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - BEATMAP.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + BEATMAP.mouseWheelMoved(newValue); } }, /** The beatmap deletion screen for a beatmap set with multiple beatmaps. */ BEATMAP_DELETE_SELECT (new Button[] { Button.DELETE_GROUP, Button.DELETE_SONG, Button.CANCEL_DELETE }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); + public String[] getTitle() { + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); String beatmapString = (node != null) ? node.toString() : ""; return new String[] { String.format("Are you sure you wish to delete '%s' from disk?", beatmapString) }; } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.CANCEL_DELETE.click(container, game); + public void leave() { + Button.CANCEL_DELETE.click(); } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - MenuState.BEATMAP.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + MenuState.BEATMAP.mouseWheelMoved(newValue); } }, /** The beatmap deletion screen for a single beatmap. */ BEATMAP_DELETE_CONFIRM (new Button[] { Button.DELETE_CONFIRM, Button.CANCEL_DELETE }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { - return BEATMAP_DELETE_SELECT.getTitle(container, game); + public String[] getTitle() { + return BEATMAP_DELETE_SELECT.getTitle(); } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.CANCEL_DELETE.click(container, game); + public void leave() { + Button.CANCEL_DELETE.click(); } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - MenuState.BEATMAP.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + MenuState.BEATMAP.mouseWheelMoved(newValue); } }, /** The beatmap reloading confirmation screen. */ RELOAD (new Button[] { Button.RELOAD_CONFIRM, Button.RELOAD_CANCEL }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { + public String[] getTitle() { return new String[] { "You have requested a full process of your beatmaps.", "This could take a few minutes.", @@ -155,70 +152,68 @@ public class ButtonMenu extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.RELOAD_CANCEL.click(container, game); + public void leave() { + Button.RELOAD_CANCEL.click(); } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - MenuState.BEATMAP.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + MenuState.BEATMAP.mouseWheelMoved(newValue); } }, /** The score management screen. */ SCORE (new Button[] { Button.DELETE_SCORE, Button.CLOSE }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { + public String[] getTitle() { return new String[] { "Score Management" }; } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.CLOSE.click(container, game); + public void leave() { + Button.CLOSE.click(); } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - MenuState.BEATMAP.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + MenuState.BEATMAP.mouseWheelMoved(newValue); } }, /** The game mod selection screen. */ MODS (new Button[] { Button.RESET_MODS, Button.CLOSE }) { @Override - public String[] getTitle(GameContainer container, StateBasedGame game) { + public String[] getTitle() { return new String[] { "Mods provide different ways to enjoy gameplay. Some have an effect on the score you can achieve during ranked play. Others are just for fun." }; } @Override - protected float getBaseY(GameContainer container, StateBasedGame game) { - return container.getHeight() * 2f / 3; + protected float getBaseY(DisplayContainer displayContainer) { + return displayContainer.height * 2f / 3; } @Override - public void enter(GameContainer container, StateBasedGame game) { - super.enter(container, game); - for (GameMod mod : GameMod.values()) + public void enter() { + super.enter(); + for (GameMod mod : GameMod.values()) { mod.resetHover(); + } } @Override - public void leave(GameContainer container, StateBasedGame game) { - Button.CLOSE.click(container, game); + public void leave() { + Button.CLOSE.click(); } @Override - public void draw(GameContainer container, StateBasedGame game, Graphics g) { - int width = container.getWidth(); - int height = container.getHeight(); - + public void render(Graphics g) { // score multiplier (TODO: fade in color changes) float mult = GameMod.getScoreMultiplier(); String multString = String.format("Score Multiplier: %.2fx", mult); Color multColor = (mult == 1f) ? Color.white : (mult > 1f) ? Color.green : Color.red; - float multY = Fonts.LARGE.getLineHeight() * 2 + height * 0.06f; + float multY = Fonts.LARGE.getLineHeight() * 2 + displayContainer.height * 0.06f; Fonts.LARGE.drawString( - (width - Fonts.LARGE.getWidth(multString)) / 2f, + (displayContainer.width - Fonts.LARGE.getWidth(multString)) / 2f, multY, multString, multColor); // category text @@ -232,27 +227,28 @@ public class ButtonMenu extends BasicGameState { for (GameMod mod : GameMod.values()) mod.draw(); - super.draw(container, game, g); + super.render(g); } @Override - public void update(GameContainer container, int delta, int mouseX, int mouseY) { - super.update(container, delta, mouseX, mouseY); + public void preRenderUpdate() { + super.preRenderUpdate(); GameMod hoverMod = null; for (GameMod mod : GameMod.values()) { - mod.hoverUpdate(delta, mod.isActive()); - if (hoverMod == null && mod.contains(mouseX, mouseY)) + mod.hoverUpdate(displayContainer.renderDelta, mod.isActive()); + if (hoverMod == null && mod.contains(displayContainer.mouseX, displayContainer.mouseY)) hoverMod = mod; } // tooltips - if (hoverMod != null) - UI.updateTooltip(delta, hoverMod.getDescription(), true); + if (hoverMod != null) { + UI.updateTooltip(displayContainer.renderDelta, hoverMod.getDescription(), true); + } } @Override - public void keyPress(GameContainer container, StateBasedGame game, int key, char c) { - super.keyPress(container, game, key, c); + public void keyPressed(int key, char c) { + super.keyPressed(key, c); for (GameMod mod : GameMod.values()) { if (key == mod.getKey()) { mod.toggle(true); @@ -262,8 +258,8 @@ public class ButtonMenu extends BasicGameState { } @Override - public void click(GameContainer container, StateBasedGame game, int cx, int cy) { - super.click(container, game, cx, cy); + public void mousePressed(int cx, int cy) { + super.mousePressed(cx, cy); for (GameMod mod : GameMod.values()) { if (mod.contains(cx, cy)) { boolean prevState = mod.isActive(); @@ -276,11 +272,14 @@ public class ButtonMenu extends BasicGameState { } @Override - public void scroll(GameContainer container, StateBasedGame game, int newValue) { - MenuState.BEATMAP.scroll(container, game, newValue); + public void mouseWheelMoved(int newValue) { + MenuState.BEATMAP.mouseWheelMoved(newValue); } }; + public static DisplayContainer displayContainer; + public static InstanceContainer instanceContainer; + /** The buttons in the state. */ private final Button[] buttons; @@ -306,15 +305,10 @@ public class ButtonMenu extends BasicGameState { /** * Initializes the menu state. - * @param container the game container - * @param game the game - * @param button the center button image - * @param buttonL the left button image - * @param buttonR the right button image */ - public void init(GameContainer container, StateBasedGame game, Image button, Image buttonL, Image buttonR) { - float center = container.getWidth() / 2f; - float baseY = getBaseY(container, game); + public void revalidate(Image button, Image buttonL, Image buttonR) { + float center = displayContainer.width / 2; + float baseY = getBaseY(displayContainer); float offsetY = button.getHeight() * 1.25f; menuButtons = new MenuButton[buttons.length]; @@ -328,25 +322,21 @@ public class ButtonMenu extends BasicGameState { /** * Returns the base Y coordinate for the buttons. - * @param container the game container - * @param game the game */ - protected float getBaseY(GameContainer container, StateBasedGame game) { - float baseY = container.getHeight() * 0.2f; - baseY += ((getTitle(container, game).length - 1) * Fonts.LARGE.getLineHeight()); + protected float getBaseY(DisplayContainer displayContainer) { + float baseY = displayContainer.height * 0.2f; + baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight()); return baseY; } /** * Draws the title and buttons to the graphics context. - * @param container the game container - * @param game the game * @param g the graphics context */ - public void draw(GameContainer container, StateBasedGame game, Graphics g) { + public void render(Graphics g) { // draw title if (actualTitle != null) { - float marginX = container.getWidth() * 0.015f, marginY = container.getHeight() * 0.01f; + float marginX = displayContainer.width * 0.015f, marginY = displayContainer.height * 0.01f; int lineHeight = Fonts.LARGE.getLineHeight(); for (int i = 0, size = actualTitle.size(); i < size; i++) Fonts.LARGE.drawString(marginX, marginY + (i * lineHeight), actualTitle.get(i), Color.white); @@ -361,17 +351,13 @@ public class ButtonMenu extends BasicGameState { /** * Updates the menu state. - * @param container the game container - * @param delta the delta interval - * @param mouseX the mouse x coordinate - * @param mouseY the mouse y coordinate */ - public void update(GameContainer container, int delta, int mouseX, int mouseY) { - float center = container.getWidth() / 2f; - boolean centerOffsetUpdated = centerOffset.update(delta); + public void preRenderUpdate() { + float center = displayContainer.width / 2f; + boolean centerOffsetUpdated = centerOffset.update(displayContainer.renderDelta); float centerOffsetX = centerOffset.getValue(); for (int i = 0; i < buttons.length; i++) { - menuButtons[i].hoverUpdate(delta, mouseX, mouseY); + menuButtons[i].hoverUpdate(displayContainer.renderDelta, displayContainer.mouseX, displayContainer.mouseY); // move button to center if (centerOffsetUpdated) @@ -381,15 +367,11 @@ public class ButtonMenu extends BasicGameState { /** * Processes a mouse click action. - * @param container the game container - * @param game the game - * @param cx the x coordinate - * @param cy the y coordinate */ - public void click(GameContainer container, StateBasedGame game, int cx, int cy) { + public void mousePressed(int x, int y) { for (int i = 0; i < buttons.length; i++) { - if (menuButtons[i].contains(cx, cy)) { - buttons[i].click(container, game); + if (menuButtons[i].contains(x, y)) { + buttons[i].click(); break; } } @@ -397,42 +379,34 @@ public class ButtonMenu extends BasicGameState { /** * Processes a key press action. - * @param container the game container - * @param game the game * @param key the key code that was pressed (see {@link org.newdawn.slick.Input}) * @param c the character of the key that was pressed */ - public void keyPress(GameContainer container, StateBasedGame game, int key, char c) { + public void keyPressed(int key, char c) { int index = Character.getNumericValue(c) - 1; if (index >= 0 && index < buttons.length) - buttons[index].click(container, game); + buttons[index].click(); } /** * Retrieves the title strings for the menu state (via override). - * @param container the game container - * @param game the game */ - public String[] getTitle(GameContainer container, StateBasedGame game) { return new String[0]; } + public String[] getTitle() { return new String[0]; } /** * Processes a mouse wheel movement. - * @param container the game container - * @param game the game * @param newValue the amount that the mouse wheel moved */ - public void scroll(GameContainer container, StateBasedGame game, int newValue) { + public void mouseWheelMoved(int newValue) { UI.changeVolume((newValue < 0) ? -1 : 1); } /** * Processes a state enter request. - * @param container the game container - * @param game the game */ - public void enter(GameContainer container, StateBasedGame game) { - float center = container.getWidth() / 2f; - float centerOffsetX = container.getWidth() * OFFSET_WIDTH_RATIO; + public void enter() { + float center = displayContainer.width / 2f; + float centerOffsetX = displayContainer.width * OFFSET_WIDTH_RATIO; centerOffset = new AnimatedValue(700, centerOffsetX, 0, AnimationEquation.OUT_BOUNCE); for (int i = 0; i < buttons.length; i++) { menuButtons[i].setX(center + ((i % 2 == 0) ? centerOffsetX : centerOffsetX * -1)); @@ -440,150 +414,149 @@ public class ButtonMenu extends BasicGameState { } // create title string list - actualTitle = new ArrayList(); - String[] title = getTitle(container, game); - int maxLineWidth = (int) (container.getWidth() * 0.96f); - for (int i = 0; i < title.length; i++) { + actualTitle = new ArrayList<>(); + String[] title = getTitle(); + int maxLineWidth = (int) (displayContainer.width * 0.96f); + for (String aTitle : title) { // wrap text if too long - if (Fonts.LARGE.getWidth(title[i]) > maxLineWidth) { - List list = Fonts.wrap(Fonts.LARGE, title[i], maxLineWidth, false); + if (Fonts.LARGE.getWidth(aTitle) > maxLineWidth) { + List list = Fonts.wrap(Fonts.LARGE, aTitle, maxLineWidth, false); actualTitle.addAll(list); - } else - actualTitle.add(title[i]); + } else { + actualTitle.add(aTitle); + } } } /** * Processes a state exit request (via override). - * @param container the game container - * @param game the game */ - public void leave(GameContainer container, StateBasedGame game) {} - }; + public void leave() {} + } /** Button types. */ private enum Button { YES ("Yes", Color.green) { @Override - public void click(GameContainer container, StateBasedGame game) { - container.exit(); + public void click() { + displayContainer.exitRequested = true; } }, NO ("No", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUBACK); - game.enterState(Opsu.STATE_MAINMENU, new EmptyTransition(), new FadeInTransition()); + displayContainer.switchState(MainMenu.class); } }, CLEAR_SCORES ("Clear local scores", Color.magenta) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP, node); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); + instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP, node); + displayContainer.switchState(SongMenu.class); } }, FAVORITE_ADD ("Add to Favorites", Color.blue) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); node.getBeatmapSet().setFavorite(true); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + displayContainer.switchState(SongMenu.class); } }, FAVORITE_REMOVE ("Remove from Favorites", Color.blue) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); node.getBeatmapSet().setFavorite(false); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_FAVORITE); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_FAVORITE); + displayContainer.switchState(SongMenu.class); } }, DELETE ("Delete...", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); MenuState ms = (node.beatmapIndex == -1 || node.getBeatmapSet().size() == 1) ? MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT; - ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(ms, node); - game.enterState(Opsu.STATE_BUTTONMENU); + instanceContainer.provide(ButtonMenu.class).setMenuState(ms, node); + displayContainer.switchState(ButtonMenu.class); } }, CANCEL ("Cancel", Color.gray) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUBACK); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + displayContainer.switchState(SongMenu.class); } }, DELETE_CONFIRM ("Yes, delete this beatmap!", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); + instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node); + displayContainer.switchState(SongMenu.class); } }, DELETE_GROUP ("Yes, delete all difficulties!", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { - DELETE_CONFIRM.click(container, game); + public void click() { + DELETE_CONFIRM.click(); } }, DELETE_SONG ("Yes, but only this difficulty", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - BeatmapSetNode node = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getNode(); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode(); + instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node); + displayContainer.switchState(SongMenu.class); } }, CANCEL_DELETE ("Nooooo! I didn't mean to!", Color.gray) { @Override - public void click(GameContainer container, StateBasedGame game) { - CANCEL.click(container, game); + public void click() { + CANCEL.click(); } }, RELOAD_CONFIRM ("Let's do it!", Color.green) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.RELOAD); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.RELOAD); + displayContainer.switchState(SongMenu.class); } }, RELOAD_CANCEL ("Cancel", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { - CANCEL.click(container, game); + public void click() { + CANCEL.click(); } }, DELETE_SCORE ("Delete score", Color.green) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUHIT); - ScoreData scoreData = ((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).getScoreData(); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).doStateActionOnLoad(MenuState.SCORE, scoreData); - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); + ScoreData scoreData = instanceContainer.provide(ButtonMenu.class).getScoreData(); + instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.SCORE, scoreData); + displayContainer.switchState(SongMenu.class); } }, CLOSE ("Close", Color.gray) { @Override - public void click(GameContainer container, StateBasedGame game) { - CANCEL.click(container, game); + public void click() { + CANCEL.click(); } }, RESET_MODS ("Reset All Mods", Color.red) { @Override - public void click(GameContainer container, StateBasedGame game) { + public void click() { SoundController.playSound(SoundEffect.MENUCLICK); for (GameMod mod : GameMod.values()) { if (mod.isActive()) @@ -592,6 +565,9 @@ public class ButtonMenu extends BasicGameState { } }; + public static DisplayContainer displayContainer; + public static InstanceContainer instanceContainer; + /** The text to show on the button. */ private final String text; @@ -620,10 +596,8 @@ public class ButtonMenu extends BasicGameState { /** * Processes a mouse click action (via override). - * @param container the game container - * @param game the game */ - public void click(GameContainer container, StateBasedGame game) {} + public void click() {} } /** The current menu state. */ @@ -635,98 +609,89 @@ public class ButtonMenu extends BasicGameState { /** The score data to process in the state. */ private ScoreData scoreData; - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - - public ButtonMenu(int state) { - this.state = state; + public ButtonMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + Button.displayContainer = MenuState.displayContainer = displayContainer; + Button.instanceContainer = MenuState.instanceContainer = instanceContainer; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); + public void revalidate() { + super.revalidate(); // initialize buttons Image button = GameImage.MENU_BUTTON_MID.getImage(); - button = button.getScaledCopy(container.getWidth() / 2, button.getHeight()); + button = button.getScaledCopy(displayContainer.width / 2, button.getHeight()); Image buttonL = GameImage.MENU_BUTTON_LEFT.getImage(); Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage(); - for (MenuState ms : MenuState.values()) - ms.init(container, game, button, buttonL, buttonR); - } - - @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { - g.setBackground(Color.black); - if (menuState != null) - menuState.draw(container, game, g); - } - - @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { - UI.update(delta); - MusicController.loopTrackIfEnded(false); - if (menuState != null) - menuState.update(container, delta, input.getMouseX(), input.getMouseY()); - } - - @Override - public int getID() { return state; } - - @Override - public void mousePressed(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; - - if (menuState != null) - menuState.click(container, game, x, y); - } - - @Override - public void mouseWheelMoved(int newValue) { - if (menuState != null) - menuState.scroll(container, game, newValue); - } - - @Override - public void keyPressed(int key, char c) { - switch (key) { - case Input.KEY_ESCAPE: - if (menuState != null) - menuState.leave(container, game); - break; - case Input.KEY_F7: - // TODO - //Options.setNextFPS(displayContainer); - break; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - break; - case Input.KEY_F12: - Utils.takeScreenShot(); - break; - default: - if (menuState != null) - menuState.keyPress(container, game, key, c); - break; + for (MenuState ms : MenuState.values()) { + ms.revalidate(button, buttonL, buttonR); } } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void render(Graphics g) { + super.render(g); + + g.setBackground(Color.black); + if (menuState == null) { + return; + } + menuState.render(g); + } + + @Override + public void preRenderUpdate() { + super.preRenderUpdate(); + + UI.update(displayContainer.renderDelta); + MusicController.loopTrackIfEnded(false); + menuState.preRenderUpdate(); + } + + @Override + public boolean mousePressed(int button, int x, int y) { + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } + + menuState.mousePressed(x, y); + return true; + } + + @Override + public boolean mouseWheelMoved(int newValue) { + menuState.mouseWheelMoved(newValue); + return true; + } + + @Override + public boolean keyPressed(int key, char c) { + switch (key) { + case Input.KEY_ESCAPE: + menuState.leave(); + return true; + case Input.KEY_F7: + // TODO + //Options.setNextFPS(displayContainer); + return true; + case Input.KEY_F10: + Options.toggleMouseDisabled(); + return true; + case Input.KEY_F12: + Utils.takeScreenShot(); + return true; + } + menuState.keyPressed(key, c); + return true; + } + + @Override + public void enter() { + super.enter(); + UI.enter(); - if (menuState != null) - menuState.enter(container, game); + menuState.enter(); } /** diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index a2fa86dc..a91e7fef 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -20,7 +20,6 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.audio.MusicController; @@ -47,8 +46,6 @@ import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; -import org.newdawn.slick.state.transition.FadeInTransition; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.state.BaseOpsuState; @@ -647,9 +644,8 @@ public class MainMenu extends BaseOpsuState { logoTimer = 0; break; } - // TODO - //((ButtonMenu) game.getState(Opsu.STATE_BUTTONMENU)).setMenuState(MenuState.EXIT); - //game.enterState(Opsu.STATE_BUTTONMENU); + instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.EXIT); + displayContainer.switchState(ButtonMenu.class); return true; case Input.KEY_P: SoundController.playSound(SoundEffect.MENUHIT); diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 4e2557e6..3741aab4 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -783,7 +783,7 @@ public class SongMenu extends BaseOpsuState { MenuState state = focusNode.getBeatmapSet().isFavorite() ? MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP; instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode); - // TODO d displayContainer.switchState(ButtonMenu.class); + displayContainer.switchState(ButtonMenu.class); } return; } @@ -1053,7 +1053,7 @@ public class SongMenu extends BaseOpsuState { } else { // score management instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.SCORE, focusScores[rank]); - // TODO d displayContainer.switchState(ButtonMenu.class); + displayContainer.switchState(ButtonMenu.class); } return true; } @@ -1084,18 +1084,17 @@ public class SongMenu extends BaseOpsuState { searchTimer = SEARCH_DELAY; searchTransitionTimer = 0; searchResultString = null; - } else { + } else*/ { // return to main menu SoundController.playSound(SoundEffect.MENUBACK); - ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); - game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); + instanceContainer.provide(MainMenu.class).reset(); // TODO d is this needed + displayContainer.switchState(MainMenu.class); } - */ return true; case Input.KEY_F1: SoundController.playSound(SoundEffect.MENUHIT); instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.MODS); - // TODO d displayContainer.switchState(ButtonMenu.class); + displayContainer.switchState(ButtonMenu.class); return true; case Input.KEY_F2: if (focusNode == null) @@ -1124,7 +1123,7 @@ public class SongMenu extends BaseOpsuState { MenuState state = focusNode.getBeatmapSet().isFavorite() ? MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP; instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode); - // TODO d displayContainer.switchState(ButtonMenu.class); + displayContainer.switchState(ButtonMenu.class); return true; case Input.KEY_F5: SoundController.playSound(SoundEffect.MENUHIT); @@ -1132,7 +1131,7 @@ public class SongMenu extends BaseOpsuState { reloadBeatmaps(false); else { instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.RELOAD); - // TODO d displayContainer.switchState(ButtonMenu.class); + displayContainer.switchState(ButtonMenu.class); } return true; case Input.KEY_DELETE: @@ -1143,7 +1142,7 @@ public class SongMenu extends BaseOpsuState { MenuState ms = (focusNode.beatmapIndex == -1 || focusNode.getBeatmapSet().size() == 1) ? MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT; instanceContainer.provide(ButtonMenu.class).setMenuState(ms, focusNode); - // TODO d displayContainer.switchState(ButtonMenu.class); + displayContainer.switchState(ButtonMenu.class); } return true; case Input.KEY_F7: diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 8fd39377..499d5221 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -17,6 +17,7 @@ */ package yugecin.opsudance.core.inject; +import itdelatrisu.opsu.states.ButtonMenu; import itdelatrisu.opsu.states.MainMenu; import itdelatrisu.opsu.states.SongMenu; import itdelatrisu.opsu.states.Splash; @@ -56,6 +57,7 @@ public class OpsuDanceInjector extends Injector { bind(Splash.class).asEagerSingleton(); bind(MainMenu.class).asEagerSingleton(); + bind(ButtonMenu.class).asEagerSingleton(); bind(SongMenu.class).asEagerSingleton(); } From a02613bb7644c8849230e2246312456d3970722a Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 19:22:14 +0100 Subject: [PATCH 14/38] pause music on exception --- src/yugecin/opsudance/OpsuDance.java | 3 +++ .../opsudance/core/DisplayContainer.java | 22 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index 42fa75de..06a2f206 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -69,6 +69,7 @@ public class OpsuDance { } while (rungame()); + container.teardownAL(); closeSingleInstanceSocket(); DBController.closeConnections(); @@ -78,6 +79,7 @@ public class OpsuDance { private boolean rungame() { try { container.setup(); + container.resume(); } catch (Exception e) { ErrorHandler.error("could not initialize GL", e).preventContinue().show(); return false; @@ -89,6 +91,7 @@ public class OpsuDance { caughtException = e; } container.teardown(); + container.pause(); return caughtException != null && ErrorHandler.error("update/render error", caughtException).show().shouldIgnoreAndContinue(); } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 82b39997..ee8912d7 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -19,8 +19,8 @@ package yugecin.opsudance.core; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; +import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.ui.Fonts; -import org.lwjgl.LWJGLException; import org.lwjgl.Sys; import org.lwjgl.openal.AL; import org.lwjgl.opengl.Display; @@ -95,6 +95,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen private long lastFrame; + private boolean wasMusicPlaying; + private String glVersion; private String glVendor; @@ -150,7 +152,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen } - public void run() throws LWJGLException { + public void run() throws Exception { while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest())) { delta = getDelta(); @@ -211,9 +213,25 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public void teardown() { Display.destroy(); + } + + public void teardownAL() { AL.destroy(); } + public void pause() { + wasMusicPlaying = MusicController.isPlaying(); + if (wasMusicPlaying) { + MusicController.pause(); + } + } + + public void resume() { + if (wasMusicPlaying) { + MusicController.resume(); + } + } + public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception { if (this.width == width && this.height == height) { Display.setFullscreen(fullscreen); From 156026bd9b3853275018120277b36483904ca062 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 19:33:58 +0100 Subject: [PATCH 15/38] destroy all images when closing --- src/itdelatrisu/opsu/GameImage.java | 31 +++++++++++++++++++ .../opsudance/core/DisplayContainer.java | 2 ++ 2 files changed, 33 insertions(+) diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index 21d10812..de479156 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -461,6 +461,37 @@ public enum GameImage { } } + public static void destroyAll() { + for (GameImage img : GameImage.values()) { + destroyAll(img.defaultImages); + destroyImage(img.defaultImage); + destroyAll(img.skinImages); + destroyImage(img.skinImage); + img.isSkinned = false; + img.defaultImages = img.skinImages = null; + img.defaultImage = img.skinImage = null; + } + } + + public static void destroyAll(Image[] imgs) { + if (imgs == null) { + return; + } + for (Image i : imgs) { + destroyImage(i); + } + } + + public static void destroyImage(Image image) { + if (image == null) { + return; + } + try { + image.destroy(); + } catch (SlickException ignored) { + } + } + /** * Returns the bitmask image type from a type string. * @param type the type string diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index ee8912d7..4ede5648 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -212,6 +212,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen } public void teardown() { + InternalTextureLoader.get().clear(); + GameImage.destroyAll(); Display.destroy(); } From 0eac32505b2bd7c8ced54a3beb9088b2f0ba2e1e Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 19:40:31 +0100 Subject: [PATCH 16/38] destroy even more images when closing --- src/itdelatrisu/opsu/GameData.java | 12 ++++- src/itdelatrisu/opsu/GameImage.java | 30 +++---------- src/itdelatrisu/opsu/beatmap/Beatmap.java | 9 ++++ .../opsudance/core/DisplayContainer.java | 6 ++- src/yugecin/opsudance/utils/SlickUtil.java | 44 +++++++++++++++++++ 5 files changed, 74 insertions(+), 27 deletions(-) create mode 100644 src/yugecin/opsudance/utils/SlickUtil.java diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index e35a079e..9138d725 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -42,7 +42,7 @@ import org.newdawn.slick.Animation; import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; -import yugecin.opsudance.Dancer; +import yugecin.opsudance.utils.SlickUtil; /** * Holds game data and renders all related elements. @@ -101,8 +101,16 @@ public class GameData { * This does NOT destroy images, so be careful of memory leaks! */ public static void clearReferences() { - for (Grade grade : Grade.values()) + for (Grade grade : Grade.values()) { grade.menuImage = null; + } + } + + public static void destroyImages() { + for (Grade grade : Grade.values()) { + SlickUtil.destroyImage(grade.menuImage); + grade.menuImage = null; + } } /** diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index de479156..cd1dd463 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -28,6 +28,7 @@ import org.newdawn.slick.Animation; import org.newdawn.slick.Image; import org.newdawn.slick.SlickException; import org.newdawn.slick.util.ResourceLoader; +import yugecin.opsudance.utils.SlickUtil; /** * Game images. @@ -461,37 +462,18 @@ public enum GameImage { } } - public static void destroyAll() { + public static void destroyImages() { for (GameImage img : GameImage.values()) { - destroyAll(img.defaultImages); - destroyImage(img.defaultImage); - destroyAll(img.skinImages); - destroyImage(img.skinImage); + SlickUtil.destroyImages(img.defaultImages); + SlickUtil.destroyImage(img.defaultImage); + SlickUtil.destroyImages(img.skinImages); + SlickUtil.destroyImage(img.skinImage); img.isSkinned = false; img.defaultImages = img.skinImages = null; img.defaultImage = img.skinImage = null; } } - public static void destroyAll(Image[] imgs) { - if (imgs == null) { - return; - } - for (Image i : imgs) { - destroyImage(i); - } - } - - public static void destroyImage(Image image) { - if (image == null) { - return; - } - try { - image.destroy(); - } catch (SlickException ignored) { - } - } - /** * Returns the bitmask image type from a type string. * @param type the type string diff --git a/src/itdelatrisu/opsu/beatmap/Beatmap.java b/src/itdelatrisu/opsu/beatmap/Beatmap.java index a87cc236..55a34ab5 100644 --- a/src/itdelatrisu/opsu/beatmap/Beatmap.java +++ b/src/itdelatrisu/opsu/beatmap/Beatmap.java @@ -22,6 +22,7 @@ import itdelatrisu.opsu.Options; import java.io.File; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedList; import java.util.Map; @@ -59,6 +60,14 @@ public class Beatmap implements Comparable { */ public static void clearBackgroundImageCache() { bgImageCache.clear(); } + public static void destroyBackgroundImageCache() { + Collection values = bgImageCache.values(); + for (ImageLoader value : values) { + value.destroy(); + } + bgImageCache.clear(); + } + /** The OSU File object associated with this beatmap. */ private File file; diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 4ede5648..6c6242fd 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -17,9 +17,11 @@ */ package yugecin.opsudance.core; +import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.audio.MusicController; +import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.ui.Fonts; import org.lwjgl.Sys; import org.lwjgl.openal.AL; @@ -213,7 +215,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public void teardown() { InternalTextureLoader.get().clear(); - GameImage.destroyAll(); + GameImage.destroyImages(); + GameData.Grade.destroyImages(); + Beatmap.destroyBackgroundImageCache(); Display.destroy(); } diff --git a/src/yugecin/opsudance/utils/SlickUtil.java b/src/yugecin/opsudance/utils/SlickUtil.java new file mode 100644 index 00000000..1123caf0 --- /dev/null +++ b/src/yugecin/opsudance/utils/SlickUtil.java @@ -0,0 +1,44 @@ +/* + * 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 org.newdawn.slick.Image; +import org.newdawn.slick.SlickException; + +public class SlickUtil { + + public static void destroyImages(Image[] imgs) { + if (imgs == null) { + return; + } + for (Image i : imgs) { + destroyImage(i); + } + } + + public static void destroyImage(Image image) { + if (image == null) { + return; + } + try { + image.destroy(); + } catch (SlickException ignored) { + } + } + +} From 8d05a8893b76383330e6bfeff992546fb46e4ead Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 19:41:27 +0100 Subject: [PATCH 17/38] save options and delete temp dir on close --- src/yugecin/opsudance/OpsuDance.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index 06a2f206..e8b5b28a 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -71,9 +71,11 @@ public class OpsuDance { while (rungame()); container.teardownAL(); + Options.saveOptions(); closeSingleInstanceSocket(); DBController.closeConnections(); DownloadList.get().cancelAllDownloads(); + Utils.deleteDirectory(Options.TEMP_DIR); } private boolean rungame() { From c4560ae9f1f201c40f09b108e1182b80ee314fc4 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 19:44:54 +0100 Subject: [PATCH 18/38] stop loading stuff when close is requested in splash state --- src/itdelatrisu/opsu/states/Splash.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/itdelatrisu/opsu/states/Splash.java b/src/itdelatrisu/opsu/states/Splash.java index 73445a75..c832408f 100644 --- a/src/itdelatrisu/opsu/states/Splash.java +++ b/src/itdelatrisu/opsu/states/Splash.java @@ -37,6 +37,7 @@ import java.io.File; import org.newdawn.slick.Color; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; +import org.newdawn.slick.util.Log; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.state.BaseOpsuState; @@ -182,6 +183,19 @@ public class Splash extends BaseOpsuState { } } + @Override + public boolean onCloseRequest() { + if (thread != null && thread.isAlive()) { + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException e) { + Log.warn("InterruptedException while waiting for splash thread to die", e); + } + } + return true; + } + @Override public boolean keyPressed(int key, char c) { if (key != Input.KEY_ESCAPE) { From f21484135934450525ded2686809dc4d736022d8 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 21:48:27 +0100 Subject: [PATCH 19/38] mouseDragged event --- src/yugecin/opsudance/core/DisplayContainer.java | 4 +++- src/yugecin/opsudance/core/state/BaseOpsuState.java | 5 +++++ src/yugecin/opsudance/core/state/OpsuState.java | 5 +++++ src/yugecin/opsudance/states/EmptyRedState.java | 5 +++++ src/yugecin/opsudance/states/EmptyState.java | 5 +++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 6c6242fd..c827a2e0 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -386,7 +386,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public void mouseMoved(int oldx, int oldy, int newx, int newy) { } @Override - public void mouseDragged(int oldx, int oldy, int newx, int newy) { } + public void mouseDragged(int oldx, int oldy, int newx, int newy) { + state.mouseDragged(oldx, oldy, newx, newy); + } @Override public void setInput(Input input) { } diff --git a/src/yugecin/opsudance/core/state/BaseOpsuState.java b/src/yugecin/opsudance/core/state/BaseOpsuState.java index 72ebc54b..8c13315d 100644 --- a/src/yugecin/opsudance/core/state/BaseOpsuState.java +++ b/src/yugecin/opsudance/core/state/BaseOpsuState.java @@ -107,6 +107,11 @@ public abstract class BaseOpsuState implements OpsuState, EventListener BaseOpsuState dump\n"); diff --git a/src/yugecin/opsudance/core/state/OpsuState.java b/src/yugecin/opsudance/core/state/OpsuState.java index 37902c0b..0a0a65ca 100644 --- a/src/yugecin/opsudance/core/state/OpsuState.java +++ b/src/yugecin/opsudance/core/state/OpsuState.java @@ -58,4 +58,9 @@ public interface OpsuState extends ErrorDumpable { */ 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/states/EmptyRedState.java b/src/yugecin/opsudance/states/EmptyRedState.java index a4102ff3..b8d049ad 100644 --- a/src/yugecin/opsudance/states/EmptyRedState.java +++ b/src/yugecin/opsudance/states/EmptyRedState.java @@ -100,6 +100,11 @@ public class EmptyRedState implements OpsuState { return false; } + @Override + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { + return false; + } + @Override public void writeErrorDump(StringWriter dump) { dump.append("> EmptyRedState dump\n"); diff --git a/src/yugecin/opsudance/states/EmptyState.java b/src/yugecin/opsudance/states/EmptyState.java index 28703a57..6a75f783 100644 --- a/src/yugecin/opsudance/states/EmptyState.java +++ b/src/yugecin/opsudance/states/EmptyState.java @@ -92,6 +92,11 @@ public class EmptyState implements OpsuState { return false; } + @Override + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { + return false; + } + @Override public void writeErrorDump(StringWriter dump) { dump.append("> EmptyState dump\n"); From 6f7e4242da2f836cf8ec82dbef551854a049e530 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 21:55:06 +0100 Subject: [PATCH 20/38] correct red color for bubble notifs --- src/itdelatrisu/opsu/Options.java | 2 +- src/yugecin/opsudance/events/BubbleNotificationEvent.java | 2 +- src/yugecin/opsudance/states/EmptyRedState.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index d810feba..2c033336 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -1372,7 +1372,7 @@ public class Options { try { container.setDisplayMode(width, height, isFullscreen()); } catch (Exception e) { - container.eventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COLOR_RED)); + container.eventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED)); Log.error("Failed to set display mode.", e); } diff --git a/src/yugecin/opsudance/events/BubbleNotificationEvent.java b/src/yugecin/opsudance/events/BubbleNotificationEvent.java index a4abdd51..8ae2b1de 100644 --- a/src/yugecin/opsudance/events/BubbleNotificationEvent.java +++ b/src/yugecin/opsudance/events/BubbleNotificationEvent.java @@ -24,7 +24,7 @@ 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 COLOR_RED = new Color(178, 62, 41); + 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; diff --git a/src/yugecin/opsudance/states/EmptyRedState.java b/src/yugecin/opsudance/states/EmptyRedState.java index b8d049ad..95c6427c 100644 --- a/src/yugecin/opsudance/states/EmptyRedState.java +++ b/src/yugecin/opsudance/states/EmptyRedState.java @@ -74,7 +74,7 @@ public class EmptyRedState implements OpsuState { @Override public boolean keyPressed(int key, char c) { - displayContainer.eventBus.post(new BubbleNotificationEvent("this is a bubble notification... bubbly bubbly bubbly linewraaaaaaaaaap", BubbleNotificationEvent.COLOR_RED)); + displayContainer.eventBus.post(new BubbleNotificationEvent("this is a bubble notification... bubbly bubbly bubbly linewraaaaaaaaaap", BubbleNotificationEvent.COMMONCOLOR_RED)); return false; } From 36cfe3813a8a7f07682e8a540c3ed59aa2781793 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 22:35:57 +0100 Subject: [PATCH 21/38] taking over components --- src/org/newdawn/slick/gui/TextField.java | 526 +++++------------- .../core/components/ActionListener.java | 24 + .../opsudance/core/components/Component.java | 60 ++ .../core/state/ComplexOpsuState.java | 124 +++++ 4 files changed, 334 insertions(+), 400 deletions(-) create mode 100644 src/yugecin/opsudance/core/components/ActionListener.java create mode 100644 src/yugecin/opsudance/core/components/Component.java create mode 100644 src/yugecin/opsudance/core/state/ComplexOpsuState.java diff --git a/src/org/newdawn/slick/gui/TextField.java b/src/org/newdawn/slick/gui/TextField.java index 6696ff9f..a989d2c4 100644 --- a/src/org/newdawn/slick/gui/TextField.java +++ b/src/org/newdawn/slick/gui/TextField.java @@ -34,232 +34,70 @@ import org.newdawn.slick.Font; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; import org.newdawn.slick.geom.Rectangle; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.components.ActionListener; +import yugecin.opsudance.core.components.Component; /** * A single text field supporting text entry * * @author kevin */ -@SuppressWarnings("unused") -public class TextField extends AbstractComponent { - /** The key repeat interval */ +public class TextField extends Component { + private static final int INITIAL_KEY_REPEAT_INTERVAL = 400; - /** The key repeat interval */ private static final int KEY_REPEAT_INTERVAL = 50; + + private final DisplayContainer displayContainer; - /** The width of the field */ - private int width; - - /** The height of the field */ - private int height; - - /** The location in the X coordinate */ - protected int x; - - /** The location in the Y coordinate */ - protected int y; - - /** The maximum number of characters allowed to be input */ + private String value = ""; + private Font font; private int maxCharacter = 10000; - /** The value stored in the text field */ - private String value = ""; + private Color borderCol = Color.white; + private Color textCol = Color.white; + private Color backgroundCol = new Color(0, 0, 0, 0.5f); - /** The font used to render text in the field */ - private Font font; - - /** The border color - null if no border */ - private Color border = Color.white; - - /** The text color */ - private Color text = Color.white; - - /** The background color - null if no background */ - private Color background = new Color(0, 0, 0, 0.5f); - - /** The current cursor position */ private int cursorPos; - - /** True if the cursor should be visible */ - private boolean visibleCursor = true; - - /** The last key pressed */ private int lastKey = -1; - - /** The last character pressed */ private char lastChar = 0; - - /** The time since last key repeat */ private long repeatTimer; - - /** The text before the paste in */ - private String oldText; - - /** The cursor position before the paste */ - private int oldCursorPos; - - /** True if events should be consumed by the field */ - private boolean consume = true; - - /** - * Create a new text field - * - * @param container - * The container rendering this field - * @param font - * The font to use in the text field - * @param x - * The x coordinate of the top left corner of the text field - * @param y - * The y coordinate of the top left corner of the text field - * @param width - * The width of the text field - * @param height - * The height of the text field - * @param listener - * The listener to add to the text field - */ - public TextField(GUIContext container, Font font, int x, int y, int width, - int height, ComponentListener listener) { - this(container,font,x,y,width,height); - addListener(listener); - } - - /** - * Create a new text field - * - * @param container - * The container rendering this field - * @param font - * The font to use in the text field - * @param x - * The x coordinate of the top left corner of the text field - * @param y - * The y coordinate of the top left corner of the text field - * @param width - * The width of the text field - * @param height - * The height of the text field - */ - public TextField(GUIContext container, Font font, int x, int y, int width, - int height) { - super(container); + private ActionListener listener; + + public TextField(DisplayContainer displayContainer, Font font, int x, int y, int width, int height) { + this.displayContainer = displayContainer; this.font = font; - - setLocation(x, y); + this.x = x; + this.y = y; this.width = width; this.height = height; } - /** - * Indicate if the input events should be consumed by this field - * - * @param consume True if events should be consumed by this field - */ - public void setConsumeEvents(boolean consume) { - this.consume = consume; + public void setListener(ActionListener listener) { + this.listener = listener; } - - /** - * Deactivate the key input handling for this field - */ - public void deactivate() { - setFocus(false); + + public void setBorderColor(Color border) { + this.borderCol = border; } - - /** - * Moves the component. - * - * @param x - * X coordinate - * @param y - * Y coordinate - */ + + public void setTextColor(Color text) { + this.textCol = text; + } + + public void setBackgroundColor(Color background) { + this.backgroundCol = background; + } + @Override - public void setLocation(int x, int y) { - this.x = x; - this.y = y; + public boolean isFocusable() { + return true; } - /** - * Returns the position in the X coordinate - * - * @return x - */ - @Override - public int getX() { - return x; - } - - /** - * Returns the position in the Y coordinate - * - * @return y - */ - @Override - public int getY() { - return y; - } - - /** - * Get the width of the component - * - * @return The width of the component - */ - @Override - public int getWidth() { - return width; - } - - /** - * Get the height of the component - * - * @return The height of the component - */ - @Override - public int getHeight() { - return height; - } - - /** - * Set the background color. Set to null to disable the background - * - * @param color - * The color to use for the background - */ - public void setBackgroundColor(Color color) { - background = color; - } - - /** - * Set the border color. Set to null to disable the border - * - * @param color - * The color to use for the border - */ - public void setBorderColor(Color color) { - border = color; - } - - /** - * Set the text color. - * - * @param color - * The color to use for the text - */ - public void setTextColor(Color color) { - text = color; - } - - /** - * @see org.newdawn.slick.gui.AbstractComponent#render(org.newdawn.slick.gui.GUIContext, - * org.newdawn.slick.Graphics) - */ - @Override - public void render(GUIContext container, Graphics g) { + public void render(Graphics g) { if (lastKey != -1) { - if (input.isKeyDown(lastKey)) { + if (displayContainer.input.isKeyDown(lastKey)) { if (repeatTimer < System.currentTimeMillis()) { repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL; keyPressed(lastKey, lastChar); @@ -274,11 +112,11 @@ public class TextField extends AbstractComponent { // Someone could have set a color for me to blend... Color clr = g.getColor(); - if (background != null) { - g.setColor(background.multiply(clr)); + if (backgroundCol != null) { + g.setColor(backgroundCol.multiply(clr)); g.fillRect(x, y, width, height); } - g.setColor(text.multiply(clr)); + g.setColor(textCol.multiply(clr)); Font temp = g.getFont(); int cpos = font.getWidth(value.substring(0, cursorPos)); @@ -291,14 +129,14 @@ public class TextField extends AbstractComponent { g.setFont(font); g.drawString(value, x + 1, y + 1); - if (hasFocus() && visibleCursor) { - g.drawString("_", x + 1 + cpos + 2, y + 1); + if (focused) { + g.drawString("|", x + 1 + cpos + 2, y + 1); } g.translate(-tx - 2, 0); - if (border != null) { - g.setColor(border.multiply(clr)); + if (borderCol != null) { + g.setColor(borderCol.multiply(clr)); g.drawRect(x, y, width, height); } g.setColor(clr); @@ -307,21 +145,10 @@ public class TextField extends AbstractComponent { g.setClip(oldClip); } - /** - * Get the value in the text field - * - * @return The value in the text field - */ public String getText() { return value; } - /** - * Set the value to be displayed in the text field - * - * @param value - * The value to be displayed in the text field - */ public void setText(String value) { this.value = value; if (cursorPos > value.length()) { @@ -329,35 +156,6 @@ public class TextField extends AbstractComponent { } } - /** - * Set the position of the cursor - * - * @param pos - * The new position of the cursor - */ - public void setCursorPos(int pos) { - cursorPos = pos; - if (cursorPos > value.length()) { - cursorPos = value.length(); - } - } - - /** - * Indicate whether the mouse cursor should be visible or not - * - * @param visibleCursor - * True if the mouse cursor should be visible - */ - public void setCursorVisible(boolean visibleCursor) { - this.visibleCursor = visibleCursor; - } - - /** - * Set the length of the allowed input - * - * @param length - * The length of the allowed input - */ public void setMaxLength(int length) { maxCharacter = length; if (value.length() > maxCharacter) { @@ -365,173 +163,101 @@ public class TextField extends AbstractComponent { } } - /** - * Do the paste into the field, overrideable for custom behaviour - * - * @param text The text to be pasted in - */ protected void doPaste(String text) { - recordOldPosition(); - for (int i=0;i 0) { + cursorPos--; + } + // Nobody more will be notified + if (consume) { + container.getInput().consumeEvent(); + } + */ } else if (key == Input.KEY_RIGHT) { /* + if (cursorPos < value.length()) { + cursorPos++; + } + // Nobody more will be notified + if (consume) { + container.getInput().consumeEvent(); + } + */ } else if (key == Input.KEY_BACK) { + if ((cursorPos > 0) && (value.length() > 0)) { + if (displayContainer.input.isKeyDown(Input.KEY_LCONTROL) || displayContainer.input.isKeyDown(Input.KEY_RCONTROL)) { + int sp = 0; + boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1)); + boolean charSeen = false; + for (int i = cursorPos - 1; i >= 0; i--) { + boolean isSpace = Character.isWhitespace(value.charAt(i)); + if (!startSpace && isSpace) { + sp = i; + break; + } else if (startSpace) { + if (charSeen && isSpace) { + sp = i + 1; + break; + } else if (!charSeen && !isSpace) + charSeen = true; + } + } + if (cursorPos < value.length()) + value = value.substring(0, sp) + value.substring(cursorPos); + else + value = value.substring(0, sp); + cursorPos = sp; + } else { + if (cursorPos < value.length()) { + value = value.substring(0, cursorPos - 1) + + value.substring(cursorPos); + } else { + value = value.substring(0, cursorPos - 1); } - return; - } */ - - // alt and control keys don't come through here - /* if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) { - return; - } */ - if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) { - return; - } - } - - if (lastKey != key) { - lastKey = key; - repeatTimer = System.currentTimeMillis() + INITIAL_KEY_REPEAT_INTERVAL; - } else { - repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL; - } - lastChar = c; - - if (key == Input.KEY_LEFT) { /* - if (cursorPos > 0) { cursorPos--; } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - */ } else if (key == Input.KEY_RIGHT) { /* - if (cursorPos < value.length()) { - cursorPos++; - } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - */ } else if (key == Input.KEY_BACK) { - if ((cursorPos > 0) && (value.length() > 0)) { - if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) { - int sp = 0; - boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1)); - boolean charSeen = false; - for (int i = cursorPos - 1; i >= 0; i--) { - boolean isSpace = Character.isWhitespace(value.charAt(i)); - if (!startSpace && isSpace) { - sp = i; - break; - } else if (startSpace) { - if (charSeen && isSpace) { - sp = i + 1; - break; - } else if (!charSeen && !isSpace) - charSeen = true; - } - } - if (cursorPos < value.length()) - value = value.substring(0, sp) + value.substring(cursorPos); - else - value = value.substring(0, sp); - cursorPos = sp; - } else { - if (cursorPos < value.length()) { - value = value.substring(0, cursorPos - 1) - + value.substring(cursorPos); - } else { - value = value.substring(0, cursorPos - 1); - } - cursorPos--; - } - } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - } else if (key == Input.KEY_DELETE) { - if (value.length() > cursorPos) { - value = value.substring(0,cursorPos) + value.substring(cursorPos+1); - } - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - } else if ((c < 127) && (c > 31) && (value.length() < maxCharacter)) { - if (cursorPos < value.length()) { - value = value.substring(0, cursorPos) + c - + value.substring(cursorPos); - } else { - value = value.substring(0, cursorPos) + c; - } - cursorPos++; - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } - } else if (key == Input.KEY_RETURN) { - notifyListeners(); - // Nobody more will be notified - if (consume) { - container.getInput().consumeEvent(); - } } - + } else if (key == Input.KEY_DELETE) { + if (value.length() > cursorPos) { + value = value.substring(0,cursorPos) + value.substring(cursorPos+1); + } + } else if ((c < 127) && (c > 31) && (value.length() < maxCharacter)) { + if (cursorPos < value.length()) { + value = value.substring(0, cursorPos) + c + + value.substring(cursorPos); + } else { + value = value.substring(0, cursorPos) + c; + } + cursorPos++; + } else if (key == Input.KEY_RETURN) { + if (listener != null) { + listener.onAction(); + } } + } - /** - * @see org.newdawn.slick.gui.AbstractComponent#setFocus(boolean) - */ - @Override - public void setFocus(boolean focus) { - lastKey = -1; - - super.setFocus(focus); - } } diff --git a/src/yugecin/opsudance/core/components/ActionListener.java b/src/yugecin/opsudance/core/components/ActionListener.java new file mode 100644 index 00000000..b1e05733 --- /dev/null +++ b/src/yugecin/opsudance/core/components/ActionListener.java @@ -0,0 +1,24 @@ +/* + * 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.components; + +public interface ActionListener { + + void onAction(); + +} diff --git a/src/yugecin/opsudance/core/components/Component.java b/src/yugecin/opsudance/core/components/Component.java new file mode 100644 index 00000000..20e4f777 --- /dev/null +++ b/src/yugecin/opsudance/core/components/Component.java @@ -0,0 +1,60 @@ +/* + * 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.components; + +import org.newdawn.slick.Graphics; + +public abstract class Component { + + public int width; + public int height; + public int x; + public int y; + + protected boolean focused; + protected boolean hovered; + + public abstract boolean isFocusable(); + + public boolean isHovered() { + return hovered; + } + + public void updateHover(int x, int y) { + this.hovered = this.x <= x && x <= this.x + width && this.y <= y && y <= this.y + height; + } + + public void mouseReleased(int button) { + } + + public void preRenderUpdate() { + } + + public abstract void render(Graphics g); + + public void keyPressed(int key, char c) { + } + + public void keyReleased(int key, char c) { + } + + public void setFocused(boolean focused) { + this.focused = focused; + } + +} diff --git a/src/yugecin/opsudance/core/state/ComplexOpsuState.java b/src/yugecin/opsudance/core/state/ComplexOpsuState.java new file mode 100644 index 00000000..ff3da952 --- /dev/null +++ b/src/yugecin/opsudance/core/state/ComplexOpsuState.java @@ -0,0 +1,124 @@ +/* + * 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; + +import org.newdawn.slick.Graphics; +import org.newdawn.slick.Input; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.components.Component; + +import java.util.LinkedList; + +public class ComplexOpsuState extends BaseOpsuState { + + protected final LinkedList components; + + private Component focusedComponent; + + public ComplexOpsuState(DisplayContainer displayContainer) { + super(displayContainer); + this.components = new LinkedList<>(); + } + + public final void focusComponent(Component component) { + if (!component.isFocusable()) { + return; + } + if (focusedComponent != null) { + focusedComponent.setFocused(false); + } + focusedComponent = component; + component.setFocused(true); + } + + public boolean isAnyComponentFocused() { + return focusedComponent != null; + } + + @Override + public boolean mouseReleased(int button, int x, int y) { + if (focusedComponent == null) { + for (Component component : components) { + if (!component.isFocusable()) { + continue; + } + component.updateHover(x, y); + if (component.isHovered()) { + focusedComponent = component; + focusedComponent.setFocused(true); + return true; + } + } + return false; + } + focusedComponent.updateHover(x, y); + if (focusedComponent.isHovered()) { + focusedComponent.mouseReleased(button); + return true; + } + focusedComponent.setFocused(false); + focusedComponent = null; + return false; + } + + @Override + public void preRenderUpdate() { + super.preRenderUpdate(); + for (Component component : components) { + component.updateHover(displayContainer.mouseX, displayContainer.mouseY); + component.preRenderUpdate(); + } + } + + @Override + public void render(Graphics g) { + super.render(g); + for (Component component : components) { + component.render(g); + } + } + + @Override + public boolean keyReleased(int key, char c) { + if (focusedComponent != null) { + if (key == Input.KEY_ESCAPE) { + focusedComponent.setFocused(false); + focusedComponent = null; + return true; + } + focusedComponent.keyReleased(key, c); + return true; + } + return false; + } + + @Override + public boolean keyPressed(int key, char c) { + if (focusedComponent != null) { + if (key == Input.KEY_ESCAPE) { + focusedComponent.setFocused(false); + focusedComponent = null; + return true; + } + focusedComponent.keyPressed(key, c); + return true; + } + return false; + } + +} From 81b71d5703f028f022ba2ac49601b12c20593107 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 22:36:09 +0100 Subject: [PATCH 22/38] convert download state --- src/itdelatrisu/opsu/Opsu.java | 2 +- .../opsu/states/DownloadsMenu.java | 302 +++++++------- src/itdelatrisu/opsu/states/MainMenu.java | 10 +- src/itdelatrisu/opsu/ui/DropdownMenu.java | 372 +++++------------- .../core/inject/OpsuDanceInjector.java | 6 +- 5 files changed, 262 insertions(+), 430 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index de11aab1..7547cb0d 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -93,7 +93,7 @@ public class Opsu extends StateBasedGame { addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); addState(new GameRanking(STATE_GAMERANKING)); addState(new OptionsMenu(STATE_OPTIONSMENU)); - addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); + //addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); } /** diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index df4435bc..ed6e47ec 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -51,17 +51,15 @@ import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; import org.newdawn.slick.SlickException; import org.newdawn.slick.gui.TextField; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; -import org.newdawn.slick.state.transition.FadeInTransition; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.ComplexOpsuState; /** * Downloads menu. @@ -69,7 +67,10 @@ import org.newdawn.slick.util.Log; * Players are able to download beatmaps off of various servers and import them * from this state. */ -public class DownloadsMenu extends BasicGameState { +public class DownloadsMenu extends ComplexOpsuState { + + private final InstanceContainer instanceContainer; + /** Delay time, in milliseconds, between each search. */ private static final int SEARCH_DELAY = 700; @@ -288,45 +289,42 @@ public class DownloadsMenu extends BasicGameState { } } - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - - public DownloadsMenu(int state) { - this.state = state; + public DownloadsMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + this.instanceContainer = instanceContainer; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); + public void revalidate() { + super.revalidate(); - int width = container.getWidth(); - int height = container.getHeight(); - float baseX = width * 0.024f; - float searchY = (height * 0.04f) + Fonts.LARGE.getLineHeight(); - float searchWidth = width * 0.3f; + components.clear(); + + int width = displayContainer.width; + int height = displayContainer.height; + int baseX = (int) (width * 0.024f); + int searchY = (int) (height * 0.04f + Fonts.LARGE.getLineHeight()); + int searchWidth = (int) (width * 0.3f); // search searchTimer = SEARCH_DELAY; searchResultString = "Loading data from server..."; - search = new TextField( - container, Fonts.DEFAULT, (int) baseX, (int) searchY, - (int) searchWidth, Fonts.MEDIUM.getLineHeight() - ); + search = new TextField(displayContainer, Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) { + @Override + public boolean isFocusable() { + return false; + } + }; + search.setFocused(true); search.setBackgroundColor(Colors.BLACK_BG_NORMAL); search.setBorderColor(Color.white); search.setTextColor(Color.white); - search.setConsumeEvents(false); search.setMaxLength(255); + components.add(search); // page buttons - float pageButtonY = height * 0.2f; - float pageButtonWidth = width * 0.7f; + int pageButtonY = (int) (height * 0.2f); + int pageButtonWidth = (int) (width * 0.7f); Image prevImg = GameImage.MUSIC_PREVIOUS.getImage(); Image nextImg = GameImage.MUSIC_NEXT.getImage(); prevPage = new MenuButton(prevImg, baseX + prevImg.getWidth() / 2f, @@ -337,25 +335,25 @@ public class DownloadsMenu extends BasicGameState { nextPage.setHoverExpand(1.5f); // buttons - float buttonMarginX = width * 0.004f; - float buttonHeight = height * 0.038f; - float resetWidth = width * 0.085f; - float rankedWidth = width * 0.15f; - float lowerWidth = width * 0.12f; - float topButtonY = searchY + Fonts.MEDIUM.getLineHeight() / 2f; - float lowerButtonY = height * 0.995f - searchY - buttonHeight / 2f; + int buttonMarginX = (int) (width * 0.004f); + int buttonHeight = (int) (height * 0.038f); + int resetWidth = (int) (width * 0.085f); + int rankedWidth = (int) (width * 0.15f); + int lowerWidth = (int) (width * 0.12f); + int topButtonY = (int) (searchY + Fonts.MEDIUM.getLineHeight() / 2f); + int lowerButtonY = (int) (height * 0.995f - searchY - buttonHeight / 2f); Image button = GameImage.MENU_BUTTON_MID.getImage(); Image buttonL = GameImage.MENU_BUTTON_LEFT.getImage(); Image buttonR = GameImage.MENU_BUTTON_RIGHT.getImage(); buttonL = buttonL.getScaledCopy(buttonHeight / buttonL.getHeight()); buttonR = buttonR.getScaledCopy(buttonHeight / buttonR.getHeight()); int lrButtonWidth = buttonL.getWidth() + buttonR.getWidth(); - Image resetButtonImage = button.getScaledCopy((int) resetWidth - lrButtonWidth, (int) buttonHeight); - Image rankedButtonImage = button.getScaledCopy((int) rankedWidth - lrButtonWidth, (int) buttonHeight); - Image lowerButtonImage = button.getScaledCopy((int) lowerWidth - lrButtonWidth, (int) buttonHeight); - float resetButtonWidth = resetButtonImage.getWidth() + lrButtonWidth; - float rankedButtonWidth = rankedButtonImage.getWidth() + lrButtonWidth; - float lowerButtonWidth = lowerButtonImage.getWidth() + lrButtonWidth; + Image resetButtonImage = button.getScaledCopy(resetWidth - lrButtonWidth, buttonHeight); + Image rankedButtonImage = button.getScaledCopy(rankedWidth - lrButtonWidth, buttonHeight); + Image lowerButtonImage = button.getScaledCopy(lowerWidth - lrButtonWidth, buttonHeight); + int resetButtonWidth = resetButtonImage.getWidth() + lrButtonWidth; + int rankedButtonWidth = rankedButtonImage.getWidth() + lrButtonWidth; + int lowerButtonWidth = lowerButtonImage.getWidth() + lrButtonWidth; clearButton = new MenuButton(lowerButtonImage, buttonL, buttonR, width * 0.75f + buttonMarginX + lowerButtonWidth / 2f, lowerButtonY); importButton = new MenuButton(lowerButtonImage, buttonL, buttonR, @@ -374,8 +372,8 @@ public class DownloadsMenu extends BasicGameState { // dropdown menu int serverWidth = (int) (width * 0.12f); - serverMenu = new DropdownMenu(container, SERVERS, - baseX + searchWidth + buttonMarginX * 3f + resetButtonWidth + rankedButtonWidth, searchY, serverWidth) { + int x = baseX + searchWidth + buttonMarginX * 3 + resetButtonWidth + rankedButtonWidth; + serverMenu = new DropdownMenu(displayContainer, SERVERS, x, searchY, serverWidth) { @Override public void itemSelected(int index, DownloadServer item) { resultList = null; @@ -388,13 +386,14 @@ public class DownloadsMenu extends BasicGameState { searchResultString = "Loading data from server..."; lastQuery = null; pageDir = Page.RESET; - if (searchQuery != null) + if (searchQuery != null) { searchQuery.interrupt(); + } resetSearchTimer(); } @Override - public boolean menuClicked(int index) { + public boolean canSelect(int index) { // block input during beatmap importing if (importThread != null) return false; @@ -406,28 +405,25 @@ public class DownloadsMenu extends BasicGameState { serverMenu.setBackgroundColor(Colors.BLACK_BG_HOVER); serverMenu.setBorderColor(Color.black); serverMenu.setChevronRightColor(Color.white); + components.add(serverMenu); } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { - int width = container.getWidth(); - int height = container.getHeight(); - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - boolean inDropdownMenu = serverMenu.contains(mouseX, mouseY); + public void render(Graphics g) { + super.render(g); // background GameImage.SEARCH_BG.getImage().draw(); // title - Fonts.LARGE.drawString(width * 0.024f, height * 0.03f, "Download Beatmaps!", Color.white); + Fonts.LARGE.drawString(displayContainer.width * 0.024f, displayContainer.height * 0.03f, "Download Beatmaps!", Color.white); // search g.setColor(Color.white); g.setLineWidth(2f); - search.render(container, g); + search.render(g); Fonts.BOLD.drawString( - search.getX() + search.getWidth() * 0.01f, search.getY() + search.getHeight() * 1.3f, + search.x + search.width * 0.01f, search.y + search.height * 1.3f, searchResultString, Color.white ); @@ -446,7 +442,7 @@ public class DownloadsMenu extends BasicGameState { if (index >= nodes.length) break; nodes[index].drawResult(g, offset + i * DownloadNode.getButtonOffset(), - DownloadNode.resultContains(mouseX, mouseY - offset, i) && !inDropdownMenu, + DownloadNode.resultContains(displayContainer.mouseX, displayContainer.mouseY - offset, i) && !serverMenu.isHovered(), (index == focusResult), (previewID == nodes[index].getID())); } g.clearClip(); @@ -457,9 +453,9 @@ public class DownloadsMenu extends BasicGameState { // pages if (nodes.length > 0) { - float baseX = width * 0.024f; - float buttonY = height * 0.2f; - float buttonWidth = width * 0.7f; + float baseX = displayContainer.width * 0.024f; + float buttonY = displayContainer.height * 0.2f; + float buttonWidth = displayContainer.width * 0.7f; Fonts.BOLD.drawString( baseX + (buttonWidth - Fonts.BOLD.getWidth("Page 1")) / 2f, buttonY - Fonts.BOLD.getLineHeight() * 1.3f, @@ -473,11 +469,11 @@ public class DownloadsMenu extends BasicGameState { } // downloads - float downloadsX = width * 0.75f, downloadsY = search.getY(); + float downloadsX = displayContainer.width * 0.75f, downloadsY = search.y; g.setColor(Colors.BLACK_BG_NORMAL); g.fillRect(downloadsX, downloadsY, - width * 0.25f, height - downloadsY * 2f); - Fonts.LARGE.drawString(downloadsX + width * 0.015f, downloadsY + height * 0.015f, "Downloads", Color.white); + displayContainer.width * 0.25f, displayContainer.height - downloadsY * 2f); + Fonts.LARGE.drawString(downloadsX + displayContainer.width * 0.015f, downloadsY + displayContainer.height * 0.015f, "Downloads", Color.white); int downloadsSize = DownloadList.get().size(); if (downloadsSize > 0) { int maxDownloadsShown = DownloadNode.maxDownloadsShown(); @@ -493,7 +489,7 @@ public class DownloadsMenu extends BasicGameState { if (node == null) break; node.drawDownload(g, i * DownloadNode.getInfoHeight() + offset, index, - DownloadNode.downloadContains(mouseX, mouseY - offset, i)); + DownloadNode.downloadContains(displayContainer.mouseX, displayContainer.mouseY - offset, i)); } g.clearClip(); @@ -510,13 +506,13 @@ public class DownloadsMenu extends BasicGameState { rankedButton.draw(Color.magenta); // dropdown menu - serverMenu.render(container, g); + serverMenu.render(g); // importing beatmaps if (importThread != null) { // darken the screen g.setColor(Colors.BLACK_ALPHA); - g.fillRect(0, 0, width, height); + g.fillRect(0, 0, displayContainer.width, displayContainer.height); UI.drawLoadingProgress(g); } @@ -529,8 +525,10 @@ public class DownloadsMenu extends BasicGameState { } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + super.preRenderUpdate(); + + int delta = displayContainer.renderDelta; UI.update(delta); if (importThread == null) MusicController.loopTrackIfEnded(false); @@ -547,11 +545,12 @@ public class DownloadsMenu extends BasicGameState { // focus new beatmap // NOTE: This can't be called in another thread because it makes OpenGL calls. - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).setFocus(importedNode, -1, true, true); + instanceContainer.provide(SongMenu.class).setFocus(importedNode, -1, true, true); } importThread = null; } - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; UI.getBackButton().hoverUpdate(delta, mouseX, mouseY); prevPage.hoverUpdate(delta, mouseX, mouseY); nextPage.hoverUpdate(delta, mouseX, mouseY); @@ -572,7 +571,6 @@ public class DownloadsMenu extends BasicGameState { focusTimer += delta; // search - search.setFocus(true); searchTimer += delta; if (searchTimer >= SEARCH_DELAY && importThread == null) { searchTimer = 0; @@ -608,24 +606,26 @@ public class DownloadsMenu extends BasicGameState { } @Override - public int getID() { return state; } + public boolean mousePressed(int button, int x, int y) { + if (super.mousePressed(button, x, y)) { + return true; + } - @Override - public void mousePressed(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } // block input during beatmap importing - if (importThread != null) - return; + if (importThread != null) { + return true; + } // back if (UI.getBackButton().contains(x, y)) { SoundController.playSound(SoundEffect.MENUBACK); - ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); - game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); - return; + instanceContainer.provide(MainMenu.class).reset(); + displayContainer.switchState(MainMenu.class); + return true; } // search results @@ -694,11 +694,12 @@ public class DownloadsMenu extends BasicGameState { } }.start(); } - return; + return true; } - if (isLoaded) - return; + if (isLoaded) { + return true; + } SoundController.playSound(SoundEffect.MENUCLICK); if (index == focusResult) { @@ -725,7 +726,7 @@ public class DownloadsMenu extends BasicGameState { break; } } - return; + return true; } // pages @@ -741,7 +742,7 @@ public class DownloadsMenu extends BasicGameState { searchQuery.interrupt(); resetSearchTimer(); } - return; + return true; } if (pageResultTotal < totalResults && nextPage.contains(x, y)) { if (lastQueryDir == Page.NEXT && searchQuery != null && !searchQuery.isComplete()) @@ -753,7 +754,7 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - return; + return true; } } } @@ -763,7 +764,7 @@ public class DownloadsMenu extends BasicGameState { if (clearButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); DownloadList.get().clearInactiveDownloads(); - return; + return true; } if (importButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); @@ -771,7 +772,7 @@ public class DownloadsMenu extends BasicGameState { // import songs in new thread importThread = new BeatmapImportThread(); importThread.start(); - return; + return true; } if (resetButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); @@ -781,7 +782,7 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - return; + return true; } if (rankedButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUCLICK); @@ -791,7 +792,7 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - return; + return true; } // downloads @@ -807,8 +808,9 @@ public class DownloadsMenu extends BasicGameState { if (DownloadNode.downloadIconContains(x, y - offset, i)) { SoundController.playSound(SoundEffect.MENUCLICK); DownloadNode node = DownloadList.get().getNode(index); - if (node == null) - return; + if (node == null) { + return true; + } Download dl = node.getDownload(); switch (dl.getStatus()) { case CANCELLED: @@ -822,62 +824,78 @@ public class DownloadsMenu extends BasicGameState { dl.cancel(); break; } - return; + return true; } } } + return false; } @Override - public void mouseReleased(int button, int x, int y) { - // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + public boolean mouseReleased(int button, int x, int y) { + if (super.mouseReleased(button, x, y)) { + return true; + } + + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } startDownloadIndexPos.released(); startResultPos.released(); + return true; } @Override - public void mouseWheelMoved(int newValue) { + public boolean mouseWheelMoved(int newValue) { // change volume - if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) { + if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) { UI.changeVolume((newValue < 0) ? -1 : 1); - return; + return true; } // block input during beatmap importing - if (importThread != null) - return; + if (importThread != null) { + return true; + } int shift = (newValue < 0) ? 1 : -1; - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - scrollLists(mouseX, mouseY, shift); + scrollLists(displayContainer.mouseX, displayContainer.mouseY, shift); + return true; } @Override - public void mouseDragged(int oldx, int oldy, int newx, int newy) { + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { // block input during beatmap importing - if (importThread != null) - return; - - // check mouse button - if (!input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON) && - !input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) - return; + if (importThread != null) { + return true; + } int diff = newy - oldy; - if (diff == 0) - return; + if (diff == 0) { + return false; + } + startDownloadIndexPos.dragged(-diff); startResultPos.dragged(-diff); + return true; } @Override - public void keyPressed(int key, char c) { + public boolean keyReleased(int key, char c) { + return super.keyReleased(key, c); + } + + @Override + public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; + } + // block input during beatmap importing - if (importThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) - return; + if (importThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) { + return true; + } switch (key) { case Input.KEY_ESCAPE: @@ -892,16 +910,16 @@ public class DownloadsMenu extends BasicGameState { } else { // return to main menu SoundController.playSound(SoundEffect.MENUBACK); - ((MainMenu) game.getState(Opsu.STATE_MAINMENU)).reset(); - game.enterState(Opsu.STATE_MAINMENU, new EasedFadeOutTransition(), new FadeInTransition()); + instanceContainer.provide(MainMenu.class).reset(); + displayContainer.switchState(MainMenu.class); } - break; + return true; case Input.KEY_ENTER: if (!search.getText().isEmpty()) { pageDir = Page.RESET; resetSearchTimer(); } - break; + return true; case Input.KEY_F5: SoundController.playSound(SoundEffect.MENUCLICK); lastQuery = null; @@ -909,30 +927,31 @@ public class DownloadsMenu extends BasicGameState { if (searchQuery != null) searchQuery.interrupt(); resetSearchTimer(); - break; + return true; case Input.KEY_F7: // TODO d //Options.setNextFPS(container); - break; + return true; case Input.KEY_F10: Options.toggleMouseDisabled(); - break; + return true; case Input.KEY_F12: Utils.takeScreenShot(); - break; - default: - // wait for user to finish typing - if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) { - searchTimer = 0; - pageDir = Page.RESET; - } - break; + return true; } + // wait for user to finish typing + if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) { + search.keyPressed(key, c); + searchTimer = 0; + pageDir = Page.RESET; + } + return true; } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); + UI.enter(); prevPage.resetHover(); nextPage.resetHover(); @@ -940,7 +959,6 @@ public class DownloadsMenu extends BasicGameState { importButton.resetHover(); resetButton.resetHover(); rankedButton.resetHover(); - serverMenu.activate(); serverMenu.reset(); focusResult = -1; startResultPos.setPosition(0); @@ -954,10 +972,10 @@ public class DownloadsMenu extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) - throws SlickException { - search.setFocus(false); - serverMenu.deactivate(); + public void leave() { + super.leave(); + + focusComponent(search); SoundController.stopTrack(); MusicController.resume(); } diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index a91e7fef..d1f63a9e 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -553,8 +553,7 @@ public class MainMenu extends BaseOpsuState { // downloads button actions if (downloadsButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUHIT); - // TODO //displayContainer.switchState(DownloadsMenu.class); - //game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); + displayContainer.switchState(DownloadsMenu.class); return true; } @@ -659,9 +658,8 @@ public class MainMenu extends BaseOpsuState { enterSongMenu(); return true; case Input.KEY_D: - // TODO - //SoundController.playSound(SoundEffect.MENUHIT); - //game.enterState(Opsu.STATE_DOWNLOADSMENU, new EasedFadeOutTransition(), new FadeInTransition()); + SoundController.playSound(SoundEffect.MENUHIT); + displayContainer.switchState(DownloadsMenu.class); return true; case Input.KEY_R: nextTrack(true); @@ -754,7 +752,7 @@ public class MainMenu extends BaseOpsuState { Class state = SongMenu.class; if (BeatmapSetList.get().getMapSetCount() == 0) { instanceContainer.provide(DownloadsMenu.class).notifyOnLoad("Download some beatmaps to get started!"); - // TODO d state = DownloadsMenu.class; + state = DownloadsMenu.class; } displayContainer.switchState(state); } diff --git a/src/itdelatrisu/opsu/ui/DropdownMenu.java b/src/itdelatrisu/opsu/ui/DropdownMenu.java index 5204c257..095ead77 100644 --- a/src/itdelatrisu/opsu/ui/DropdownMenu.java +++ b/src/itdelatrisu/opsu/ui/DropdownMenu.java @@ -27,152 +27,62 @@ import org.newdawn.slick.Font; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; import org.newdawn.slick.UnicodeFont; -import org.newdawn.slick.gui.AbstractComponent; -import org.newdawn.slick.gui.GUIContext; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.components.Component; + +public class DropdownMenu extends Component { -/** - * Simple dropdown menu. - *

- * Basic usage: - *

    - *
  • Override {@link #menuClicked(int)} to perform actions when the menu is clicked - * (e.g. play a sound effect, block input under certain conditions). - *
  • Override {@link #itemSelected(int, Object)} to perform actions when a new item is selected. - *
  • Call {@link #activate()}/{@link #deactivate()} whenever the component is needed - * (e.g. in a state's {@code enter} and {@code leave} events. - *
- * - * @param the type of the elements in the menu - */ -public class DropdownMenu extends AbstractComponent { - /** Padding ratios for drawing. */ private static final float PADDING_Y = 0.1f, CHEVRON_X = 0.03f; - /** Whether this component is active. */ - private boolean active; + private final DisplayContainer displayContainer; - /** The menu items. */ private E[] items; - - /** The menu item names. */ private String[] itemNames; + private int selectedItemIndex = 0; + private boolean expanded; - /** The index of the selected item. */ - private int itemIndex = 0; - - /** Whether the menu is expanded. */ - private boolean expanded = false; - - /** The expanding animation progress. */ private AnimatedValue expandProgress = new AnimatedValue(300, 0f, 1f, AnimationEquation.LINEAR); - /** The last update time, in milliseconds. */ - private long lastUpdateTime; - - /** The top-left coordinates. */ - private float x, y; - - /** The width and height of the dropdown menu. */ - private int width, height; - - /** The height of the base item. */ private int baseHeight; - - /** The vertical offset between items. */ private float offsetY; - /** The colors to use. */ - private Color - textColor = Color.white, backgroundColor = Color.black, - highlightColor = Colors.BLUE_DIVIDER, borderColor = Colors.BLUE_DIVIDER, - chevronDownColor = textColor, chevronRightColor = backgroundColor; + private Color textColor = Color.white; + private Color backgroundColor = Color.black; + private Color highlightColor = Colors.BLUE_DIVIDER; + private Color borderColor = Colors.BLUE_DIVIDER; + private Color chevronDownColor = textColor; + private Color chevronRightColor = backgroundColor; - /** The fonts to use. */ - private UnicodeFont fontNormal = Fonts.MEDIUM, fontSelected = Fonts.MEDIUMBOLD; + private UnicodeFont fontNormal = Fonts.MEDIUM; + private UnicodeFont fontSelected = Fonts.MEDIUMBOLD; - /** The chevron images. */ - private Image chevronDown, chevronRight; + private Image chevronDown; + private Image chevronRight; - /** Should the next click be blocked? */ - private boolean blockClick = false; - - /** - * Creates a new dropdown menu. - * @param container the container rendering this menu - * @param items the list of items (with names given as their {@code toString()} methods) - * @param x the top-left x coordinate - * @param y the top-left y coordinate - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y) { - this(container, items, x, y, 0); - } - - /** - * Creates a new dropdown menu with the given fonts. - * @param container the container rendering this menu - * @param items the list of items (with names given as their {@code toString()} methods) - * @param x the top-left x coordinate - * @param y the top-left y coordinate - * @param normal the normal font - * @param selected the font for the selected item - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y, UnicodeFont normal, UnicodeFont selected) { - this(container, items, x, y, 0, normal, selected); - } - - /** - * Creates a new dropdown menu with the given width. - * @param container the container rendering this menu - * @param items the list of items (with names given as their {@code toString()} methods) - * @param x the top-left x coordinate - * @param y the top-left y coordinate - * @param width the menu width - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y, int width) { - super(container); + public DropdownMenu(DisplayContainer displayContainer, E[] items, int x, int y, int width) { + this.displayContainer = displayContainer; init(items, x, y, width); } - /** - * Creates a new dropdown menu with the given width and fonts. - * @param container the container rendering this menu - * @param items the list of items (with names given as their {@code toString()} methods) - * @param x the top-left x coordinate - * @param y the top-left y coordinate - * @param width the menu width - * @param normal the normal font - * @param selected the font for the selected item - */ - public DropdownMenu(GUIContext container, E[] items, float x, float y, int width, UnicodeFont normal, UnicodeFont selected) { - super(container); - this.fontNormal = normal; - this.fontSelected = selected; - init(items, x, y, width); - } - - /** - * Returns the maximum item width from the list. - */ private int getMaxItemWidth() { int maxWidth = 0; - for (int i = 0; i < itemNames.length; i++) { - int w = fontSelected.getWidth(itemNames[i]); - if (w > maxWidth) + for (String itemName : itemNames) { + int w = fontSelected.getWidth(itemName); + if (w > maxWidth) { maxWidth = w; + } } return maxWidth; } - /** - * Initializes the component. - */ - private void init(E[] items, float x, float y, int width) { + @SuppressWarnings("SuspiciousNameCombination") + private void init(E[] items, int x, int y, int width) { this.items = items; this.itemNames = new String[items.length]; - for (int i = 0; i < itemNames.length; i++) + for (int i = 0; i < itemNames.length; i++) { itemNames[i] = items[i].toString(); + } this.x = x; this.y = y; this.baseHeight = fontNormal.getLineHeight(); @@ -188,77 +98,27 @@ public class DropdownMenu extends AbstractComponent { } @Override - public void setLocation(int x, int y) { - this.x = x; - this.y = y; + public void updateHover(int x, int y) { + this.hovered = this.x <= x && x <= this.x + width && this.y <= y && y <= this.y + (expanded ? height : baseHeight); + } + + public boolean baseContains(int x, int y) { + return (x > this.x && x < this.x + width && y > this.y && y < this.y + baseHeight); } @Override - public int getX() { return (int) x; } + public void render(Graphics g) { + int delta = displayContainer.renderDelta; - @Override - public int getY() { return (int) y; } - - @Override - public int getWidth() { return width; } - - @Override - public int getHeight() { return (expanded) ? height : baseHeight; } - - /** Activates the component. */ - public void activate() { this.active = true; } - - /** Deactivates the component. */ - public void deactivate() { this.active = false; } - - /** - * Returns whether the dropdown menu is currently open. - * @return true if open, false otherwise - */ - public boolean isOpen() { return expanded; } - - /** - * Opens or closes the dropdown menu. - * @param flag true to open, false to close - */ - public void open(boolean flag) { this.expanded = flag; } - - /** - * Returns true if the coordinates are within the menu bounds. - * @param cx the x coordinate - * @param cy the y coordinate - */ - public boolean contains(float cx, float cy) { - return (cx > x && cx < x + width && ( - (cy > y && cy < y + baseHeight) || - (expanded && cy > y + offsetY && cy < y + height))); - } - - /** - * Returns true if the coordinates are within the base item bounds. - * @param cx the x coordinate - * @param cy the y coordinate - */ - public boolean baseContains(float cx, float cy) { - return (cx > x && cx < x + width && cy > y && cy < y + baseHeight); - } - - @Override - public void render(GUIContext container, Graphics g) throws SlickException { // update animation - long time = container.getTime(); - if (lastUpdateTime > 0) { - int delta = (int) (time - lastUpdateTime); - expandProgress.update((expanded) ? delta : -delta * 2); - } - this.lastUpdateTime = time; + expandProgress.update((expanded) ? delta : -delta * 2); // get parameters - Input input = container.getInput(); - int idx = getIndexAt(input.getMouseX(), input.getMouseY()); + int idx = getIndexAt(displayContainer.mouseY); float t = expandProgress.getValue(); - if (expanded) + if (expanded) { t = AnimationEquation.OUT_CUBIC.calc(t); + } // background and border Color oldGColor = g.getColor(); @@ -293,12 +153,12 @@ public class DropdownMenu extends AbstractComponent { // text chevronDown.draw(x + width - chevronDown.getWidth() - width * CHEVRON_X, y + (baseHeight - chevronDown.getHeight()) / 2f, chevronDownColor); - fontNormal.drawString(x + (width * 0.03f), y + (fontNormal.getPaddingTop() + fontNormal.getPaddingBottom()) / 2f, itemNames[itemIndex], textColor); + fontNormal.drawString(x + (width * 0.03f), y + (fontNormal.getPaddingTop() + fontNormal.getPaddingBottom()) / 2f, itemNames[selectedItemIndex], textColor); float oldTextAlpha = textColor.a; textColor.a *= t; if (expanded || t >= 0.0001) { for (int i = 0; i < itemNames.length; i++) { - Font f = (i == itemIndex) ? fontSelected : fontNormal; + Font f = (i == selectedItemIndex) ? fontSelected : fontNormal; if (i == idx && t >= 0.999) chevronRight.draw(x, y + offsetY + (offsetY * i) + (offsetY - chevronRight.getHeight()) / 2f, chevronRightColor); f.drawString(x + chevronRight.getWidth(), y + offsetY + (offsetY * i * t), itemNames[i], textColor); @@ -310,131 +170,89 @@ public class DropdownMenu extends AbstractComponent { /** * Returns the index of the item at the given location, -1 for the base item, * and -2 if there is no item at the location. - * @param cx the x coordinate - * @param cy the y coordinate + * @param y the y coordinate */ - private int getIndexAt(float cx, float cy) { - if (!contains(cx, cy)) + private int getIndexAt(int y) { + if (!hovered) { return -2; - if (cy <= y + baseHeight) + } + if (y <= this.y + baseHeight) { return -1; - if (!expanded) + } + if (!expanded) { return -2; - return (int) ((cy - (y + offsetY)) / offsetY); + } + return (int) ((y - (this.y + offsetY)) / offsetY); } - /** - * Resets the menu state. - */ public void reset() { this.expanded = false; - this.lastUpdateTime = 0; expandProgress.setTime(0); - blockClick = false; + } + + + @Override + public void setFocused(boolean focused) { + super.setFocused(focused); + expanded = focused; } @Override - public void mousePressed(int button, int x, int y) { - if (!active) - return; + public boolean isFocusable() { + return true; + } - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + @Override + public void mouseReleased(int button) { + super.mouseReleased(button); - int idx = getIndexAt(x, y); + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return; + } + + int idx = getIndexAt(displayContainer.mouseY); if (idx == -2) { this.expanded = false; return; } - if (!menuClicked(idx)) + if (!canSelect(selectedItemIndex)) { return; - this.expanded = (idx == -1) ? !expanded : false; - if (idx >= 0 && itemIndex != idx) { - this.itemIndex = idx; - itemSelected(idx, items[idx]); } - blockClick = true; - consumeEvent(); - } - - @Override - public void mouseClicked(int button, int x, int y, int clickCount) { - if (!active) - return; - - if (blockClick) { - blockClick = false; - consumeEvent(); + this.expanded = (idx == -1) && !expanded; + if (idx >= 0 && selectedItemIndex != idx) { + this.selectedItemIndex = idx; + itemSelected(idx, items[selectedItemIndex]); } } - /** - * Notification that a new item was selected (via override). - * @param index the index of the item selected - * @param item the item selected - */ - public void itemSelected(int index, E item) {} - - /** - * Notification that the menu was clicked (via override). - * @param index the index of the item clicked, or -1 for the base item - * @return true to process the click, or false to block/intercept it - */ - public boolean menuClicked(int index) { return true; } - - @Override - public void setFocus(boolean focus) { /* does not currently use the "focus" concept */ } - - @Override - public void mouseReleased(int button, int x, int y) { /* does not currently use the "focus" concept */ } - - /** - * Selects the item at the given index. - * @param index the list item index - * @throws IllegalArgumentException if {@code index} is negative or greater than or equal to size - */ - public void setSelectedIndex(int index) { - if (index < 0 || index >= items.length) - throw new IllegalArgumentException(); - this.itemIndex = index; + protected boolean canSelect(int index) { + return true; } - /** - * Returns the index of the selected item. - */ - public int getSelectedIndex() { return itemIndex; } + protected void itemSelected(int index, E item) { + } - /** - * Returns the selected item. - */ - public E getSelectedItem() { return items[itemIndex]; } + public E getSelectedItem() { + return items[selectedItemIndex]; + } - /** - * Returns the item at the given index. - * @param index the list item index - */ - public E getItemAt(int index) { return items[index]; } + public void setBackgroundColor(Color c) { + this.backgroundColor = c; + } - /** - * Returns the number of items in the list. - */ - public int getItemCount() { return items.length; } + public void setHighlightColor(Color c) { + this.highlightColor = c; + } - /** Sets the text color. */ - public void setTextColor(Color c) { this.textColor = c; } + public void setBorderColor(Color c) { + this.borderColor = c; + } - /** Sets the background color. */ - public void setBackgroundColor(Color c) { this.backgroundColor = c; } + public void setChevronDownColor(Color c) { + this.chevronDownColor = c; + } - /** Sets the highlight color. */ - public void setHighlightColor(Color c) { this.highlightColor = c; } - - /** Sets the border color. */ - public void setBorderColor(Color c) { this.borderColor = c; } - - /** Sets the down chevron color. */ - public void setChevronDownColor(Color c) { this.chevronDownColor = c; } - - /** Sets the right chevron color. */ - public void setChevronRightColor(Color c) { this.chevronRightColor = c; } + public void setChevronRightColor(Color c) { + this.chevronRightColor = c; + } } diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 499d5221..df63f5a9 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -17,10 +17,7 @@ */ package yugecin.opsudance.core.inject; -import itdelatrisu.opsu.states.ButtonMenu; -import itdelatrisu.opsu.states.MainMenu; -import itdelatrisu.opsu.states.SongMenu; -import itdelatrisu.opsu.states.Splash; +import itdelatrisu.opsu.states.*; import yugecin.opsudance.PreStartupInitializer; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.events.EventBus; @@ -59,6 +56,7 @@ public class OpsuDanceInjector extends Injector { bind(MainMenu.class).asEagerSingleton(); bind(ButtonMenu.class).asEagerSingleton(); bind(SongMenu.class).asEagerSingleton(); + bind(DownloadsMenu.class).asEagerSingleton(); } } From 06a5deb3a158911c39849a51fdcb5ecc8fa4e583 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 22:46:45 +0100 Subject: [PATCH 23/38] process common hotkeys in base state --- src/itdelatrisu/opsu/Options.java | 6 +++--- src/itdelatrisu/opsu/states/ButtonMenu.java | 20 +++++++------------ .../opsu/states/DownloadsMenu.java | 12 +---------- src/itdelatrisu/opsu/states/MainMenu.java | 13 ++++-------- src/itdelatrisu/opsu/states/SongMenu.java | 16 +++++---------- .../opsudance/core/state/BaseOpsuState.java | 15 ++++++++++++++ .../core/state/ComplexOpsuState.java | 3 +++ 7 files changed, 38 insertions(+), 47 deletions(-) diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index 2c033336..272b3057 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -395,8 +395,7 @@ public class Options { @Override public void clickListItem(int index) { targetFPSindex = index; - Container.instance.setTargetFrameRate(targetFPS[index]); - Container.instance.setVSync(targetFPS[index] == 60); + displayContainer.setFPS(targetFPS[index]); } @Override @@ -985,6 +984,7 @@ public class Options { PIPPI_SLIDER_FOLLOW_EXPAND ("Followcircle expand", "PippiFollowExpand", "Increase radius in followcircles", false), PIPPI_PREVENT_WOBBLY_STREAMS ("Prevent wobbly streams", "PippiPreventWobblyStreams", "Force linear mover while doing streams to prevent wobbly pippi", true); + public static DisplayContainer displayContainer; /** Option name. */ private final String name; @@ -1283,9 +1283,9 @@ public class Options { * bar notification about the action. */ public static void setNextFPS(DisplayContainer displayContainer) { + GameOption.displayContainer = displayContainer; // TODO dirty shit GameOption.TARGET_FPS.clickListItem((targetFPSindex + 1) % targetFPS.length); UI.sendBarNotification(String.format("Frame limiter: %s", GameOption.TARGET_FPS.getValueString())); - displayContainer.setFPS(GameOption.TARGET_FPS.val); } /** diff --git a/src/itdelatrisu/opsu/states/ButtonMenu.java b/src/itdelatrisu/opsu/states/ButtonMenu.java index 8533dbf9..ca899a0d 100644 --- a/src/itdelatrisu/opsu/states/ButtonMenu.java +++ b/src/itdelatrisu/opsu/states/ButtonMenu.java @@ -667,21 +667,15 @@ public class ButtonMenu extends BaseOpsuState { @Override public boolean keyPressed(int key, char c) { - switch (key) { - case Input.KEY_ESCAPE: - menuState.leave(); - return true; - case Input.KEY_F7: - // TODO - //Options.setNextFPS(displayContainer); - return true; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - return true; - case Input.KEY_F12: - Utils.takeScreenShot(); + if (super.keyPressed(key, c)) { return true; } + + if (key == Input.KEY_ESCAPE) { + menuState.leave(); + return true; + } + menuState.keyPressed(key, c); return true; } diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index ed6e47ec..6a2e7c89 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -893,7 +893,7 @@ public class DownloadsMenu extends ComplexOpsuState { } // block input during beatmap importing - if (importThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) { + if (importThread != null && key != Input.KEY_ESCAPE) { return true; } @@ -928,16 +928,6 @@ public class DownloadsMenu extends ComplexOpsuState { searchQuery.interrupt(); resetSearchTimer(); return true; - case Input.KEY_F7: - // TODO d - //Options.setNextFPS(container); - return true; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - return true; - case Input.KEY_F12: - Utils.takeScreenShot(); - return true; } // wait for user to finish typing if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) { diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index d1f63a9e..8bf821c0 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -634,6 +634,10 @@ public class MainMenu extends BaseOpsuState { @Override public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; + } + switch (key) { case Input.KEY_ESCAPE: case Input.KEY_Q: @@ -670,15 +674,6 @@ public class MainMenu extends BaseOpsuState { case Input.KEY_DOWN: UI.changeVolume(-1); return true; - case Input.KEY_F7: - Options.setNextFPS(displayContainer); - return true; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - return true; - case Input.KEY_F12: - Utils.takeScreenShot(); - return true; } return false; } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 3741aab4..788fb9a8 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -1064,8 +1064,12 @@ public class SongMenu extends BaseOpsuState { @Override public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; + } + // block input - if ((reloadThread != null && !(key == Input.KEY_ESCAPE || key == Input.KEY_F12)) || beatmapMenuTimer > -1 || isScrollingToFocusNode) { + if ((reloadThread != null && key != Input.KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) { return true; } @@ -1145,16 +1149,6 @@ public class SongMenu extends BaseOpsuState { displayContainer.switchState(ButtonMenu.class); } return true; - case Input.KEY_F7: - // TODO d - //Options.setNextFPS(container); - return true; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - return true; - case Input.KEY_F12: - Utils.takeScreenShot(); - return true; case Input.KEY_ENTER: if (focusNode == null) break; diff --git a/src/yugecin/opsudance/core/state/BaseOpsuState.java b/src/yugecin/opsudance/core/state/BaseOpsuState.java index 8c13315d..86bdfb9c 100644 --- a/src/yugecin/opsudance/core/state/BaseOpsuState.java +++ b/src/yugecin/opsudance/core/state/BaseOpsuState.java @@ -17,7 +17,10 @@ */ package yugecin.opsudance.core.state; +import itdelatrisu.opsu.Options; +import itdelatrisu.opsu.Utils; import org.newdawn.slick.Graphics; +import org.newdawn.slick.Input; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.events.EventListener; import yugecin.opsudance.events.ResolutionChangedEvent; @@ -89,6 +92,18 @@ public abstract class BaseOpsuState implements OpsuState, EventListener Date: Wed, 18 Jan 2017 22:50:18 +0100 Subject: [PATCH 24/38] remove the reset method from mainmenu --- .../opsu/states/DownloadsMenu.java | 2 - src/itdelatrisu/opsu/states/MainMenu.java | 38 ++++--------------- src/itdelatrisu/opsu/states/SongMenu.java | 2 - 3 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index 6a2e7c89..718be4dd 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -623,7 +623,6 @@ public class DownloadsMenu extends ComplexOpsuState { // back if (UI.getBackButton().contains(x, y)) { SoundController.playSound(SoundEffect.MENUBACK); - instanceContainer.provide(MainMenu.class).reset(); displayContainer.switchState(MainMenu.class); return true; } @@ -910,7 +909,6 @@ public class DownloadsMenu extends ComplexOpsuState { } else { // return to main menu SoundController.playSound(SoundEffect.MENUBACK); - instanceContainer.provide(MainMenu.class).reset(); displayContainer.switchState(MainMenu.class); } return true; diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index 8bf821c0..a56418fe 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -224,8 +224,6 @@ public class MainMenu extends BaseOpsuState { logoOpen = new AnimatedValue(100, 0, centerOffsetX, AnimationEquation.OUT_QUAD); logoClose = new AnimatedValue(2200, centerOffsetX, 0, AnimationEquation.OUT_QUAD); logoButtonAlpha = new AnimatedValue(200, 0f, 1f, AnimationEquation.LINEAR); - - reset(); } @Override @@ -459,6 +457,14 @@ public class MainMenu extends BaseOpsuState { @Override public void enter() { super.enter(); + + logo.setX(displayContainer.width / 2); + logoOpen.setTime(0); + logoClose.setTime(0); + logoButtonAlpha.setTime(0); + logoTimer = 0; + logoState = LogoState.DEFAULT; + UI.enter(); if (!enterNotification) { if (Updater.get().getStatus() == Updater.Status.UPDATE_AVAILABLE) { @@ -688,34 +694,6 @@ public class MainMenu extends BaseOpsuState { (cy > musicBarY && cy < musicBarY + musicBarHeight)); } - /** - * Resets the button states. - */ - public void reset() { - // reset logo - logo.setX(displayContainer.width / 2); - logoOpen.setTime(0); - logoClose.setTime(0); - logoButtonAlpha.setTime(0); - logoTimer = 0; - logoState = LogoState.DEFAULT; - - logo.resetHover(); - playButton.resetHover(); - exitButton.resetHover(); - musicPlay.resetHover(); - musicPause.resetHover(); - musicNext.resetHover(); - musicPrevious.resetHover(); - if (repoButton != null) - repoButton.resetHover(); - if (danceRepoButton != null) - danceRepoButton.resetHover(); - updateButton.resetHover(); - restartButton.resetHover(); - downloadsButton.resetHover(); - } - /** * Plays the next track, and adds the previous one to the stack. * @param user {@code true} if this was user-initiated, false otherwise (track end) diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index 788fb9a8..af2ca892 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -941,7 +941,6 @@ public class SongMenu extends BaseOpsuState { if (UI.getBackButton().contains(x, y)) { SoundController.playSound(SoundEffect.MENUBACK); - instanceContainer.provide(MainMenu.class).reset(); // TODO d why is this needed displayContainer.switchState(MainMenu.class); return true; } @@ -1091,7 +1090,6 @@ public class SongMenu extends BaseOpsuState { } else*/ { // return to main menu SoundController.playSound(SoundEffect.MENUBACK); - instanceContainer.provide(MainMenu.class).reset(); // TODO d is this needed displayContainer.switchState(MainMenu.class); } return true; From 04449abe62ca769bc8d3d5544254cfea895b5da3 Mon Sep 17 00:00:00 2001 From: yugecin Date: Wed, 18 Jan 2017 23:08:23 +0100 Subject: [PATCH 25/38] readd search field and sort menu in songmenu --- src/itdelatrisu/opsu/states/SongMenu.java | 200 +++++++----------- .../core/state/ComplexOpsuState.java | 2 +- 2 files changed, 79 insertions(+), 123 deletions(-) diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index af2ca892..ce6f431c 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -22,7 +22,6 @@ import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.GameData.Grade; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameMod; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.Utils; @@ -62,25 +61,16 @@ import java.nio.file.WatchEvent.Kind; import java.util.Map; import java.util.Stack; -import org.lwjgl.opengl.Display; import org.newdawn.slick.Animation; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; import org.newdawn.slick.SpriteSheet; import org.newdawn.slick.gui.TextField; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; -import org.newdawn.slick.state.transition.EmptyTransition; -import org.newdawn.slick.state.transition.FadeInTransition; import yugecin.opsudance.core.DisplayContainer; -import yugecin.opsudance.core.events.EventListener; import yugecin.opsudance.core.inject.InstanceContainer; -import yugecin.opsudance.core.state.BaseOpsuState; -import yugecin.opsudance.events.ResolutionChangedEvent; +import yugecin.opsudance.core.state.ComplexOpsuState; /** * "Song Selection" state. @@ -88,7 +78,7 @@ import yugecin.opsudance.events.ResolutionChangedEvent; * Players are able to select a beatmap to play, view previous scores, choose game mods, * manage beatmaps, or change game options from this state. */ -public class SongMenu extends BaseOpsuState { +public class SongMenu extends ComplexOpsuState { private final InstanceContainer instanceContainer; @@ -176,8 +166,7 @@ public class SongMenu extends BaseOpsuState { private MenuButton selectModsButton, selectRandomButton, selectMapOptionsButton, selectOptionsButton; /** The search textfield. */ - //private TextField search; - // TODO d recreate textfield + private TextField searchTextField; /** * Delay timer, in milliseconds, before running another search. @@ -238,7 +227,7 @@ public class SongMenu extends BaseOpsuState { } finally { finished = true; } - }; + } /** Reloads all beatmaps. */ private void reloadBeatmaps() { @@ -329,8 +318,7 @@ public class SongMenu extends BaseOpsuState { private boolean isScrollingToFocusNode = false; /** Sort order dropdown menu. */ - // TODO: d remake dropdownmenu - //private DropdownMenu sortMenu; + private DropdownMenu sortMenu; public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) { super(displayContainer); @@ -357,11 +345,10 @@ public class SongMenu extends BaseOpsuState { footerLogoButton.setHoverExpand(1.2f); // initialize sorts - // TODO d reenable dropdown - /* int sortWidth = (int) (displayContainer.width * 0.12f); - sortMenu = new DropdownMenu(container, BeatmapSortOrder.values(), - displayContainer.width * 0.87f, headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f, sortWidth) { + int posX = (int) (displayContainer.width * 0.87f); + int posY = (int) (headerY - GameImage.MENU_TAB.getImage().getHeight() * 2.25f); + sortMenu = new DropdownMenu(displayContainer, BeatmapSortOrder.values(), posX, posY, sortWidth) { @Override public void itemSelected(int index, BeatmapSortOrder item) { BeatmapSortOrder.set(item); @@ -375,7 +362,7 @@ public class SongMenu extends BaseOpsuState { } @Override - public boolean menuClicked(int index) { + public boolean canSelect(int index) { if (isInputBlocked()) return false; @@ -386,7 +373,7 @@ public class SongMenu extends BaseOpsuState { sortMenu.setBackgroundColor(Colors.BLACK_BG_HOVER); sortMenu.setBorderColor(Colors.BLUE_DIVIDER); sortMenu.setChevronRightColor(Color.white); - */ + components.add(sortMenu); // initialize group tabs for (BeatmapGroup group : BeatmapGroup.values()) @@ -406,20 +393,20 @@ public class SongMenu extends BaseOpsuState { buttonOffset = (footerY - headerY - DIVIDER_LINE_WIDTH) / MAX_SONG_BUTTONS; // search - // TODO d reenable search box - /* int textFieldX = (int) (displayContainer.width * 0.7125f + Fonts.BOLD.getWidth("Search: ")); int textFieldY = (int) (headerY + Fonts.BOLD.getLineHeight() / 2); - search = new TextField( - container, Fonts.BOLD, textFieldX, textFieldY, - (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight() - ); - search.setBackgroundColor(Color.transparent); - search.setBorderColor(Color.transparent); - search.setTextColor(Color.white); - search.setConsumeEvents(false); - search.setMaxLength(60); - */ + searchTextField = new TextField(displayContainer, Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) { + @Override + public boolean isFocusable() { + return false; + } + }; + searchTextField.setBackgroundColor(Color.transparent); + searchTextField.setBorderColor(Color.transparent); + searchTextField.setTextColor(Color.white); + searchTextField.setMaxLength(60); + searchTextField.setFocused(true); + components.add(searchTextField); // selection buttons Image selectionMods = GameImage.SELECTION_MODS.getImage(); @@ -482,9 +469,6 @@ public class SongMenu extends BaseOpsuState { int mouseX = displayContainer.mouseX; int mouseY = displayContainer.mouseY; - // TODO d - //boolean inDropdownMenu = sortMenu.contains(mouseX, mouseY); - // background if (focusNode != null) { Beatmap focusNodeBeatmap = focusNode.getSelectedBeatmap(); @@ -555,11 +539,9 @@ public class SongMenu extends BaseOpsuState { g.clearClip(); // scroll bar - // TODO d - /* - if (focusScores.length > MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY) && !inDropdownMenu) + if (focusScores.length > MAX_SCORE_BUTTONS && ScoreData.areaContains(mouseX, mouseY) && !isAnyComponentFocused()) { ScoreData.drawScrollbar(g, startScorePos.getPosition(), focusScores.length * ScoreData.getButtonOffset()); - */ + } } // top/bottom bars @@ -576,9 +558,7 @@ public class SongMenu extends BaseOpsuState { Float position = MusicController.getBeatProgress(); if (position == null) // default to 60bpm position = System.currentTimeMillis() % 1000 / 1000f; - // TODO d - /* - if (footerLogoButton.contains(mouseX, mouseY, 0.25f) && !inDropdownMenu) { + if (footerLogoButton.contains(mouseX, mouseY, 0.25f)) { // hovering over logo: stop pulsing footerLogoButton.draw(); } else { @@ -591,7 +571,6 @@ public class SongMenu extends BaseOpsuState { ghostLogo.drawCentered(footerLogoButton.getX(), footerLogoButton.getY(), Colors.GHOST_LOGO); Colors.GHOST_LOGO.a = oldGhostAlpha; } - */ // header if (focusNode != null) { @@ -672,9 +651,7 @@ public class SongMenu extends BaseOpsuState { // group tabs BeatmapGroup currentGroup = BeatmapGroup.current(); BeatmapGroup hoverGroup = null; - // TODO d - /* - if (!inDropdownMenu) { + if (!isAnyComponentFocused()) { for (BeatmapGroup group : BeatmapGroup.values()) { if (group.contains(mouseX, mouseY)) { hoverGroup = group; @@ -682,7 +659,6 @@ public class SongMenu extends BaseOpsuState { } } } - */ for (BeatmapGroup group : BeatmapGroup.VALUES_REVERSED) { if (group != currentGroup) group.draw(false, group == hoverGroup); @@ -690,10 +666,9 @@ public class SongMenu extends BaseOpsuState { currentGroup.draw(true, false); // search - // TODO d - /* - boolean searchEmpty = search.getText().isEmpty(); - int searchX = search.getX(), searchY = search.getY(); + boolean searchEmpty = searchTextField.getText().isEmpty(); + int searchX = searchTextField.x; + int searchY = searchTextField.y; float searchBaseX = width * 0.7f; float searchTextX = width * 0.7125f; float searchRectHeight = Fonts.BOLD.getLineHeight() * 2; @@ -712,21 +687,15 @@ public class SongMenu extends BaseOpsuState { g.fillRect(searchBaseX, headerY + DIVIDER_LINE_WIDTH / 2, width - searchBaseX, searchRectHeight); Colors.BLACK_ALPHA.a = oldAlpha; Fonts.BOLD.drawString(searchTextX, searchY, "Search:", Colors.GREEN_SEARCH); - if (searchEmpty) + if (searchEmpty) { Fonts.BOLD.drawString(searchX, searchY, "Type to search!", Color.white); - else { + } else { g.setColor(Color.white); - // TODO: why is this needed to correctly position the TextField? - search.setLocation(searchX - 3, searchY - 1); - search.render(container, g); - search.setLocation(searchX, searchY); - Fonts.DEFAULT.drawString(searchTextX, searchY + Fonts.BOLD.getLineHeight(), - (searchResultString == null) ? "Searching..." : searchResultString, Color.white); + searchTextField.render(g); + Fonts.DEFAULT.drawString(searchTextX, searchY + Fonts.BOLD.getLineHeight(), (searchResultString == null) ? "Searching..." : searchResultString, Color.white); } - // sorting options - sortMenu.render(container, g); - */ + sortMenu.render(g); // reloading beatmaps if (reloadThread != null) { @@ -766,7 +735,6 @@ public class SongMenu extends BaseOpsuState { } int mouseX = displayContainer.mouseX; int mouseY = displayContainer.mouseY; - boolean inDropdownMenu = false; // TODO d sortMenu.contains(mouseX, mouseY); UI.getBackButton().hoverUpdate(delta, mouseX, mouseY); selectModsButton.hoverUpdate(delta, mouseX, mouseY); selectRandomButton.hoverUpdate(delta, mouseX, mouseY); @@ -805,9 +773,6 @@ public class SongMenu extends BaseOpsuState { starStream.update(delta); // search - // TODO d - /* - search.setFocus(true); searchTimer += delta; if (searchTimer >= SEARCH_DELAY && reloadThread == null && beatmapMenuTimer == -1) { searchTimer = 0; @@ -816,12 +781,12 @@ public class SongMenu extends BaseOpsuState { if (focusNode != null) oldFocusNode = new SongNode(BeatmapSetList.get().getBaseNode(focusNode.index), focusNode.beatmapIndex); - if (BeatmapSetList.get().search(search.getText())) { + if (BeatmapSetList.get().search(searchTextField.getText())) { // reset song stack - randomStack = new Stack(); + randomStack = new Stack<>(); // empty search - if (search.getText().isEmpty()) + if (searchTextField.getText().isEmpty()) searchResultString = null; // search produced new list: re-initialize it @@ -830,7 +795,7 @@ public class SongMenu extends BaseOpsuState { focusScores = null; if (BeatmapSetList.get().size() > 0) { BeatmapSetList.get().init(); - if (search.getText().isEmpty()) { // cleared search + if (searchTextField.getText().isEmpty()) { // cleared search // use previous start/focus if possible if (oldFocusNode != null) setFocus(oldFocusNode.getNode(), oldFocusNode.getIndex(), true, true); @@ -843,7 +808,7 @@ public class SongMenu extends BaseOpsuState { setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true); } oldFocusNode = null; - } else if (!search.getText().isEmpty()) + } else if (!searchTextField.getText().isEmpty()) searchResultString = "No matches found. Hit ESC to reset."; } } @@ -852,7 +817,6 @@ public class SongMenu extends BaseOpsuState { if (searchTransitionTimer > SEARCH_TRANSITION_TIME) searchTransitionTimer = SEARCH_TRANSITION_TIME; } - */ // scores if (focusScores != null) { @@ -874,7 +838,7 @@ public class SongMenu extends BaseOpsuState { // mouse hover BeatmapSetNode node = getNodeAtPosition(mouseX, mouseY); - if (node != null && !inDropdownMenu) { + if (node != null && !isAnyComponentFocused()) { if (node == hoverIndex) hoverOffset.update(delta); else { @@ -888,11 +852,9 @@ public class SongMenu extends BaseOpsuState { } // tooltips - // TODO d - /* if (sortMenu.baseContains(mouseX, mouseY)) UI.updateTooltip(delta, "Sort by...", false); - else */if (focusScores != null && ScoreData.areaContains(mouseX, mouseY)) { + else if (focusScores != null && ScoreData.areaContains(mouseX, mouseY)) { int startScore = (int) (startScorePos.getPosition() / ScoreData.getButtonOffset()); int offset = (int) (-startScorePos.getPosition() + startScore * ScoreData.getButtonOffset()); int scoreButtons = Math.min(focusScores.length - startScore, MAX_SCORE_BUTTONS); @@ -909,6 +871,10 @@ public class SongMenu extends BaseOpsuState { @Override public boolean mousePressed(int button, int x, int y) { + if (super.mousePressed(button, x, y)) { + return true; + } + if (button == Input.MOUSE_MIDDLE_BUTTON) { return false; } @@ -924,6 +890,10 @@ public class SongMenu extends BaseOpsuState { @Override public boolean mouseReleased(int button, int x, int y) { + if (super.mouseReleased(button, x, y)) { + return true; + } + if (button == Input.MOUSE_MIDDLE_BUTTON) { return false; } @@ -973,7 +943,7 @@ public class SongMenu extends BaseOpsuState { songInfo = null; scoreMap = null; focusScores = null; - // TODO d search.setText(""); + searchTextField.setText(""); searchTimer = SEARCH_DELAY; searchTransitionTimer = SEARCH_TRANSITION_TIME; searchResultString = null; @@ -1076,18 +1046,16 @@ public class SongMenu extends BaseOpsuState { switch (key) { case Input.KEY_ESCAPE: - // TODO d - /* if (reloadThread != null) { // beatmap reloading: stop parsing beatmaps by sending interrupt to BeatmapParser reloadThread.interrupt(); - } else if (!search.getText().isEmpty()) { + } else if (!searchTextField.getText().isEmpty()) { // clear search text - search.setText(""); + searchTextField.setText(""); searchTimer = SEARCH_DELAY; searchTransitionTimer = 0; searchResultString = null; - } else*/ { + } else { // return to main menu SoundController.playSound(SoundEffect.MENUBACK); displayContainer.switchState(MainMenu.class); @@ -1206,9 +1174,8 @@ public class SongMenu extends BaseOpsuState { // TODO: accept all characters (current conditions are from TextField class) if ((c > 31 && c < 127) || key == Input.KEY_BACK) { searchTimer = 0; - // TODO d - //int textLength = search.getText().length(); - int textLength = 0; + searchTextField.keyPressed(key, c); + int textLength = searchTextField.getText().length(); if (lastSearchTextLength != textLength) { if (key == Input.KEY_BACK) { if (textLength == 0) @@ -1223,36 +1190,38 @@ public class SongMenu extends BaseOpsuState { return true; } - // TODO d - /* @Override - public void mouseDragged(int oldx, int oldy, int newx, int newy) { - // block input - if (isInputBlocked()) - return; + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { + if (super.mouseDragged(oldx, oldy, newx, newy)) { + return true; + } + + if (isInputBlocked()) { + return true; + } int diff = newy - oldy; - if (diff == 0) - return; + if (diff == 0) { + return false; + } // check mouse button (right click scrolls faster on songs) int multiplier; - if (input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) + if (displayContainer.input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) { multiplier = 10; - else if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) + } else if (displayContainer.input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) { multiplier = 1; - else - return; + } else { + return false; + } - // score buttons - if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(oldx, oldy)) + if (focusScores != null && focusScores.length >= MAX_SCORE_BUTTONS && ScoreData.areaContains(oldx, oldy)) { startScorePos.dragged(-diff * multiplier); - - // song buttons - else + } else { songScrolling.dragged(-diff * multiplier); + } + return true; } - */ @Override public boolean mouseWheelMoved(int newValue) { @@ -1302,12 +1271,10 @@ public class SongMenu extends BaseOpsuState { songChangeTimer.setTime(songChangeTimer.getDuration()); musicIconBounceTimer.setTime(musicIconBounceTimer.getDuration()); starStream.clear(); - // TODO d - //sortMenu.activate(); - //sortMenu.reset(); + sortMenu.reset(); // reset song stack - randomStack = new Stack(); + randomStack = new Stack<>(); // reload beatmaps if song folder changed if (songFolderChanged && stateAction != MenuState.RELOAD) @@ -1467,16 +1434,6 @@ public class SongMenu extends BaseOpsuState { } } - @Override - public void leave() { - super.leave(); - // TODO d - /* - search.setFocus(false); - sortMenu.deactivate(); - */ - } - /** * Shifts the startNode forward (+) or backwards (-) by a given number of nodes. * Initiates sliding "animation" by shifting the button Y position. @@ -1734,8 +1691,7 @@ public class SongMenu extends BaseOpsuState { songInfo = null; hoverOffset.setTime(0); hoverIndex = null; - // TODO d - //search.setText(""); + searchTextField.setText(""); searchTimer = SEARCH_DELAY; searchTransitionTimer = SEARCH_TRANSITION_TIME; searchResultString = null; diff --git a/src/yugecin/opsudance/core/state/ComplexOpsuState.java b/src/yugecin/opsudance/core/state/ComplexOpsuState.java index f3d1a634..e6e12608 100644 --- a/src/yugecin/opsudance/core/state/ComplexOpsuState.java +++ b/src/yugecin/opsudance/core/state/ComplexOpsuState.java @@ -73,7 +73,7 @@ public class ComplexOpsuState extends BaseOpsuState { } focusedComponent.setFocused(false); focusedComponent = null; - return false; + return true; } @Override From e7eec143419094e579de760c0eacd46f3ed31790 Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 19 Jan 2017 16:03:53 +0100 Subject: [PATCH 26/38] add options menu as overlay --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/Options.java | 11 +- src/itdelatrisu/opsu/states/OptionsMenu.java | 125 +---------------- src/itdelatrisu/opsu/states/SongMenu.java | 19 ++- .../core/state/ComplexOpsuState.java | 77 ++++++++++- .../core/state/OverlayOpsuState.java | 117 ++++++++++++++++ src/yugecin/opsudance/ui/OptionsOverlay.java | 128 +++++++++++------- src/yugecin/opsudance/ui/SBOverlay.java | 8 +- 8 files changed, 297 insertions(+), 190 deletions(-) create mode 100644 src/yugecin/opsudance/core/state/OverlayOpsuState.java diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 7547cb0d..73493858 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -92,7 +92,7 @@ public class Opsu extends StateBasedGame { addState(new Game(STATE_GAME)); addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); addState(new GameRanking(STATE_GAMERANKING)); - addState(new OptionsMenu(STATE_OPTIONSMENU)); + //addState(new OptionsMenu(STATE_OPTIONSMENU)); //addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); } diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index 272b3057..03a8c772 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -415,8 +415,7 @@ public class Options { SHOW_FPS ("Show FPS Counter", "FpsCounter", "Show an FPS counter in the bottom-right hand corner.", true), SHOW_UNICODE ("Prefer Non-English Metadata", "ShowUnicode", "Where available, song titles will be shown in their native language.", false) { @Override - public void click(GameContainer container) { - super.click(container); + public void click() { if (bool) { try { Fonts.LARGE.loadGlyphs(); @@ -468,8 +467,7 @@ public class Options { }, NEW_CURSOR ("Enable New Cursor", "NewCursor", "Use the new cursor style (may cause higher CPU usage).", true) { @Override - public void click(GameContainer container) { - super.click(container); + public void click() { UI.getCursor().reset(); } }, @@ -1131,9 +1129,8 @@ public class Options { * Processes a mouse click action (via override). *

* By default, this inverts the current {@code bool} field. - * @param container the game container */ - public void click(GameContainer container) { bool = !bool; } + public void click() { bool = !bool; } /** * Get a list of values to choose from @@ -1697,7 +1694,7 @@ public class Options { * sends a bar notification about the action. */ public static void toggleMouseDisabled() { - GameOption.DISABLE_MOUSE_BUTTONS.click(null); + GameOption.DISABLE_MOUSE_BUTTONS.click(); UI.sendBarNotification((GameOption.DISABLE_MOUSE_BUTTONS.getBooleanValue()) ? "Mouse buttons are disabled." : "Mouse buttons are enabled."); } diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index 39ffa7ca..03e458b5 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -18,35 +18,14 @@ package itdelatrisu.opsu.states; -import itdelatrisu.opsu.GameImage; -import itdelatrisu.opsu.Opsu; -import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Options.GameOption; -import itdelatrisu.opsu.audio.MusicController; -import itdelatrisu.opsu.audio.SoundController; -import itdelatrisu.opsu.audio.SoundEffect; -import itdelatrisu.opsu.ui.UI; -import org.newdawn.slick.GameContainer; -import org.newdawn.slick.Graphics; -import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.FadeInTransition; -import org.newdawn.slick.state.transition.EmptyTransition; import yugecin.opsudance.ui.OptionsOverlay; import yugecin.opsudance.ui.OptionsOverlay.OptionTab; -/** - * "Game Options" state. - *

- * Players are able to view and change various game settings in this state. - */ -public class OptionsMenu extends BasicGameState implements OptionsOverlay.Parent { +public class OptionsMenu { - /** Option tabs. */ - private static final OptionTab[] options = new OptionsOverlay.OptionTab[]{ + public static final OptionTab[] normalOptions = new OptionsOverlay.OptionTab[]{ new OptionTab("Display", new GameOption[]{ GameOption.SCREEN_RESOLUTION, GameOption.FULLSCREEN, @@ -154,104 +133,4 @@ public class OptionsMenu extends BasicGameState implements OptionsOverlay.Parent }) }; - private StateBasedGame game; - private Input input; - private final int state; - - private OptionsOverlay optionsOverlay; - - public OptionsMenu(int state) { - this.state = state; - } - - @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.game = game; - this.input = container.getInput(); - - optionsOverlay = new OptionsOverlay(this, options, 5, container); - } - - @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException { - // background - GameImage.OPTIONS_BG.getImage().draw(); - - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - optionsOverlay.render(g, mouseX, mouseY); - UI.draw(g); - } - - @Override - public void update(GameContainer container, StateBasedGame game, int delta) throws SlickException { - UI.update(delta); - MusicController.loopTrackIfEnded(false); - optionsOverlay.update(delta, input.getMouseX(), input.getMouseY()); - } - - @Override - public int getID() { - return state; - } - - @Override - public void mouseReleased(int button, int x, int y) { - optionsOverlay.mouseReleased(button, x, y); - } - - @Override - public void mousePressed(int button, int x, int y) { - optionsOverlay.mousePressed(button, x, y); - } - - @Override - public void mouseDragged(int oldx, int oldy, int newx, int newy) { - optionsOverlay.mouseDragged(oldx, oldy, newx, newy); - } - - @Override - public void mouseWheelMoved(int newValue) { - optionsOverlay.mouseWheelMoved(newValue); - } - - @Override - public void keyPressed(int key, char c) { - optionsOverlay.keyPressed(key, c); - } - - /** - * This string is built with option values when entering the options menu. - * When leaving the options menu, this string is checked against the new optionstring with the same options. - * If those do not match, it means some option has change which requires a restart - */ - private String restartOptions; - - @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { - UI.enter(); - restartOptions = "" + Options.getResolutionIdx() + Options.isFullscreen() + Options.allowLargeResolutions() + Options.getSkinName(); - } - - @Override - public void leave(GameContainer container, StateBasedGame game) throws SlickException { - if (!("" + Options.getResolutionIdx() + Options.isFullscreen() + Options.allowLargeResolutions() + Options.getSkinName()).equals(restartOptions)) { - container.setForceExit(false); - container.exit(); - return; - } - SoundController.playSound(SoundEffect.MENUBACK); - } - - @Override - public void onLeave() { - game.enterState(Opsu.STATE_SONGMENU, new EmptyTransition(), new FadeInTransition()); - } - - @Override - public void onSaveOption(GameOption option) { - - } - } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index ce6f431c..aeef2f1e 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -71,6 +71,7 @@ import org.newdawn.slick.gui.TextField; import yugecin.opsudance.core.DisplayContainer; import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.state.ComplexOpsuState; +import yugecin.opsudance.ui.OptionsOverlay; /** * "Song Selection" state. @@ -320,15 +321,21 @@ public class SongMenu extends ComplexOpsuState { /** Sort order dropdown menu. */ private DropdownMenu sortMenu; + private final OptionsOverlay optionsOverlay; + public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) { super(displayContainer); this.instanceContainer = instanceContainer; + optionsOverlay = new OptionsOverlay(this, displayContainer, OptionsMenu.normalOptions, 0); + overlays.add(optionsOverlay); } @Override public void revalidate() { super.revalidate(); + components.clear(); + // header/footer coordinates headerY = displayContainer.height * 0.0075f + GameImage.MENU_MUSICNOTE.getImage().getHeight() + Fonts.BOLD.getLineHeight() + Fonts.DEFAULT.getLineHeight() + @@ -460,8 +467,6 @@ public class SongMenu extends ComplexOpsuState { @Override public void render(Graphics g) { - super.render(g); - g.setBackground(Color.black); int width = displayContainer.width; @@ -711,6 +716,8 @@ public class SongMenu extends ComplexOpsuState { UI.getBackButton().draw(); UI.draw(g); + + super.render(g); } @Override @@ -927,7 +934,7 @@ public class SongMenu extends ComplexOpsuState { return true; } else if (selectOptionsButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUHIT); - // TODO d displayContainer.switchState(OptionsMenu.class); + optionsOverlay.show(); return true; } @@ -1166,7 +1173,7 @@ public class SongMenu extends ComplexOpsuState { return true; case Input.KEY_O: if (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL)) { - // TODO d displayContainer.switchState(OptionsMenu.class); + optionsOverlay.show(); } return true; default: @@ -1225,6 +1232,10 @@ public class SongMenu extends ComplexOpsuState { @Override public boolean mouseWheelMoved(int newValue) { + if (super.mouseWheelMoved(newValue)) { + return true; + } + Input input = displayContainer.input; if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) { diff --git a/src/yugecin/opsudance/core/state/ComplexOpsuState.java b/src/yugecin/opsudance/core/state/ComplexOpsuState.java index e6e12608..d0dc544e 100644 --- a/src/yugecin/opsudance/core/state/ComplexOpsuState.java +++ b/src/yugecin/opsudance/core/state/ComplexOpsuState.java @@ -24,15 +24,17 @@ import yugecin.opsudance.core.components.Component; import java.util.LinkedList; -public class ComplexOpsuState extends BaseOpsuState { +public abstract class ComplexOpsuState extends BaseOpsuState { protected final LinkedList components; + protected final LinkedList overlays; private Component focusedComponent; public ComplexOpsuState(DisplayContainer displayContainer) { super(displayContainer); this.components = new LinkedList<>(); + this.overlays = new LinkedList<>(); } public final void focusComponent(Component component) { @@ -47,11 +49,55 @@ public class ComplexOpsuState extends BaseOpsuState { } public boolean isAnyComponentFocused() { - return focusedComponent != null; + return focusedComponent != null || isAnyOverlayActive(); + } + + public boolean isAnyOverlayActive() { + for (OverlayOpsuState overlay : overlays) { + if (overlay.active) { + return true; + } + } + return false; + } + + @Override + public boolean mouseWheelMoved(int delta) { + for (OverlayOpsuState overlay : overlays) { + if (overlay.mouseWheelMoved(delta)) { + return true; + } + } + return false; + } + + @Override + public boolean mousePressed(int button, int x, int y) { + for (OverlayOpsuState overlay : overlays) { + if (overlay.mousePressed(button, x, y)) { + return true; + } + } + return false; + } + + @Override + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { + for (OverlayOpsuState overlay : overlays) { + if (overlay.mouseDragged(oldx, oldy, newx, newy)) { + return true; + } + } + return false; } @Override public boolean mouseReleased(int button, int x, int y) { + for (OverlayOpsuState overlay : overlays) { + if (overlay.mouseReleased(button, x, y)) { + return true; + } + } if (focusedComponent == null) { for (Component component : components) { if (!component.isFocusable()) { @@ -83,14 +129,25 @@ public class ComplexOpsuState extends BaseOpsuState { component.updateHover(displayContainer.mouseX, displayContainer.mouseY); component.preRenderUpdate(); } + for (OverlayOpsuState overlay : overlays) { + overlay.preRenderUpdate(); + } + } + + @Override + protected void revalidate() { + super.revalidate(); + for (OverlayOpsuState overlay : overlays) { + overlay.revalidate(); + } } @Override public void render(Graphics g) { - super.render(g); - for (Component component : components) { - component.render(g); + for (OverlayOpsuState overlay : overlays) { + overlay.render(g); } + super.render(g); } @Override @@ -98,6 +155,11 @@ public class ComplexOpsuState extends BaseOpsuState { if (super.keyReleased(key, c)) { return true; } + for (OverlayOpsuState overlay : overlays) { + if (overlay.keyReleased(key, c)) { + return true; + } + } if (focusedComponent != null) { if (key == Input.KEY_ESCAPE) { focusedComponent.setFocused(false); @@ -112,6 +174,11 @@ public class ComplexOpsuState extends BaseOpsuState { @Override public boolean keyPressed(int key, char c) { + for (OverlayOpsuState overlay : overlays) { + if (overlay.keyPressed(key, c)) { + return true; + } + } if (focusedComponent != null) { if (key == Input.KEY_ESCAPE) { focusedComponent.setFocused(false); diff --git a/src/yugecin/opsudance/core/state/OverlayOpsuState.java b/src/yugecin/opsudance/core/state/OverlayOpsuState.java new file mode 100644 index 00000000..f5df8b46 --- /dev/null +++ b/src/yugecin/opsudance/core/state/OverlayOpsuState.java @@ -0,0 +1,117 @@ +/* + * 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; + +import org.newdawn.slick.Graphics; + +import java.io.StringWriter; + +public abstract class OverlayOpsuState implements OpsuState { + + protected boolean active; + protected boolean acceptInput; + + public abstract void hide(); + public abstract void show(); + + @Override + public final void update() { + } + + public void revalidate() { + } + + protected abstract void onPreRenderUpdate(); + + @Override + public final void preRenderUpdate() { + if (active) { + onPreRenderUpdate(); + } + } + + protected abstract void onRender(Graphics g); + + @Override + public final void render(Graphics g) { + if (active) { + onRender(g); + } + } + + @Override + public final void enter() { + } + + @Override + public final void leave() { + } + + @Override + public final boolean onCloseRequest() { + return true; + } + + protected abstract boolean onKeyPressed(int key, char c); + + @Override + public final boolean keyPressed(int key, char c) { + return acceptInput && onKeyPressed(key, c); + } + + protected abstract boolean onKeyReleased(int key, char c); + + @Override + public final boolean keyReleased(int key, char c) { + return acceptInput && onKeyReleased(key, c); + } + + protected abstract boolean onMouseWheelMoved(int delta); + + @Override + public final boolean mouseWheelMoved(int delta) { + return acceptInput && onMouseWheelMoved(delta); + } + + protected abstract boolean onMousePressed(int button, int x, int y); + + @Override + public final boolean mousePressed(int button, int x, int y) { + return acceptInput && onMousePressed(button, x, y); + } + + protected abstract boolean onMouseReleased(int button, int x, int y); + + @Override + public final boolean mouseReleased(int button, int x, int y) { + return acceptInput && onMouseReleased(button, x, y); + } + + protected abstract boolean onMouseDragged(int oldx, int oldy, int newx, int newy); + + @Override + public final boolean mouseDragged(int oldx, int oldy, int newx, int newy) { + return acceptInput && onMouseDragged(oldx, oldy, newx, newy); + } + + @Override + public void writeErrorDump(StringWriter dump) { + dump.append("> OverlayOpsuState dump\n"); + dump.append("accepts input: ").append(String.valueOf(acceptInput)).append(" is active: ").append(String.valueOf(active)); + } +} diff --git a/src/yugecin/opsudance/ui/OptionsOverlay.java b/src/yugecin/opsudance/ui/OptionsOverlay.java index fdff1e3f..447a41b8 100644 --- a/src/yugecin/opsudance/ui/OptionsOverlay.java +++ b/src/yugecin/opsudance/ui/OptionsOverlay.java @@ -29,16 +29,18 @@ import itdelatrisu.opsu.ui.Fonts; import itdelatrisu.opsu.ui.MenuButton; import itdelatrisu.opsu.ui.UI; import org.newdawn.slick.*; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.state.ComplexOpsuState; +import yugecin.opsudance.core.state.OverlayOpsuState; -@SuppressWarnings("UnusedParameters") -public class OptionsOverlay { +public class OptionsOverlay extends OverlayOpsuState { - private Parent parent; - private GameContainer container; + private final ComplexOpsuState parent; + private final DisplayContainer displayContainer; - private final Image sliderBallImg; - private final Image checkOnImg; - private final Image checkOffImg; + private Image sliderBallImg; + private Image checkOnImg; + private Image checkOffImg; private OptionTab[] tabs; private int selectedTab; @@ -79,21 +81,26 @@ public class OptionsOverlay { private int sliderSoundDelay; - public OptionsOverlay(Parent parent, OptionTab[] tabs, int defaultSelectedTabIndex, GameContainer container) { + public OptionsOverlay(ComplexOpsuState parent, DisplayContainer displayContainer, OptionTab[] tabs, int defaultSelectedTabIndex) { this.parent = parent; - this.container = container; + this.displayContainer = displayContainer; this.tabs = tabs; selectedTab = defaultSelectedTabIndex; listHoverIndex = -1; + } + + @Override + public void revalidate() { + super.revalidate(); sliderBallImg = GameImage.CONTROL_SLIDER_BALL.getImage().getScaledCopy(20, 20); checkOnImg = GameImage.CONTROL_CHECK_ON.getImage().getScaledCopy(20, 20); checkOffImg = GameImage.CONTROL_CHECK_OFF.getImage().getScaledCopy(20, 20); - width = container.getWidth(); - height = container.getHeight(); + width = displayContainer.width; + height = displayContainer.height; // calculate positions optionWidth = width / 2; @@ -109,10 +116,12 @@ public class OptionsOverlay { maxScrollOffset = Fonts.MEDIUM.getLineHeight() * 2 * tabs.length; scrollOffset = 0; for (OptionTab tab : tabs) { + /* if (defaultSelectedTabIndex-- > 0) { scrollOffset += Fonts.MEDIUM.getLineHeight() * 2; scrollOffset += tab.options.length * optionHeight; } + */ maxScrollOffset += tab.options.length * optionHeight; tab.button = new MenuButton(tabImage, tabX, tabY); tabX += tabOffset; @@ -127,7 +136,8 @@ public class OptionsOverlay { optionStartY = (int) (tabY + tabImage.getHeight() / 2 + 2); // +2 for the separator line } - public void render(Graphics g, int mouseX, int mouseY) { + @Override + public void onRender(Graphics g) { // bg g.setColor(Colors.BLACK_ALPHA_75); g.fillRect(0, 0, width, height); @@ -136,7 +146,7 @@ public class OptionsOverlay { renderTitle(); // option tabs - renderTabs(mouseX, mouseY); + renderTabs(); // line separator g.setColor(Color.white); @@ -159,7 +169,7 @@ public class OptionsOverlay { UI.getBackButton().draw(); // tooltip - renderTooltip(g, mouseX, mouseY); + renderTooltip(g); // key input options if (keyEntryLeft || keyEntryRight) { @@ -175,15 +185,10 @@ public class OptionsOverlay { Fonts.LARGE.drawString((width - Fonts.LARGE.getWidth(prompt)) / 2, (height - Fonts.LARGE.getLineHeight()) / 2, prompt); } - private void renderTooltip(Graphics g, int mouseX, int mouseY) { + private void renderTooltip(Graphics g) { if (hoverOption != null) { - String optionDescription = hoverOption.getDescription(); - float textWidth = Fonts.SMALL.getWidth(optionDescription); - Color.black.a = 0.7f; - g.setColor(Color.black); - g.fillRoundRect(mouseX + 10, mouseY + 10, 10 + textWidth, 10 + Fonts.SMALL.getLineHeight(), 4); - Fonts.SMALL.drawString(mouseX + 15, mouseY + 15, optionDescription, Color.white); - Color.black.a = 1f; + UI.updateTooltip(displayContainer.renderDelta, hoverOption.getDescription(), false); + UI.drawTooltip(g); } } @@ -322,10 +327,10 @@ public class OptionsOverlay { Fonts.MEDIUM.drawString(optionStartX + optionWidth - valueLen, y, value, Colors.BLUE_BACKGROUND); } - public void renderTabs(int mouseX, int mouseY) { + public void renderTabs() { for (int i = 0; i < tabs.length; i++) { OptionTab tab = tabs[i]; - boolean hovering = tab.button.contains(mouseX, mouseY); + boolean hovering = tab.button.contains(displayContainer.mouseX, displayContainer.mouseY); UI.drawTab(tab.button.getX(), tab.button.getY(), tab.name, i == selectedTab, hovering); } } @@ -339,7 +344,25 @@ public class OptionsOverlay { Fonts.DEFAULT.drawString(marginX, marginY, "Change the way opsu! behaves", Color.white); } - public void update(int delta, int mouseX, int mouseY) { + @Override + public void hide() { + acceptInput = false; + SoundController.playSound(SoundEffect.MENUBACK); + active = false; + } + + @Override + public void show() { + acceptInput = true; + active = true; + } + + @Override + public void onPreRenderUpdate() { + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; + int delta = displayContainer.renderDelta; + if (sliderSoundDelay > 0) { sliderSoundDelay -= delta; } @@ -352,7 +375,7 @@ public class OptionsOverlay { UI.getBackButton().hoverUpdate(delta, mouseX, mouseY); if (isAdjustingSlider) { int sliderValue = hoverOption.getIntegerValue(); - updateSliderOption(mouseX, mouseY); + updateSliderOption(); if (hoverOption.getIntegerValue() - sliderValue != 0 && sliderSoundDelay <= 0) { sliderSoundDelay = 90; SoundController.playSound(SoundEffect.MENUHIT); @@ -366,22 +389,23 @@ public class OptionsOverlay { } } - public void mousePressed(int button, int x, int y) { + @Override + public boolean onMousePressed(int button, int x, int y) { if (keyEntryLeft || keyEntryRight) { keyEntryLeft = keyEntryRight = false; - return; + return true; } if (isListOptionOpen) { if (y > optionStartY && listStartX <= x && x < listStartX + listWidth && listStartY <= y && y < listStartY + listHeight) { hoverOption.clickListItem(listHoverIndex); - parent.onSaveOption(hoverOption); + // TODO d parent.onSaveOption(hoverOption); SoundController.playSound(SoundEffect.MENUCLICK); } isListOptionOpen = false; listHoverIndex = -1; updateHoverOption(x, y); - return; + return true; } mousePressY = y; @@ -393,35 +417,37 @@ public class OptionsOverlay { } else if (hoverOption.getType() == OptionType.NUMERIC) { isAdjustingSlider = sliderOptionStartX <= x && x < sliderOptionStartX + sliderOptionLength; if (isAdjustingSlider) { - updateSliderOption(x, y); + updateSliderOption(); } } } if (UI.getBackButton().contains(x, y)) { - parent.onLeave(); + hide(); } + return true; } - public void mouseReleased(int button, int x, int y) { + @Override + public boolean onMouseReleased(int button, int x, int y) { selectedOption = null; if (isAdjustingSlider) { - parent.onSaveOption(hoverOption); + // TODO d parent.onSaveOption(hoverOption); } isAdjustingSlider = false; sliderOptionLength = 0; // check if clicked, not dragged if (Math.abs(y - mousePressY) >= 5) { - return; + return true; } if (hoverOption != null) { if (hoverOption.getType() == OptionType.BOOLEAN) { - hoverOption.click(container); - parent.onSaveOption(hoverOption); + hoverOption.click(); + // TODO d parent.onSaveOption(hoverOption); SoundController.playSound(SoundEffect.MENUHIT); - return; + return true; } else if (hoverOption == GameOption.KEY_LEFT) { keyEntryLeft = true; } else if (hoverOption == GameOption.KEY_RIGHT) { @@ -435,27 +461,33 @@ public class OptionsOverlay { if (tab.button.contains(x, y)) { scrollOffset = tScrollOffset; SoundController.playSound(SoundEffect.MENUCLICK); - return; + return true; } tScrollOffset += Fonts.MEDIUM.getLineHeight() * 2; tScrollOffset += tab.options.length * optionHeight; } + return true; } - public void mouseDragged(int oldx, int oldy, int newx, int newy) { + @Override + public boolean onMouseDragged(int oldx, int oldy, int newx, int newy) { if (!isAdjustingSlider) { scrollOffset = Utils.clamp(scrollOffset + oldy - newy, 0, maxScrollOffset); } + return true; } - public void mouseWheelMoved(int delta) { + @Override + public boolean onMouseWheelMoved(int delta) { if (!isAdjustingSlider) { scrollOffset = Utils.clamp(scrollOffset - delta, 0, maxScrollOffset); } updateHoverOption(prevMouseX, prevMouseY); + return true; } - public boolean keyPressed(int key, char c) { + @Override + public boolean onKeyPressed(int key, char c) { if (keyEntryRight) { Options.setGameKeyRight(key); keyEntryRight = false; @@ -475,16 +507,21 @@ public class OptionsOverlay { listHoverIndex = -1; return true; } - parent.onLeave(); + hide(); return true; } return false; } - private void updateSliderOption(int mouseX, int mouseY) { + @Override + public boolean onKeyReleased(int key, char c) { + return false; + } + + private void updateSliderOption() { int min = hoverOption.getMinValue(); int max = hoverOption.getMaxValue(); - int value = min + Math.round((float) (max - min) * (mouseX - sliderOptionStartX) / (sliderOptionLength)); + int value = min + Math.round((float) (max - min) * (displayContainer.mouseX - sliderOptionStartX) / (sliderOptionLength)); hoverOption.setValue(Utils.clamp(value, min, max)); } @@ -536,7 +573,6 @@ public class OptionsOverlay { public interface Parent { void onLeave(); - void onSaveOption(GameOption option); } diff --git a/src/yugecin/opsudance/ui/SBOverlay.java b/src/yugecin/opsudance/ui/SBOverlay.java index bd03da4d..723c0afb 100644 --- a/src/yugecin/opsudance/ui/SBOverlay.java +++ b/src/yugecin/opsudance/ui/SBOverlay.java @@ -112,7 +112,7 @@ public class SBOverlay implements OptionsOverlay.Parent { private final Game game; private final MoveStoryboard msb; - private final OptionsOverlay overlay; + private OptionsOverlay overlay; static { for (OptionTab tab : options) { @@ -124,7 +124,7 @@ public class SBOverlay implements OptionsOverlay.Parent { this.game = game; this.msb = msb; initialOptions = new HashMap<>(); - overlay = new OptionsOverlay(this, options, 2, container); + //overlay = new OptionsOverlay(this, options, 2, container); this.width = container.getWidth(); this.height = container.getHeight(); speed = 10; @@ -160,13 +160,13 @@ public class SBOverlay implements OptionsOverlay.Parent { g.fillRect(curtime * width, height - 10f, 10f, 10f); } if (menu) { - overlay.render(g, container.getInput().getMouseX(), container.getInput().getMouseY()); + //overlay.render(g, container.getInput().getMouseX(), container.getInput().getMouseY()); } } public void update(int delta, int mouseX, int mouseY) { if (Options.isEnableSB() && menu) { - overlay.update(delta, mouseX, mouseY); + //overlay.update(delta, mouseX, mouseY); } msb.update(delta, mouseX, mouseY); } From 4b2f29df985e492cb9585d6c71a101942e9db205 Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 19 Jan 2017 16:16:30 +0100 Subject: [PATCH 27/38] convert gameranking --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/states/GameRanking.java | 163 +++++++++---------- 2 files changed, 75 insertions(+), 90 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 73493858..ab738061 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -91,7 +91,7 @@ public class Opsu extends StateBasedGame { //addState(new SongMenu(STATE_SONGMENU)); addState(new Game(STATE_GAME)); addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); - addState(new GameRanking(STATE_GAMERANKING)); + //addState(new GameRanking(STATE_GAMERANKING)); //addState(new OptionsMenu(STATE_OPTIONSMENU)); //addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); } diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index 00f1b48f..6a92d44b 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -21,9 +21,6 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameMod; -import itdelatrisu.opsu.Opsu; -import itdelatrisu.opsu.Options; -import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundEffect; @@ -35,17 +32,13 @@ import itdelatrisu.opsu.ui.UI; import java.io.FileNotFoundException; import java.io.IOException; -import org.lwjgl.opengl.Display; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.FadeInTransition; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.BaseOpsuState; /** * "Game Ranking" (score card) state. @@ -54,7 +47,10 @@ import org.newdawn.slick.util.Log; * or watch a replay of the game from this state. * */ -public class GameRanking extends BasicGameState { +public class GameRanking extends BaseOpsuState { + + private final InstanceContainer instanceContainer; + /** Associated GameData object. */ private GameData data; @@ -64,48 +60,34 @@ public class GameRanking extends BasicGameState { /** Button coordinates. */ private float retryY, replayY; - // game-related variables - private GameContainer container; - private StateBasedGame game; - private final int state; - private Input input; - - public GameRanking(int state) { - this.state = state; + public GameRanking(DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + this.instanceContainer = instanceContainer; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); - - int width = container.getWidth(); - int height = container.getHeight(); + public void revalidate() { + super.revalidate(); // buttons Image retry = GameImage.PAUSE_RETRY.getImage(); Image replay = GameImage.PAUSE_REPLAY.getImage(); - replayY = (height * 0.985f) - replay.getHeight() / 2f; + replayY = (displayContainer.height * 0.985f) - replay.getHeight() / 2f; retryY = replayY - (replay.getHeight() / 2f) - (retry.getHeight() / 1.975f); - retryButton = new MenuButton(retry, width - (retry.getWidth() / 2f), retryY); - replayButton = new MenuButton(replay, width - (replay.getWidth() / 2f), replayY); + retryButton = new MenuButton(retry, displayContainer.width - (retry.getWidth() / 2f), retryY); + replayButton = new MenuButton(replay, displayContainer.width - (replay.getWidth() / 2f), replayY); retryButton.setHoverFade(); replayButton.setHoverFade(); } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { - int width = container.getWidth(); - int height = container.getHeight(); - + public void render(Graphics g) { Beatmap beatmap = MusicController.getBeatmap(); // background - if (!beatmap.drawBackground(width, height, 0.7f, true)) - GameImage.PLAYFIELD.getImage().draw(0,0); + if (!beatmap.drawBackground(displayContainer.width, displayContainer.height, 0.7f, true)) { + GameImage.PLAYFIELD.getImage().draw(0, 0); + } // ranking screen elements data.drawRankingElements(g, beatmap); @@ -117,63 +99,62 @@ public class GameRanking extends BasicGameState { UI.getBackButton().draw(); UI.draw(g); + + super.render(g); } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + int delta = displayContainer.renderDelta; UI.update(delta); - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - replayButton.hoverUpdate(delta, mouseX, mouseY); - if (data.isGameplay()) - retryButton.hoverUpdate(delta, mouseX, mouseY); - else + replayButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); + if (data.isGameplay()) { + retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); + } else { MusicController.loopTrackIfEnded(true); - UI.getBackButton().hoverUpdate(delta, mouseX, mouseY); - } - - @Override - public int getID() { return state; } - - @Override - public void mouseWheelMoved(int newValue) { - if (input.isKeyDown(Input.KEY_LALT) || input.isKeyDown(Input.KEY_RALT)) - UI.changeVolume((newValue < 0) ? -1 : 1); - } - - @Override - public void keyPressed(int key, char c) { - switch (key) { - case Input.KEY_ESCAPE: - returnToSongMenu(); - break; - case Input.KEY_F7: - // TODO d - //Options.setNextFPS(container); - break; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - break; - case Input.KEY_F12: - Utils.takeScreenShot(); - break; } + UI.getBackButton().hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); } @Override - public void mousePressed(int button, int x, int y) { + public boolean mouseWheelMoved(int newValue) { + if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) { + UI.changeVolume((newValue < 0) ? -1 : 1); + } + return true; + } + + @Override + public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; + } + + if (key == Input.KEY_ESCAPE) { + returnToSongMenu(); + } + return true; + } + + @Override + public boolean mousePressed(int button, int x, int y) { + if (super.mousePressed(button, x, y)) { + return true; + } + // check mouse button - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return false; + } // back to menu if (UI.getBackButton().contains(x, y)) { returnToSongMenu(); - return; + return true; } // replay - Game gameState = (Game) game.getState(Opsu.STATE_GAME); + Game gameState = instanceContainer.provide(Game.class); boolean returnToGame = false; boolean replayButtonPressed = replayButton.contains(x, y); if (replayButtonPressed && !(data.isGameplay() && GameMod.AUTO.isActive())) { @@ -207,16 +188,16 @@ public class GameRanking extends BasicGameState { Beatmap beatmap = MusicController.getBeatmap(); gameState.loadBeatmap(beatmap); SoundController.playSound(SoundEffect.MENUHIT); - game.enterState(Opsu.STATE_GAME, new EasedFadeOutTransition(), new FadeInTransition()); - return; + // TODO d displayContainer.switchState(Game.class); } + return true; } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); + UI.enter(); - Display.setTitle(game.getTitle()); if (!data.isGameplay()) { if (!MusicController.isTrackDimmed()) MusicController.toggleTrackDimmed(0.5f); @@ -230,11 +211,13 @@ public class GameRanking extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) - throws SlickException { + public void leave() { + super.leave(); + this.data = null; - if (MusicController.isTrackDimmed()) + if (MusicController.isTrackDimmed()) { MusicController.toggleTrackDimmed(1f); + } } /** @@ -243,13 +226,15 @@ public class GameRanking extends BasicGameState { private void returnToSongMenu() { SoundController.muteSoundComponent(); SoundController.playSound(SoundEffect.MENUBACK); - SongMenu songMenu = (SongMenu) game.getState(Opsu.STATE_SONGMENU); - if (data.isGameplay()) + SongMenu songMenu = instanceContainer.provide(SongMenu.class); + if (data.isGameplay()) { songMenu.resetTrackOnLoad(); + } songMenu.resetGameDataOnLoad(); - if (UI.getCursor().isBeatmapSkinned()) + if (UI.getCursor().isBeatmapSkinned()) { UI.getCursor().reset(); - game.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition()); + } + displayContainer.switchState(SongMenu.class); } /** From a3df6e12d6325d6e9f327f249481ad4ffd893373 Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 19 Jan 2017 19:23:31 +0100 Subject: [PATCH 28/38] convert game --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/objects/Circle.java | 3 +- src/itdelatrisu/opsu/objects/Slider.java | 8 +- src/itdelatrisu/opsu/objects/Spinner.java | 8 +- src/itdelatrisu/opsu/states/Game.java | 482 ++++++++++-------- src/itdelatrisu/opsu/states/OptionsMenu.java | 59 +++ src/itdelatrisu/opsu/states/SongMenu.java | 4 +- .../opsudance/core/DisplayContainer.java | 8 +- .../core/inject/OpsuDanceInjector.java | 2 + .../core/state/OverlayOpsuState.java | 9 +- .../opsudance/sbv2/MoveStoryboard.java | 112 ++-- src/yugecin/opsudance/ui/OptionsOverlay.java | 50 +- ...{SBOverlay.java => StoryboardOverlay.java} | 173 ++----- 13 files changed, 497 insertions(+), 423 deletions(-) rename src/yugecin/opsudance/ui/{SBOverlay.java => StoryboardOverlay.java} (59%) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index ab738061..131178b8 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -89,7 +89,7 @@ public class Opsu extends StateBasedGame { //addState(new MainMenu(STATE_MAINMENU)); //addState(new ButtonMenu(STATE_BUTTONMENU)); //addState(new SongMenu(STATE_SONGMENU)); - addState(new Game(STATE_GAME)); + //addState(new Game(STATE_GAME)); addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); //addState(new GameRanking(STATE_GAMERANKING)); //addState(new OptionsMenu(STATE_OPTIONSMENU)); diff --git a/src/itdelatrisu/opsu/objects/Circle.java b/src/itdelatrisu/opsu/objects/Circle.java index 7c0d5756..56d393b2 100644 --- a/src/itdelatrisu/opsu/objects/Circle.java +++ b/src/itdelatrisu/opsu/objects/Circle.java @@ -64,10 +64,9 @@ public class Circle extends GameObject { /** * Initializes the Circle data type with map modifiers, images, and dimensions. - * @param container the game container * @param circleDiameter the circle diameter */ - public static void init(GameContainer container, float circleDiameter) { + public static void init(float circleDiameter) { diameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480) int diameterInt = (int) diameter; GameImage.HITCIRCLE.setImage(GameImage.HITCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt)); diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index f8ad3441..6ffaee19 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -37,6 +37,7 @@ import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import yugecin.opsudance.Dancer; +import yugecin.opsudance.core.DisplayContainer; /** * Data type representing a slider object. @@ -127,13 +128,12 @@ public class Slider extends GameObject { /** * Initializes the Slider data type with images and dimensions. - * @param container the game container * @param circleDiameter the circle diameter * @param beatmap the associated beatmap */ - public static void init(GameContainer container, float circleDiameter, Beatmap beatmap) { - containerWidth = container.getWidth(); - containerHeight = container.getHeight(); + public static void init(DisplayContainer displayContainer, float circleDiameter, Beatmap beatmap) { + containerWidth = displayContainer.width; + containerHeight = displayContainer.height; diameter = circleDiameter * HitObject.getXMultiplier(); // convert from Osupixels (640x480) int diameterInt = (int) diameter; diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 551c80f8..bb3ed811 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -35,6 +35,7 @@ import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; +import yugecin.opsudance.core.DisplayContainer; /** * Data type representing a spinner object. @@ -109,12 +110,11 @@ public class Spinner extends GameObject { /** * Initializes the Spinner data type with images and dimensions. - * @param container the game container * @param difficulty the map's overall difficulty value */ - public static void init(GameContainer container, float difficulty) { - width = container.getWidth(); - height = container.getHeight(); + public static void init(DisplayContainer displayContainer, float difficulty) { + width = displayContainer.width; + height = displayContainer.height; overallDifficulty = difficulty; } diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 49bb6c95..1dd3c7dd 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -18,11 +18,9 @@ package itdelatrisu.opsu.states; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameData; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.GameMod; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.Utils; @@ -59,26 +57,28 @@ import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.Display; import org.newdawn.slick.Animation; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; import org.newdawn.slick.Input; import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.DelayedFadeOutTransition; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; -import org.newdawn.slick.state.transition.EmptyTransition; -import org.newdawn.slick.state.transition.FadeInTransition; +import org.newdawn.slick.util.Log; import yugecin.opsudance.*; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.ComplexOpsuState; +import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.objects.curves.FakeCombinedCurve; import yugecin.opsudance.sbv2.MoveStoryboard; -import yugecin.opsudance.ui.SBOverlay; +import yugecin.opsudance.ui.OptionsOverlay; +import yugecin.opsudance.ui.StoryboardOverlay; /** * "Game" state. */ -public class Game extends BasicGameState { +public class Game extends ComplexOpsuState { + + private final InstanceContainer instanceContainer; + public static boolean isInGame; // TODO delete this when #79 is fixed /** Game restart states. */ public enum Restart { @@ -307,101 +307,95 @@ public class Game extends BasicGameState { MUSICBAR_HOVER = new Color(12, 9, 10, 0.35f), MUSICBAR_FILL = new Color(255, 255, 255, 0.75f); - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - private final Cursor mirrorCursor; - private MoveStoryboard msb; - private SBOverlay sbOverlay; + private final MoveStoryboard moveStoryboardOverlay; + private final StoryboardOverlay storyboardOverlay; + private final OptionsOverlay optionsOverlay; private FakeCombinedCurve knorkesliders; private boolean skippedToCheckpoint; - public Game(int state) { - this.state = state; + public Game(DisplayContainer displayContainer, InstanceContainer instanceContainer) { + super(displayContainer); + this.instanceContainer = instanceContainer; mirrorCursor = new Cursor(true); - } - - public void loadCheckpoint(int checkpoint) { - try { - restart = Restart.MANUAL; - checkpointLoaded = true; - skippedToCheckpoint = true; - enter(container, game); - if (isLeadIn()) { - leadInTime = 0; - epiImgTime = 0; - MusicController.resume(); - } - // skip to checkpoint - MusicController.setPosition(checkpoint); - while (objectIndex < gameObjects.length && beatmap.objects[objectIndex].getTime() <= checkpoint) { - objectIndex++; - } - if (objectIndex > 0) { - objectIndex--; - } - if (Options.isMergingSliders()) { - int obj = objectIndex; - while (obj < gameObjects.length) { - if (gameObjects[obj] instanceof Slider) { - slidercurveFrom = slidercurveTo = ((Slider) gameObjects[obj]).baseSliderFrom; - break; - } - obj++; - } - spliceSliderCurve(-1, -1); - } - Dancer.instance.setObjectIndex(objectIndex); - sbOverlay.updateIndex(objectIndex); - lastReplayTime = beatmap.objects[objectIndex].getTime(); - } catch (SlickException e) { - e.printStackTrace(); - } + this.moveStoryboardOverlay = new MoveStoryboard(displayContainer); + this.optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.storyboardOptions, 0); + this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this); + storyboardOverlay.show(); + moveStoryboardOverlay.show(); + optionsOverlay.setListener(storyboardOverlay); } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.msb = new MoveStoryboard(container); - this.sbOverlay = new SBOverlay(this, msb, container); - this.container = container; - this.game = game; - input = container.getInput(); - - int width = container.getWidth(); - int height = container.getHeight(); - + public void revalidate() { // create offscreen graphics - offscreen = new Image(width, height); - gOffscreen = offscreen.getGraphics(); - gOffscreen.setBackground(Color.black); + try { + offscreen = new Image(displayContainer.width, displayContainer.height); + gOffscreen = offscreen.getGraphics(); + gOffscreen.setBackground(Color.black); + } catch (SlickException e) { + Log.error("could not create offscreen graphics", e); + displayContainer.eventBus.post(new BubbleNotificationEvent("Exception while creating offscreen graphics. See logfile for details.", BubbleNotificationEvent.COMMONCOLOR_RED)); + } // initialize music position bar location - musicBarX = width * 0.01f; - musicBarY = height * 0.05f; - musicBarWidth = Math.max(width * 0.005f, 7); - musicBarHeight = height * 0.9f; + musicBarX = displayContainer.width * 0.01f; + musicBarY = displayContainer.height * 0.05f; + musicBarWidth = Math.max(displayContainer.width * 0.005f, 7); + musicBarHeight = displayContainer.height * 0.9f; // initialize scoreboard star stream - scoreboardStarStream = new StarStream(0, height * 2f / 3f, width / 4, 0, 0); - scoreboardStarStream.setPositionSpread(height / 20f); + scoreboardStarStream = new StarStream(0, displayContainer.height * 2f / 3f, displayContainer.width / 4, 0, 0); + scoreboardStarStream.setPositionSpread(displayContainer.height / 20f); scoreboardStarStream.setDirectionSpread(10f); scoreboardStarStream.setDurationSpread(700, 100); // create the associated GameData object - data = new GameData(width, height); + data = new GameData(displayContainer.width, displayContainer.height); + } + + + public void loadCheckpoint(int checkpoint) { + restart = Restart.MANUAL; + checkpointLoaded = true; + skippedToCheckpoint = true; + enter(); + if (isLeadIn()) { + leadInTime = 0; + epiImgTime = 0; + MusicController.resume(); + } + // skip to checkpoint + MusicController.setPosition(checkpoint); + while (objectIndex < gameObjects.length && beatmap.objects[objectIndex].getTime() <= checkpoint) { + objectIndex++; + } + if (objectIndex > 0) { + objectIndex--; + } + if (Options.isMergingSliders()) { + int obj = objectIndex; + while (obj < gameObjects.length) { + if (gameObjects[obj] instanceof Slider) { + slidercurveFrom = slidercurveTo = ((Slider) gameObjects[obj]).baseSliderFrom; + break; + } + obj++; + } + spliceSliderCurve(-1, -1); + } + Dancer.instance.setObjectIndex(objectIndex); + storyboardOverlay.updateIndex(objectIndex); + lastReplayTime = beatmap.objects[objectIndex].getTime(); } @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { - int width = container.getWidth(); - int height = container.getHeight(); + public void render(Graphics g) { + int width = displayContainer.width; + int height = displayContainer.height; + int trackPosition = MusicController.getPosition(); if (isLeadIn()) { trackPosition -= leadInTime - currentMapMusicOffset - Options.getMusicOffset(); @@ -475,7 +469,7 @@ public class Game extends BasicGameState { } } - float[] sbPosition = sbOverlay.getPoint(trackPosition); + float[] sbPosition = moveStoryboardOverlay.getPoint(trackPosition); if (sbPosition != null) { autoPoint.x = sbPosition[0]; autoPoint.y = sbPosition[1]; @@ -510,8 +504,8 @@ public class Game extends BasicGameState { mouseX = replayX; mouseY = replayY; } else { - mouseX = input.getMouseX(); - mouseY = input.getMouseY(); + mouseX = displayContainer.mouseX; + mouseY = displayContainer.mouseY; } int alphaRadius = flashlightRadius * 256 / 215; int alphaX = mouseX - alphaRadius / 2; @@ -686,7 +680,7 @@ public class Game extends BasicGameState { float animation = AnimationEquation.IN_OUT_QUAD.calc( Utils.clamp((trackPosition - lastRankUpdateTime) / SCOREBOARD_ANIMATION_TIME, 0f, 1f) ); - int scoreboardPosition = 2 * container.getHeight() / 3; + int scoreboardPosition = 2 * displayContainer.height / 3; // draw star stream behind the scores scoreboardStarStream.draw(); @@ -727,8 +721,7 @@ public class Game extends BasicGameState { // draw music position bar (for replay seeking) if (isReplay && Options.isReplaySeekingEnabled()) { - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - g.setColor((musicPositionBarContains(mouseX, mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL); + g.setColor((musicPositionBarContains(displayContainer.mouseX, displayContainer.mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL); g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4); if (!isLeadIn()) { g.setColor(MUSICBAR_FILL); @@ -770,24 +763,27 @@ public class Game extends BasicGameState { else UI.draw(g); - sbOverlay.render(container, g); - if (!Options.isHideWM()) { Fonts.SMALL.drawString(0.3f, 0.3f, "opsu!dance " + Updater.get().getCurrentVersion() + " by robin_be | https://github.com/yugecin/opsu-dance"); } + + super.render(g); } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + super.preRenderUpdate(); + + int delta = displayContainer.renderDelta; + UI.update(delta); Pippi.update(delta); if (epiImgTime > 0) { epiImgTime -= delta; } yugecin.opsudance.spinners.Spinner.update(delta); - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - sbOverlay.update(delta, mouseX, mouseY); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; skipButton.hoverUpdate(delta, mouseX, mouseY); if (isReplay || GameMod.AUTO.isActive()) playbackSpeed.getButton().hoverUpdate(delta, mouseX, mouseY); @@ -805,8 +801,8 @@ public class Game extends BasicGameState { } // focus lost: go back to pause screen - else if (!container.hasFocus()) { - game.enterState(Opsu.STATE_GAMEPAUSEMENU); + else if (!Display.isActive()) { + // TODO d displayContainer.switchState(GamePauseMenu.class); pausePulse = 0f; } @@ -918,10 +914,13 @@ public class Game extends BasicGameState { // game finished: change state after timer expires if (gameFinished && !gameFinishedTimer.update(delta)) { - if (checkpointLoaded) // if checkpoint used, skip ranking screen - game.closeRequested(); - else // go to ranking screen - game.enterState(Opsu.STATE_GAMERANKING, new EasedFadeOutTransition(), new FadeInTransition()); + if (checkpointLoaded) { + // if checkpoint used, skip ranking screen + onCloseRequest(); + } else { + // go to ranking screen + displayContainer.switchState(GameRanking.class); + } } } @@ -949,7 +948,7 @@ public class Game extends BasicGameState { // save score and replay if (!checkpointLoaded) { boolean unranked = (GameMod.AUTO.isActive() || GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive()); - ((GameRanking) game.getState(Opsu.STATE_GAMERANKING)).setGameData(data); + instanceContainer.provide(GameRanking.class).setGameData(data); if (isReplay) data.setReplay(replay); else if (replayFrames != null) { @@ -1027,14 +1026,15 @@ public class Game extends BasicGameState { } // pause game if focus lost - if (!container.hasFocus() && !GameMod.AUTO.isActive() && !isReplay) { + if (!Display.isActive() && !GameMod.AUTO.isActive() && !isReplay) { if (pauseTime < 0) { pausedMousePosition = new Vec2f(mouseX, mouseY); pausePulse = 0f; } - if (MusicController.isPlaying() || isLeadIn()) + if (MusicController.isPlaying() || isLeadIn()) { pauseTime = trackPosition; - game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition()); + } + // TODO d displayContainer.switchState(GamePauseMenu.class); } // drain health @@ -1058,13 +1058,10 @@ public class Game extends BasicGameState { failTrackTime = MusicController.getPosition(); MusicController.fadeOut(MUSIC_FADEOUT_TIME); MusicController.pitchFadeOut(MUSIC_FADEOUT_TIME); - rotations = new IdentityHashMap(); + rotations = new IdentityHashMap<>(); SoundController.playSound(SoundEffect.FAIL); - // fade to pause menu - game.enterState(Opsu.STATE_GAMEPAUSEMENU, - new DelayedFadeOutTransition(Color.black, MUSIC_FADEOUT_TIME, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME), - new FadeInTransition()); + // TODO d displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300); } } } @@ -1088,7 +1085,7 @@ public class Game extends BasicGameState { if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) { skippedObject = true; objectIndex++; // done, so increment object index - sbOverlay.updateIndex(objectIndex); + storyboardOverlay.updateIndex(objectIndex); if (objectIndex >= mirrorTo) { Options.setMirror(false); } @@ -1099,20 +1096,25 @@ public class Game extends BasicGameState { } @Override - public int getID() { return state; } + public boolean onCloseRequest() { + instanceContainer.provide(SongMenu.class).resetGameDataOnLoad(); + displayContainer.switchState(SongMenu.class); + return false; + } @Override - public void keyPressed(int key, char c) { - if (gameFinished) - return; + public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; + } - if (sbOverlay.keyPressed(key, c)) { - return; + if (gameFinished) { + return true; } int trackPosition = MusicController.getPosition(); - int mouseX = input.getMouseX(); - int mouseY = input.getMouseY(); + int mouseX = displayContainer.mouseX; + int mouseY = displayContainer.mouseY; // game keys if (!Keyboard.isRepeatEvent()) { @@ -1129,7 +1131,7 @@ public class Game extends BasicGameState { case Input.KEY_ESCAPE: // "auto" mod or watching replay: go back to song menu if (GameMod.AUTO.isActive() || isReplay) { - game.closeRequested(); + onCloseRequest(); break; } @@ -1138,9 +1140,10 @@ public class Game extends BasicGameState { pausedMousePosition = new Vec2f(mouseX, mouseY); pausePulse = 0f; } - if (MusicController.isPlaying() || isLeadIn()) + if (MusicController.isPlaying() || isLeadIn()) { pauseTime = trackPosition; - game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition()); + } + // TODO d displayContainer.switchStateNow(GamePauseMenu.class); break; case Input.KEY_SPACE: // skip intro @@ -1148,23 +1151,21 @@ public class Game extends BasicGameState { break; case Input.KEY_R: // restart - if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { - try { - if (trackPosition < beatmap.objects[0].getTime()) - retries--; // don't count this retry (cancel out later increment) - restart = Restart.MANUAL; - enter(container, game); - skipIntro(); - } catch (SlickException e) { - ErrorHandler.error("Failed to restart game.", e, false); + if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) { + if (trackPosition < beatmap.objects[0].getTime()) { + retries--; // don't count this retry (cancel out later increment) } + restart = Restart.MANUAL; + enter(); + skipIntro(); } break; case Input.KEY_S: // save checkpoint - if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { - if (isLeadIn()) + if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) { + if (isLeadIn()) { break; + } int position = (pauseTime > -1) ? pauseTime : trackPosition; if (Options.setCheckpoint(position / 1000)) { @@ -1175,7 +1176,7 @@ public class Game extends BasicGameState { break; case Input.KEY_L: // load checkpoint - if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { + if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) { int checkpoint = Options.getCheckpoint(); if (checkpoint == 0 || checkpoint > beatmap.endTime) break; // invalid checkpoint @@ -1197,16 +1198,6 @@ public class Game extends BasicGameState { case Input.KEY_DOWN: UI.changeVolume(-1); break; - case Input.KEY_F7: - // TODO d - //Options.setNextFPS(container); - break; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - break; - case Input.KEY_F12: - Utils.takeScreenShot(); - break; case Input.KEY_TAB: if (!Options.isHideUI()) { scoreboardVisible = !scoreboardVisible; @@ -1243,29 +1234,33 @@ public class Game extends BasicGameState { currentMapMusicOffset -= 5; UI.sendBarNotification("Current map offset: " + currentMapMusicOffset); } + + return true; } @Override - public void mouseDragged(int oldx, int oldy, int newx, int newy) { - if (sbOverlay.mouseDragged(oldx, oldy, newx, newy)) { - //noinspection UnnecessaryReturnStatement - return; + public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { + if (super.mouseDragged(oldx, oldy, newx, newy)) { + return true; } + return true; } @Override - public void mousePressed(int button, int x, int y) { - if (gameFinished) - return; + public boolean mousePressed(int button, int x, int y) { + if (super.mousePressed(button, x, y)) { + return true; + } - if (sbOverlay.mousePressed(button, x, y)) { - return; + if (gameFinished) { + return true; } // watching replay if (isReplay || GameMod.AUTO.isActive()) { - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return true; + } // skip button if (skipButton.contains(x, y)) @@ -1284,11 +1279,12 @@ public class Game extends BasicGameState { MusicController.setPosition((int) pos); isSeeking = true; } - return; + return true; } - if (Options.isMouseDisabled()) - return; + if (Options.isMouseDisabled()) { + return true; + } // mouse wheel: pause the game if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) { @@ -1297,10 +1293,11 @@ public class Game extends BasicGameState { pausedMousePosition = new Vec2f(x, y); pausePulse = 0f; } - if (MusicController.isPlaying() || isLeadIn()) + if (MusicController.isPlaying() || isLeadIn()) { pauseTime = trackPosition; - game.enterState(Opsu.STATE_GAMEPAUSEMENU, new EmptyTransition(), new FadeInTransition()); - return; + } + // TODO d displayContainer.switchStateNow(GamePauseMenu.class); + return true; } // game keys @@ -1311,6 +1308,8 @@ public class Game extends BasicGameState { keys = ReplayFrame.KEY_M2; if (keys != ReplayFrame.KEY_NONE) gameKeyPressed(keys, x, y, MusicController.getPosition()); + + return true; } /** @@ -1353,19 +1352,22 @@ public class Game extends BasicGameState { } @Override - public void mouseReleased(int button, int x, int y) { - if (gameFinished) - return; - - if (sbOverlay.mouseReleased(button, x, y)) { - return; + public boolean mouseReleased(int button, int x, int y) { + if (super.mouseReleased(button, x, y)) { + return true; } - if (Options.isMouseDisabled()) - return; + if (gameFinished) { + return true; + } - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + if (Options.isMouseDisabled()) { + return true; + } + + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return true; + } int keys = ReplayFrame.KEY_NONE; if (button == Input.MOUSE_LEFT_BUTTON) @@ -1374,12 +1376,19 @@ public class Game extends BasicGameState { keys = ReplayFrame.KEY_M2; if (keys != ReplayFrame.KEY_NONE) gameKeyReleased(keys, x, y, MusicController.getPosition()); + + return true; } @Override - public void keyReleased(int key, char c) { - if (gameFinished) - return; + public boolean keyReleased(int key, char c) { + if (super.keyReleased(key, c)) { + return true; + } + + if (gameFinished) { + return true; + } int keys = ReplayFrame.KEY_NONE; if (key == Options.getGameKeyLeft()) @@ -1387,7 +1396,9 @@ public class Game extends BasicGameState { else if (key == Options.getGameKeyRight()) keys = ReplayFrame.KEY_K2; if (keys != ReplayFrame.KEY_NONE) - gameKeyReleased(keys, input.getMouseX(), input.getMouseY(), MusicController.getPosition()); + gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition()); + + return true; } /** @@ -1405,26 +1416,41 @@ public class Game extends BasicGameState { } @Override - public void mouseWheelMoved(int newValue) { - if (sbOverlay.mouseWheelMoved(newValue)) { - return; + public boolean mouseWheelMoved(int newValue) { + if (super.mouseWheelMoved(newValue)) { + return true; + } + + if (Options.isMouseWheelDisabled()) { + return true; } - if (Options.isMouseWheelDisabled()) - return; UI.changeVolume((newValue < 0) ? -1 : 1); + return true; } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); + + overlays.clear(); + if (Options.isEnableSB()) { + overlays.add(optionsOverlay); + overlays.add(moveStoryboardOverlay); + overlays.add(storyboardOverlay); + storyboardOverlay.onEnter(); + optionsOverlay.revalidate(); + } + isInGame = true; if (!skippedToCheckpoint) { UI.enter(); } - if (beatmap == null || beatmap.objects == null) - throw new RuntimeException("Running game with no beatmap loaded."); + if (beatmap == null || beatmap.objects == null) { + displayContainer.eventBus.post(new BubbleNotificationEvent("Game was running without a beatmap", BubbleNotificationEvent.COMMONCOLOR_RED)); + displayContainer.switchStateInstantly(SongMenu.class); + } Dancer.instance.reset(); MoverDirection.reset(beatmap.beatmapID); @@ -1451,10 +1477,10 @@ public class Game extends BasicGameState { epiImgTime = Options.getEpilepsyWarningLength(); if (epiImgTime > 0) { epiImg = GameImage.EPILEPSY_WARNING.getImage(); - float desWidth = container.getWidth() / 2; + float desWidth = displayContainer.width / 2; epiImg = epiImg.getScaledCopy(desWidth / epiImg.getWidth()); - epiImgX = (container.getWidth() - epiImg.getWidth()) / 2; - epiImgY = (container.getHeight() - epiImg.getHeight()) / 2; + epiImgX = (displayContainer.width - epiImg.getWidth()) / 2; + epiImgY = (displayContainer.height - epiImg.getHeight()) / 2; } // load mods @@ -1522,9 +1548,9 @@ public class Game extends BasicGameState { else if (hitObject.isSpinner()) gameObjects[i] = new Spinner(hitObject, this, data); } catch (Exception e) { - // try to handle the error gracefully: substitute in a dummy GameObject - ErrorHandler.error(String.format("Failed to create %s at index %d:\n%s", - hitObject.getTypeName(), i, hitObject.toString()), e, true); + String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString()); + Log.error(message, e); + displayContainer.eventBus.post(new BubbleNotificationEvent(message, BubbleNotificationEvent.COMMONCOLOR_RED)); gameObjects[i] = new DummyObject(hitObject); } } @@ -1550,8 +1576,8 @@ public class Game extends BasicGameState { // load replay frames if (isReplay) { // load initial data - replayX = container.getWidth() / 2; - replayY = container.getHeight() / 2; + replayX = displayContainer.width / 2; + replayY = displayContainer.height / 2; replayKeyPressed = false; replaySkipTime = -1; for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) { @@ -1572,8 +1598,8 @@ public class Game extends BasicGameState { else { lastKeysPressed = ReplayFrame.KEY_NONE; replaySkipTime = -1; - replayFrames = new LinkedList(); - replayFrames.add(new ReplayFrame(0, 0, input.getMouseX(), input.getMouseY(), 0)); + replayFrames = new LinkedList<>(); + replayFrames.add(new ReplayFrame(0, 0, displayContainer.mouseX, displayContainer.mouseY, 0)); } for (int i = 0; i < gameObjects.length; i++) { @@ -1635,10 +1661,10 @@ public class Game extends BasicGameState { slidercurveTo = 0; Dancer.instance.setGameObjects(gameObjects); - sbOverlay.setGameObjects(gameObjects); + storyboardOverlay.setGameObjects(gameObjects); if (!skippedToCheckpoint) { - sbOverlay.enter(); - sbOverlay.updateIndex(0); + storyboardOverlay.onEnter(); + storyboardOverlay.updateIndex(0); } Pippi.reset(); @@ -1652,15 +1678,23 @@ public class Game extends BasicGameState { } @Override - public void leave(GameContainer container, StateBasedGame game) - throws SlickException { + public void leave() { + super.leave(); + + MusicController.pause(); + MusicController.setPitch(1f); + MusicController.resume(); + + if (Options.isEnableSB()) { + storyboardOverlay.onLeave(); + } + isInGame = false; // container.setMouseGrabbed(false); skippedToCheckpoint = false; knorkesliders = null; - sbOverlay.leave(); Dancer.instance.setGameObjects(null); Cursor.lastObjColor = Color.white; @@ -1726,7 +1760,7 @@ public class Game extends BasicGameState { trackPosition = failTrackTime + (int) (System.currentTimeMillis() - failTime); // get hit objects in reverse order, or else overlapping objects are unreadable - Stack stack = new Stack(); + Stack stack = new Stack<>(); for (int index = objectIndex; index < gameObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) { stack.add(index); @@ -1739,7 +1773,7 @@ public class Game extends BasicGameState { } if (lastObjectIndex != -1 && !beatmap.objects[index].isNewCombo()) { // calculate points - final int followPointInterval = container.getHeight() / 14; + final int followPointInterval = displayContainer.height / 14; int lastObjectEndTime = gameObjects[lastObjectIndex].getEndTime() + 1; int objectStartTime = beatmap.objects[index].getTime(); Vec2f startPoint = gameObjects[lastObjectIndex].getPointAt(lastObjectEndTime); @@ -1828,7 +1862,7 @@ public class Game extends BasicGameState { g.pushTransform(); // translate and rotate the object - g.translate(0, dt * dt * container.getHeight()); + g.translate(0, dt * dt * displayContainer.height); Vec2f rotationCenter = gameObj.getPointAt((beatmap.objects[idx].getTime() + beatmap.objects[idx].getEndTime()) / 2); g.rotate(rotationCenter.x, rotationCenter.y, rotSpeed * dt); gameObj.draw(g, trackPosition, false); @@ -1847,7 +1881,7 @@ public class Game extends BasicGameState { currentMapMusicOffset = 0; } this.beatmap = beatmap; - Display.setTitle(String.format("%s - %s", game.getTitle(), beatmap.toString())); + Display.setTitle(String.format("opsu!dance - %s", beatmap.toString())); if (beatmap.breaks == null) BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY); BeatmapParser.parseHitObjects(beatmap); @@ -1879,7 +1913,7 @@ public class Game extends BasicGameState { lastReplayTime = 0; autoMousePosition = new Vec2f(); autoMousePressed = false; - flashlightRadius = container.getHeight() * 2 / 3; + flashlightRadius = displayContainer.height * 2 / 3; scoreboardStarStream.clear(); gameFinished = false; gameFinishedTimer.setTime(0); @@ -1917,9 +1951,6 @@ public class Game extends BasicGameState { * Loads all game images. */ private void loadImages() { - int width = container.getWidth(); - int height = container.getHeight(); - // set images File parent = beatmap.getFile().getParentFile(); for (GameImage img : GameImage.values()) { @@ -1932,17 +1963,17 @@ public class Game extends BasicGameState { // skip button if (GameImage.SKIP.getImages() != null) { Animation skip = GameImage.SKIP.getAnimation(120); - skipButton = new MenuButton(skip, width - skip.getWidth() / 2f, height - (skip.getHeight() / 2f)); + skipButton = new MenuButton(skip, displayContainer.width - skip.getWidth() / 2f, displayContainer.height - (skip.getHeight() / 2f)); } else { Image skip = GameImage.SKIP.getImage(); - skipButton = new MenuButton(skip, width - skip.getWidth() / 2f, height - (skip.getHeight() / 2f)); + skipButton = new MenuButton(skip, displayContainer.width - skip.getWidth() / 2f, displayContainer.height - (skip.getHeight() / 2f)); } skipButton.setHoverAnimationDuration(350); skipButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_BACK); skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT); // load other images... - ((GamePauseMenu) game.getState(Opsu.STATE_GAMEPAUSEMENU)).loadImages(); + // TODO d instanceContainer.provide(GamePauseMenu.class).loadImages(); data.loadImages(); } @@ -1974,10 +2005,10 @@ public class Game extends BasicGameState { HitObject.setStackOffset(diameter * STACK_OFFSET_MODIFIER); // initialize objects - Circle.init(container, diameter); - Slider.init(container, diameter, beatmap); - Spinner.init(container, overallDifficulty); - Curve.init(container.getWidth(), container.getHeight(), diameter, (Options.isBeatmapSkinIgnored()) ? + Circle.init(diameter); + Slider.init(displayContainer, diameter, beatmap); + Spinner.init(displayContainer, overallDifficulty); + Curve.init(displayContainer.width, displayContainer.height, diameter, (Options.isBeatmapSkinIgnored()) ? Options.getSkin().getSliderBorderColor() : beatmap.getSliderBorderColor()); // approachRate (hit object approach time) @@ -2096,7 +2127,7 @@ public class Game extends BasicGameState { this.replay = null; } else { if (replay.frames == null) { - ErrorHandler.error("Attempting to set a replay with no frames.", null, false); + displayContainer.eventBus.post(new BubbleNotificationEvent("Attempting to set a replay with no frames.", BubbleNotificationEvent.COLOR_ORANGE)); return; } this.isReplay = true; @@ -2191,30 +2222,29 @@ public class Game extends BasicGameState { if (!GameMod.FLASHLIGHT.isActive()) return; - int width = container.getWidth(), height = container.getHeight(); boolean firstObject = (objectIndex == 0 && trackPosition < beatmap.objects[0].getTime()); if (isLeadIn()) { // lead-in: expand area float progress = Math.max((float) (leadInTime - beatmap.audioLeadIn) / approachTime, 0f); - flashlightRadius = width - (int) ((width - (height * 2 / 3)) * progress); + flashlightRadius = displayContainer.width - (int) ((displayContainer.width - (displayContainer.height * 2 / 3)) * progress); } else if (firstObject) { // before first object: shrink area int timeDiff = beatmap.objects[0].getTime() - trackPosition; - flashlightRadius = width; + flashlightRadius = displayContainer.width; if (timeDiff < approachTime) { float progress = (float) timeDiff / approachTime; - flashlightRadius -= (width - (height * 2 / 3)) * (1 - progress); + flashlightRadius -= (displayContainer.width - (displayContainer.height * 2 / 3)) * (1 - progress); } } else { // gameplay: size based on combo int targetRadius; int combo = data.getComboStreak(); if (combo < 100) - targetRadius = height * 2 / 3; + targetRadius = displayContainer.height * 2 / 3; else if (combo < 200) - targetRadius = height / 2; + targetRadius = displayContainer.height / 2; else - targetRadius = height / 3; + targetRadius = displayContainer.height / 3; if (beatmap.breaks != null && breakIndex < beatmap.breaks.size() && breakTime > 0) { // breaks: expand at beginning, shrink at end flashlightRadius = targetRadius; @@ -2226,11 +2256,11 @@ public class Game extends BasicGameState { progress = (float) (trackPosition - breakTime) / approachTime; else if (endTime - trackPosition < approachTime) progress = (float) (endTime - trackPosition) / approachTime; - flashlightRadius += (width - flashlightRadius) * progress; + flashlightRadius += (displayContainer.width - flashlightRadius) * progress; } } else if (flashlightRadius != targetRadius) { // radius size change - float radiusDiff = height * delta / 2000f; + float radiusDiff = displayContainer.height * delta / 2000f; if (flashlightRadius > targetRadius) { flashlightRadius -= radiusDiff; if (flashlightRadius < targetRadius) diff --git a/src/itdelatrisu/opsu/states/OptionsMenu.java b/src/itdelatrisu/opsu/states/OptionsMenu.java index 03e458b5..4f2c22eb 100644 --- a/src/itdelatrisu/opsu/states/OptionsMenu.java +++ b/src/itdelatrisu/opsu/states/OptionsMenu.java @@ -133,4 +133,63 @@ public class OptionsMenu { }) }; + public static final OptionTab[] storyboardOptions = new OptionsOverlay.OptionTab[]{ + new OptionTab("Gameplay", new GameOption[] { + GameOption.BACKGROUND_DIM, + GameOption.DANCE_REMOVE_BG, + GameOption.SNAKING_SLIDERS, + GameOption.SHRINKING_SLIDERS, + GameOption.SHOW_HIT_LIGHTING, + GameOption.SHOW_HIT_ANIMATIONS, + GameOption.SHOW_COMBO_BURSTS, + GameOption.SHOW_PERFECT_HIT, + GameOption.SHOW_FOLLOW_POINTS, + }), + new OptionTab("Input", new GameOption[] { + GameOption.CURSOR_SIZE, + GameOption.NEW_CURSOR, + GameOption.DISABLE_CURSOR + }), + new OptionTab("Dance", new GameOption[] { + GameOption.DANCE_MOVER, + GameOption.DANCE_EXGON_DELAY, + GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS, + GameOption.DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR, + GameOption.DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS, + GameOption.DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR, + GameOption.DANCE_MOVER_DIRECTION, + GameOption.DANCE_SLIDER_MOVER_TYPE, + GameOption.DANCE_SPINNER, + GameOption.DANCE_SPINNER_DELAY, + GameOption.DANCE_LAZY_SLIDERS, + GameOption.DANCE_CIRCLE_STREAMS, + GameOption.DANCE_ONLY_CIRCLE_STACKS, + GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS, + GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS, + GameOption.DANCE_MIRROR, + }), + new OptionTab("Dance display", new GameOption[] { + GameOption.DANCE_DRAW_APPROACH, + GameOption.DANCE_OBJECT_COLOR_OVERRIDE, + GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED, + GameOption.DANCE_RGB_OBJECT_INC, + GameOption.DANCE_CURSOR_COLOR_OVERRIDE, + GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE, + GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL, + GameOption.DANCE_RGB_CURSOR_INC, + GameOption.DANCE_CURSOR_TRAIL_OVERRIDE, + GameOption.DANCE_HIDE_OBJECTS, + GameOption.DANCE_HIDE_UI, + GameOption.DANCE_HIDE_WATERMARK, + }), + new OptionTab ("Pippi", new GameOption[] { + GameOption.PIPPI_ENABLE, + GameOption.PIPPI_RADIUS_PERCENT, + GameOption.PIPPI_ANGLE_INC_MUL, + GameOption.PIPPI_ANGLE_INC_MUL_SLIDER, + GameOption.PIPPI_SLIDER_FOLLOW_EXPAND, + GameOption.PIPPI_PREVENT_WOBBLY_STREAMS, + }) + }; + } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index aeef2f1e..ee06bb49 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -326,7 +326,7 @@ public class SongMenu extends ComplexOpsuState { public SongMenu(final DisplayContainer displayContainer, InstanceContainer instanceContainer) { super(displayContainer); this.instanceContainer = instanceContainer; - optionsOverlay = new OptionsOverlay(this, displayContainer, OptionsMenu.normalOptions, 0); + optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.normalOptions, 0); overlays.add(optionsOverlay); } @@ -1794,6 +1794,6 @@ public class SongMenu extends ComplexOpsuState { gameState.loadBeatmap(beatmap); gameState.setRestart(Game.Restart.NEW); gameState.setReplay(null); - // TODO d displayContainer.switchState(Game.class); + displayContainer.switchState(Game.class); } } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index c827a2e0..fac7d085 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -334,7 +334,13 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen } public void switchStateNow(Class newState) { - switchState(newState, EmptyTransitionState.class, 0, EmptyTransitionState.class, 0); + 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) { diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index df63f5a9..98ab2278 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -57,6 +57,8 @@ public class OpsuDanceInjector extends Injector { bind(ButtonMenu.class).asEagerSingleton(); bind(SongMenu.class).asEagerSingleton(); bind(DownloadsMenu.class).asEagerSingleton(); + bind(GameRanking.class).asEagerSingleton(); + bind(Game.class).asEagerSingleton(); } } diff --git a/src/yugecin/opsudance/core/state/OverlayOpsuState.java b/src/yugecin/opsudance/core/state/OverlayOpsuState.java index f5df8b46..849b4567 100644 --- a/src/yugecin/opsudance/core/state/OverlayOpsuState.java +++ b/src/yugecin/opsudance/core/state/OverlayOpsuState.java @@ -26,8 +26,13 @@ public abstract class OverlayOpsuState implements OpsuState { protected boolean active; protected boolean acceptInput; - public abstract void hide(); - public abstract void show(); + public void hide() { + acceptInput = active = false; + } + + public void show() { + acceptInput = active = true; + } @Override public final void update() { diff --git a/src/yugecin/opsudance/sbv2/MoveStoryboard.java b/src/yugecin/opsudance/sbv2/MoveStoryboard.java index b6119d86..aa4e95c8 100644 --- a/src/yugecin/opsudance/sbv2/MoveStoryboard.java +++ b/src/yugecin/opsudance/sbv2/MoveStoryboard.java @@ -25,6 +25,8 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation; import org.newdawn.slick.Color; import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.state.OverlayOpsuState; import yugecin.opsudance.sbv2.movers.CubicStoryboardMover; import yugecin.opsudance.sbv2.movers.LinearStoryboardMover; import yugecin.opsudance.sbv2.movers.QuadraticStoryboardMover; @@ -34,20 +36,20 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -public class MoveStoryboard { +public class MoveStoryboard extends OverlayOpsuState{ - private final SimpleButton btnAddLinear; - private final SimpleButton btnAddQuadratic; - private final SimpleButton btnAddCubic; + private final DisplayContainer displayContainer; - private final SimpleButton btnAnimLin; - private final SimpleButton btnAnimMid; - private final SimpleButton btnAnimCub; + private SimpleButton btnAddLinear; + private SimpleButton btnAddQuadratic; + private SimpleButton btnAddCubic; + + private SimpleButton btnAnimLin; + private SimpleButton btnAnimMid; + private SimpleButton btnAnimCub; private final StoryboardMove dummyMove; - private int width; - private StoryboardMove[] moves; private GameObject[] gameObjects; @@ -55,14 +57,8 @@ public class MoveStoryboard { private int trackPosition; - public MoveStoryboard(GameContainer container) { - this.width = container.getWidth(); - btnAddLinear = new SimpleButton(width - 205, 50, 200, 25, Fonts.SMALL, "add linear", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON); - btnAddQuadratic = new SimpleButton(width - 205, 80, 200, 25, Fonts.SMALL, "add quadratic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON); - btnAddCubic = new SimpleButton(width - 205, 110, 200, 25, Fonts.SMALL, "add cubic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON); - btnAnimLin = new SimpleButton(width - 250, 50, 40, 25, Fonts.SMALL, "lin", Color.blue, Color.white, Color.white, Color.orange); - btnAnimMid = new SimpleButton(width - 250, 80, 40, 25, Fonts.SMALL, "mid", Color.blue, Color.white, Color.white, Color.orange); - btnAnimCub = new SimpleButton(width - 250, 110, 40, 25, Fonts.SMALL, "cub", Color.blue, Color.white, Color.white, Color.orange); + public MoveStoryboard(DisplayContainer displayContainer) { + this.displayContainer = displayContainer; dummyMove = (StoryboardMove) Proxy.newProxyInstance(StoryboardMove.class.getClassLoader(), new Class[]{StoryboardMove.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { @@ -71,6 +67,16 @@ public class MoveStoryboard { }); } + @Override + public void revalidate() { + btnAddLinear = new SimpleButton(displayContainer.width - 205, 50, 200, 25, Fonts.SMALL, "add linear", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON); + btnAddQuadratic = new SimpleButton(displayContainer.width - 205, 80, 200, 25, Fonts.SMALL, "add quadratic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON); + btnAddCubic = new SimpleButton(displayContainer.width - 205, 110, 200, 25, Fonts.SMALL, "add cubic", Colors.BLUE_BUTTON, Colors.WHITE_FADE, Colors.WHITE_FADE, Colors.ORANGE_BUTTON); + btnAnimLin = new SimpleButton(displayContainer.width - 250, 50, 40, 25, Fonts.SMALL, "lin", Color.blue, Color.white, Color.white, Color.orange); + btnAnimMid = new SimpleButton(displayContainer.width - 250, 80, 40, 25, Fonts.SMALL, "mid", Color.blue, Color.white, Color.white, Color.orange); + btnAnimCub = new SimpleButton(displayContainer.width - 250, 110, 40, 25, Fonts.SMALL, "cub", Color.blue, Color.white, Color.white, Color.orange); + } + /** * Get the point at the current time * @param trackPosition current time in ms @@ -88,7 +94,33 @@ public class MoveStoryboard { return moves[objectIndex].getPointAt(t); } - public void render(Graphics g) { + @Override + public void hide() { + + } + + @Override + public void show() { + + } + + @Override + protected void onPreRenderUpdate() { + int x = displayContainer.mouseX; + int y = displayContainer.mouseY; + btnAddLinear.update(x, y); + btnAddQuadratic.update(x, y); + btnAddCubic.update(x, y); + btnAnimLin.update(x, y); + btnAnimMid.update(x, y); + btnAnimCub.update(x, y); + if (moves[objectIndex] != null) { + moves[objectIndex].update(displayContainer.renderDelta, x, y); + } + } + + @Override + protected void onRender(Graphics g) { btnAddLinear.render(g); btnAddQuadratic.render(g); btnAddCubic.render(g); @@ -100,13 +132,31 @@ public class MoveStoryboard { } } - public void mousePressed(int x, int y) { + @Override + protected boolean onKeyPressed(int key, char c) { + return false; + } + + @Override + protected boolean onKeyReleased(int key, char c) { + return false; + } + + @Override + protected boolean onMouseWheelMoved(int delta) { + return false; + } + + @Override + protected boolean onMousePressed(int button, int x, int y) { if (moves[objectIndex] != null) { moves[objectIndex].mousePressed(x, y); } + return true; } - public void mouseReleased(int x, int y) { + @Override + protected boolean onMouseReleased(int button, int x, int y) { if (moves[objectIndex] != null) { moves[objectIndex].mouseReleased(x, y); if (moves[objectIndex].getAmountOfMovers() == 0) { @@ -114,7 +164,7 @@ public class MoveStoryboard { } } if (objectIndex == 0) { - return; + return true; } if (btnAddLinear.isHovered()) { getCurrentMoveOrCreateNew().add(new LinearStoryboardMover()); @@ -134,6 +184,12 @@ public class MoveStoryboard { if (btnAnimCub.isHovered()) { getCurrentMoveOrDummy().setAnimationEquation(AnimationEquation.IN_OUT_EASE_MIDDLE); } + return true; + } + + @Override + protected boolean onMouseDragged(int oldx, int oldy, int newx, int newy) { + return false; } private StoryboardMove getCurrentMoveOrCreateNew() { @@ -142,7 +198,7 @@ public class MoveStoryboard { return dummyMove; } if (moves[objectIndex] == null) { - return moves[objectIndex] = new StoryboardMoveImpl(gameObjects[objectIndex - 1].end, gameObjects[objectIndex].start, width); + return moves[objectIndex] = new StoryboardMoveImpl(gameObjects[objectIndex - 1].end, gameObjects[objectIndex].start, displayContainer.width); } return moves[objectIndex]; } @@ -154,18 +210,6 @@ public class MoveStoryboard { return moves[objectIndex]; } - public void update(int delta, int x, int y) { - btnAddLinear.update(x, y); - btnAddQuadratic.update(x, y); - btnAddCubic.update(x, y); - btnAnimLin.update(x, y); - btnAnimMid.update(x, y); - btnAnimCub.update(x, y); - if (moves[objectIndex] != null) { - moves[objectIndex].update(delta, x, y); - } - } - public void setGameObjects(GameObject[] gameObjects) { this.gameObjects = gameObjects; this.moves = new StoryboardMove[gameObjects.length]; diff --git a/src/yugecin/opsudance/ui/OptionsOverlay.java b/src/yugecin/opsudance/ui/OptionsOverlay.java index 447a41b8..70e607ac 100644 --- a/src/yugecin/opsudance/ui/OptionsOverlay.java +++ b/src/yugecin/opsudance/ui/OptionsOverlay.java @@ -35,9 +35,10 @@ import yugecin.opsudance.core.state.OverlayOpsuState; public class OptionsOverlay extends OverlayOpsuState { - private final ComplexOpsuState parent; private final DisplayContainer displayContainer; + private Listener listener; + private Image sliderBallImg; private Image checkOnImg; private Image checkOffImg; @@ -81,8 +82,7 @@ public class OptionsOverlay extends OverlayOpsuState { private int sliderSoundDelay; - public OptionsOverlay(ComplexOpsuState parent, DisplayContainer displayContainer, OptionTab[] tabs, int defaultSelectedTabIndex) { - this.parent = parent; + public OptionsOverlay(DisplayContainer displayContainer, OptionTab[] tabs, int defaultSelectedTabIndex) { this.displayContainer = displayContainer; this.tabs = tabs; @@ -91,6 +91,10 @@ public class OptionsOverlay extends OverlayOpsuState { listHoverIndex = -1; } + public void setListener(Listener listener) { + this.listener = listener; + } + @Override public void revalidate() { super.revalidate(); @@ -399,7 +403,9 @@ public class OptionsOverlay extends OverlayOpsuState { if (isListOptionOpen) { if (y > optionStartY && listStartX <= x && x < listStartX + listWidth && listStartY <= y && y < listStartY + listHeight) { hoverOption.clickListItem(listHoverIndex); - // TODO d parent.onSaveOption(hoverOption); + if (listener != null) { + listener.onSaveOption(hoverOption); + } SoundController.playSound(SoundEffect.MENUCLICK); } isListOptionOpen = false; @@ -431,8 +437,8 @@ public class OptionsOverlay extends OverlayOpsuState { @Override public boolean onMouseReleased(int button, int x, int y) { selectedOption = null; - if (isAdjustingSlider) { - // TODO d parent.onSaveOption(hoverOption); + if (isAdjustingSlider && listener != null) { + listener.onSaveOption(hoverOption); } isAdjustingSlider = false; sliderOptionLength = 0; @@ -445,7 +451,9 @@ public class OptionsOverlay extends OverlayOpsuState { if (hoverOption != null) { if (hoverOption.getType() == OptionType.BOOLEAN) { hoverOption.click(); - // TODO d parent.onSaveOption(hoverOption); + if (listener != null) { + listener.onSaveOption(hoverOption); + } SoundController.playSound(SoundEffect.MENUHIT); return true; } else if (hoverOption == GameOption.KEY_LEFT) { @@ -466,6 +474,11 @@ public class OptionsOverlay extends OverlayOpsuState { tScrollOffset += Fonts.MEDIUM.getLineHeight() * 2; tScrollOffset += tab.options.length * optionHeight; } + + if (UI.getBackButton().contains(x, y) && listener != null) { + listener.onLeaveOptionsMenu(); + } + return true; } @@ -500,16 +513,19 @@ public class OptionsOverlay extends OverlayOpsuState { return true; } - switch (key) { - case Input.KEY_ESCAPE: - if (isListOptionOpen) { - isListOptionOpen = false; - listHoverIndex = -1; - return true; - } - hide(); + if (key == Input.KEY_ESCAPE) { + if (isListOptionOpen) { + isListOptionOpen = false; + listHoverIndex = -1; return true; + } + hide(); + if (listener != null) { + listener.onLeaveOptionsMenu(); + } + return true; } + return false; } @@ -570,9 +586,9 @@ public class OptionsOverlay extends OverlayOpsuState { } - public interface Parent { + public interface Listener { - void onLeave(); + void onLeaveOptionsMenu(); void onSaveOption(GameOption option); } diff --git a/src/yugecin/opsudance/ui/SBOverlay.java b/src/yugecin/opsudance/ui/StoryboardOverlay.java similarity index 59% rename from src/yugecin/opsudance/ui/SBOverlay.java rename to src/yugecin/opsudance/ui/StoryboardOverlay.java index 723c0afb..725dc107 100644 --- a/src/yugecin/opsudance/ui/SBOverlay.java +++ b/src/yugecin/opsudance/ui/StoryboardOverlay.java @@ -22,86 +22,27 @@ import itdelatrisu.opsu.Options.GameOption; import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.objects.GameObject; import itdelatrisu.opsu.states.Game; +import itdelatrisu.opsu.states.OptionsMenu; import itdelatrisu.opsu.ui.Fonts; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; 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; import yugecin.opsudance.sbv2.MoveStoryboard; import yugecin.opsudance.ui.OptionsOverlay.OptionTab; import java.util.*; @SuppressWarnings("unchecked") -public class SBOverlay implements OptionsOverlay.Parent { - - private static final OptionTab[] options = new OptionsOverlay.OptionTab[]{ - new OptionTab("Gameplay", new GameOption[] { - GameOption.BACKGROUND_DIM, - GameOption.DANCE_REMOVE_BG, - GameOption.SNAKING_SLIDERS, - GameOption.SHRINKING_SLIDERS, - GameOption.SHOW_HIT_LIGHTING, - GameOption.SHOW_HIT_ANIMATIONS, - GameOption.SHOW_COMBO_BURSTS, - GameOption.SHOW_PERFECT_HIT, - GameOption.SHOW_FOLLOW_POINTS, - }), - new OptionTab("Input", new GameOption[] { - GameOption.CURSOR_SIZE, - GameOption.NEW_CURSOR, - GameOption.DISABLE_CURSOR - }), - new OptionTab("Dance", new GameOption[] { - GameOption.DANCE_MOVER, - GameOption.DANCE_EXGON_DELAY, - GameOption.DANCE_QUAD_BEZ_AGGRESSIVENESS, - GameOption.DANCE_QUAD_BEZ_SLIDER_AGGRESSIVENESS_FACTOR, - GameOption.DANCE_QUAD_BEZ_USE_CUBIC_ON_SLIDERS, - GameOption.DANCE_QUAD_BEZ_CUBIC_AGGRESSIVENESS_FACTOR, - GameOption.DANCE_MOVER_DIRECTION, - GameOption.DANCE_SLIDER_MOVER_TYPE, - GameOption.DANCE_SPINNER, - GameOption.DANCE_SPINNER_DELAY, - GameOption.DANCE_LAZY_SLIDERS, - GameOption.DANCE_CIRCLE_STREAMS, - GameOption.DANCE_ONLY_CIRCLE_STACKS, - GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS, - GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS, - GameOption.DANCE_MIRROR, - }), - new OptionTab("Dance display", new GameOption[] { - GameOption.DANCE_DRAW_APPROACH, - GameOption.DANCE_OBJECT_COLOR_OVERRIDE, - GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED, - GameOption.DANCE_RGB_OBJECT_INC, - GameOption.DANCE_CURSOR_COLOR_OVERRIDE, - GameOption.DANCE_CURSOR_MIRROR_COLOR_OVERRIDE, - GameOption.DANCE_CURSOR_ONLY_COLOR_TRAIL, - GameOption.DANCE_RGB_CURSOR_INC, - GameOption.DANCE_CURSOR_TRAIL_OVERRIDE, - GameOption.DANCE_HIDE_OBJECTS, - GameOption.DANCE_HIDE_UI, - GameOption.DANCE_HIDE_WATERMARK, - }), - new OptionTab ("Pippi", new GameOption[] { - GameOption.PIPPI_ENABLE, - GameOption.PIPPI_RADIUS_PERCENT, - GameOption.PIPPI_ANGLE_INC_MUL, - GameOption.PIPPI_ANGLE_INC_MUL_SLIDER, - GameOption.PIPPI_SLIDER_FOLLOW_EXPAND, - GameOption.PIPPI_PREVENT_WOBBLY_STREAMS, - }) - }; +public class StoryboardOverlay extends OverlayOpsuState implements OptionsOverlay.Listener { private final static List optionList = new ArrayList<>(); - private boolean hide; - private boolean menu; + private final DisplayContainer displayContainer; - private int width; - private int height; + private boolean hide; private int speed; private GameObject[] gameObjects; @@ -112,43 +53,42 @@ public class SBOverlay implements OptionsOverlay.Parent { private final Game game; private final MoveStoryboard msb; - private OptionsOverlay overlay; + private final OptionsOverlay optionsOverlay; static { - for (OptionTab tab : options) { + for (OptionTab tab : OptionsMenu.storyboardOptions) { optionList.addAll(Arrays.asList(tab.options)); } } - public SBOverlay(Game game, MoveStoryboard msb, GameContainer container) { - this.game = game; + public StoryboardOverlay(DisplayContainer displayContainer, MoveStoryboard msb, OptionsOverlay optionsOverlay, Game game) { + this.displayContainer = displayContainer; this.msb = msb; + this.optionsOverlay = optionsOverlay; + this.game = game; initialOptions = new HashMap<>(); - //overlay = new OptionsOverlay(this, options, 2, container); - this.width = container.getWidth(); - this.height = container.getHeight(); speed = 10; gameObjects = new GameObject[0]; } - public void render(GameContainer container, Graphics g) { + @Override + public void onRender(Graphics g) { if (!Options.isEnableSB() || hide) { return; } - msb.render(g); int lh = Fonts.SMALL.getLineHeight(); - Fonts.SMALL.drawString(10, height - 50 + lh, "save position: ctrl+s, load position: ctrl+l", Color.cyan); - Fonts.SMALL.drawString(10, height - 50, "speed: C " + (speed / 10f) + " V", Color.cyan); - Fonts.SMALL.drawString(10, height - 50 - lh, "Menu: N", Color.cyan); - Fonts.SMALL.drawString(10, height - 50 - lh * 2, "HIDE: H", Color.cyan); - Fonts.SMALL.drawString(10, height - 50 - lh * 3, "obj: J " + index + " K", Color.cyan); + Fonts.SMALL.drawString(10, displayContainer.height - 50 + lh, "save position: ctrl+s, load position: ctrl+l", Color.cyan); + Fonts.SMALL.drawString(10, displayContainer.height - 50, "speed: C " + (speed / 10f) + " V", Color.cyan); + Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh, "Menu: N", Color.cyan); + Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh * 2, "HIDE: H", Color.cyan); + Fonts.SMALL.drawString(10, displayContainer.height - 50 - lh * 3, "obj: J " + index + " K", Color.cyan); g.setColor(Color.red); if (index < optionsMap.length && optionsMap[index] != null) { int i = 0; for (Object o : optionsMap[index].entrySet()) { Map.Entry option = (Map.Entry) o; Fonts.SMALL.drawString(10, 50 + i * lh, option.getKey().getName(), Color.cyan); - Fonts.SMALL.drawString(width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan); + Fonts.SMALL.drawString(displayContainer.width / 5, 50 + i * lh, option.getKey().getValueString(), Color.cyan); g.fillRect(0, 50 + i * lh + lh / 4, 10, 10); i++; } @@ -157,27 +97,16 @@ public class SBOverlay implements OptionsOverlay.Parent { int start = gameObjects[0].getTime(); int end = gameObjects[gameObjects.length - 1].getEndTime(); float curtime = (float) (MusicController.getPosition() - start) / (end - start); - g.fillRect(curtime * width, height - 10f, 10f, 10f); - } - if (menu) { - //overlay.render(g, container.getInput().getMouseX(), container.getInput().getMouseY()); + g.fillRect(curtime * displayContainer.width, displayContainer.height - 10f, 10f, 10f); } } - public void update(int delta, int mouseX, int mouseY) { - if (Options.isEnableSB() && menu) { - //overlay.update(delta, mouseX, mouseY); - } - msb.update(delta, mouseX, mouseY); + @Override + public void onPreRenderUpdate() { } - public boolean keyPressed(int key, char c) { - if (!Options.isEnableSB()) { - return false; - } - if (menu && overlay.keyPressed(key, c)) { - return true; - } + @Override + public boolean onKeyPressed(int key, char c) { if (key == Input.KEY_C) { if (speed > 0) { speed -= 1; @@ -196,11 +125,9 @@ public class SBOverlay implements OptionsOverlay.Parent { } else if (key == Input.KEY_H) { hide = !hide; } else if (key == Input.KEY_N) { - menu = !menu; - if (menu && speed != 0) { + optionsOverlay.show(); + if (speed != 0) { MusicController.pause(); - } else if (!menu && speed != 0) { - MusicController.resume(); } } else if (key == Input.KEY_J && index > 0) { index--; @@ -214,6 +141,11 @@ public class SBOverlay implements OptionsOverlay.Parent { return false; } + @Override + protected boolean onKeyReleased(int key, char c) { + return false; + } + private void goBackOneSBIndex() { if (index + 1 < optionsMap.length) { // new options on previous index, so to revert then we have to reload them all to this point.. @@ -252,20 +184,13 @@ public class SBOverlay implements OptionsOverlay.Parent { this.gameObjects = gameObjects; } - public boolean mousePressed(int button, int x, int y) { - msb.mousePressed(x, y); - if (!menu) { - return false; - } - overlay.mousePressed(button, x, y); + @Override + public boolean onMousePressed(int button, int x, int y) { return true; } - public boolean mouseDragged(int oldx, int oldy, int newx, int newy) { - if (!menu) { - return false; - } - overlay.mouseDragged(oldx, oldy, newx, newy); + @Override + public boolean onMouseDragged(int oldx, int oldy, int newx, int newy) { return true; } @@ -293,12 +218,8 @@ public class SBOverlay implements OptionsOverlay.Parent { this.index--; } - public boolean mouseReleased(int button, int x, int y) { - if (menu) { - overlay.mouseReleased(button, x, y); - return true; - } - msb.mouseReleased(x, y); + @Override + public boolean onMouseReleased(int button, int x, int y) { if (x > 10 || index >= optionsMap.length || optionsMap[index] == null) { return false; } @@ -318,15 +239,12 @@ public class SBOverlay implements OptionsOverlay.Parent { return true; } - public boolean mouseWheelMoved(int delta) { - if (!menu) { - return false; - } - overlay.mouseWheelMoved(delta); + @Override + public boolean onMouseWheelMoved(int delta) { return true; } - public void enter() { + public void onEnter() { // enter, save current settings for (Options.GameOption o : optionList) { initialOptions.put(o, o.write()); @@ -334,7 +252,7 @@ public class SBOverlay implements OptionsOverlay.Parent { speed = 10; } - public void leave() { + public void onLeave() { // leave, revert the settings saved before entering for (Options.GameOption o : optionList) { if (initialOptions.containsKey(o)) { @@ -358,13 +276,8 @@ public class SBOverlay implements OptionsOverlay.Parent { } } - public float[] getPoint(int trackPosition) { - return msb.getPoint(trackPosition); - } - @Override - public void onLeave() { - menu = false; + public void onLeaveOptionsMenu() { if (speed != 0) { MusicController.resume(); } From 2d0e2143d11b4585a4c697921eec464737254afc Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 19 Jan 2017 19:43:47 +0100 Subject: [PATCH 29/38] convert gamepausemenu --- src/itdelatrisu/opsu/Opsu.java | 2 +- src/itdelatrisu/opsu/states/Game.java | 14 +- .../opsu/states/GamePauseMenu.java | 171 +++++++++--------- .../core/inject/OpsuDanceInjector.java | 1 + 4 files changed, 94 insertions(+), 94 deletions(-) diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java index 131178b8..b2c6d410 100644 --- a/src/itdelatrisu/opsu/Opsu.java +++ b/src/itdelatrisu/opsu/Opsu.java @@ -90,7 +90,7 @@ public class Opsu extends StateBasedGame { //addState(new ButtonMenu(STATE_BUTTONMENU)); //addState(new SongMenu(STATE_SONGMENU)); //addState(new Game(STATE_GAME)); - addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); + //addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); //addState(new GameRanking(STATE_GAMERANKING)); //addState(new OptionsMenu(STATE_OPTIONSMENU)); //addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 1dd3c7dd..c3d555f6 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -66,6 +66,8 @@ import yugecin.opsudance.*; import yugecin.opsudance.core.DisplayContainer; 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.BubbleNotificationEvent; import yugecin.opsudance.objects.curves.FakeCombinedCurve; import yugecin.opsudance.sbv2.MoveStoryboard; @@ -802,7 +804,7 @@ public class Game extends ComplexOpsuState { // focus lost: go back to pause screen else if (!Display.isActive()) { - // TODO d displayContainer.switchState(GamePauseMenu.class); + displayContainer.switchStateNow(GamePauseMenu.class); pausePulse = 0f; } @@ -1034,7 +1036,7 @@ public class Game extends ComplexOpsuState { if (MusicController.isPlaying() || isLeadIn()) { pauseTime = trackPosition; } - // TODO d displayContainer.switchState(GamePauseMenu.class); + displayContainer.switchStateNow(GamePauseMenu.class); } // drain health @@ -1061,7 +1063,7 @@ public class Game extends ComplexOpsuState { rotations = new IdentityHashMap<>(); SoundController.playSound(SoundEffect.FAIL); - // TODO d displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300); + displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300); } } } @@ -1143,7 +1145,7 @@ public class Game extends ComplexOpsuState { if (MusicController.isPlaying() || isLeadIn()) { pauseTime = trackPosition; } - // TODO d displayContainer.switchStateNow(GamePauseMenu.class); + displayContainer.switchStateNow(GamePauseMenu.class); break; case Input.KEY_SPACE: // skip intro @@ -1296,7 +1298,7 @@ public class Game extends ComplexOpsuState { if (MusicController.isPlaying() || isLeadIn()) { pauseTime = trackPosition; } - // TODO d displayContainer.switchStateNow(GamePauseMenu.class); + displayContainer.switchStateNow(GamePauseMenu.class); return true; } @@ -1973,7 +1975,7 @@ public class Game extends ComplexOpsuState { skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT); // load other images... - // TODO d instanceContainer.provide(GamePauseMenu.class).loadImages(); + instanceContainer.provide(GamePauseMenu.class).loadImages(); data.loadImages(); } diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java index a9d5a7ad..58d83ef5 100644 --- a/src/itdelatrisu/opsu/states/GamePauseMenu.java +++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java @@ -19,9 +19,7 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GameImage; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; -import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundEffect; @@ -31,14 +29,11 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation; import org.lwjgl.input.Keyboard; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.BasicGameState; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.FadeInTransition; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; +import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.inject.InstanceContainer; +import yugecin.opsudance.core.state.BaseOpsuState; /** * "Game Pause/Fail" state. @@ -46,33 +41,22 @@ import org.newdawn.slick.state.transition.EasedFadeOutTransition; * Players are able to continue the game (if applicable), retry the beatmap, * or return to the song menu from this state. */ -public class GamePauseMenu extends BasicGameState { - /** "Continue", "Retry", and "Back" buttons. */ +public class GamePauseMenu extends BaseOpsuState { + + private final InstanceContainer instanceContainer; + private MenuButton continueButton, retryButton, backButton; - // game-related variables - private GameContainer container; - private StateBasedGame game; - private Input input; - private final int state; - private Game gameState; + private final Game gameState; - public GamePauseMenu(int state) { - this.state = state; + public GamePauseMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer, Game gameState) { + super(displayContainer); + this.instanceContainer = instanceContainer; + this.gameState = gameState; } @Override - public void init(GameContainer container, StateBasedGame game) - throws SlickException { - this.container = container; - this.game = game; - this.input = container.getInput(); - this.gameState = (Game) game.getState(Opsu.STATE_GAME); - } - - @Override - public void render(GameContainer container, StateBasedGame game, Graphics g) - throws SlickException { + public void render(Graphics g) { // get background image GameImage bg = (gameState.getRestart() == Game.Restart.LOSE) ? GameImage.FAIL_BACKGROUND : GameImage.PAUSE_OVERLAY; @@ -97,81 +81,78 @@ public class GamePauseMenu extends BasicGameState { } @Override - public void update(GameContainer container, StateBasedGame game, int delta) - throws SlickException { + public void preRenderUpdate() { + int delta = displayContainer.renderDelta; UI.update(delta); - int mouseX = input.getMouseX(), mouseY = input.getMouseY(); - continueButton.hoverUpdate(delta, mouseX, mouseY); - retryButton.hoverUpdate(delta, mouseX, mouseY); - backButton.hoverUpdate(delta, mouseX, mouseY); + continueButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); + retryButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); + backButton.hoverUpdate(delta, displayContainer.mouseX, displayContainer.mouseY); } @Override - public int getID() { return state; } - - @Override - public void keyPressed(int key, char c) { - // game keys - if (!Keyboard.isRepeatEvent()) { - if (key == Options.getGameKeyLeft()) - mousePressed(Input.MOUSE_LEFT_BUTTON, input.getMouseX(), input.getMouseY()); - else if (key == Options.getGameKeyRight()) - mousePressed(Input.MOUSE_RIGHT_BUTTON, input.getMouseX(), input.getMouseY()); + public boolean keyPressed(int key, char c) { + if (super.keyPressed(key, c)) { + return true; } - switch (key) { - case Input.KEY_ESCAPE: + // game keys + if (!Keyboard.isRepeatEvent()) { + if (key == Options.getGameKeyLeft()) { + mousePressed(Input.MOUSE_LEFT_BUTTON, displayContainer.mouseX, displayContainer.mouseY); + } else if (key == Options.getGameKeyRight()) { + mousePressed(Input.MOUSE_RIGHT_BUTTON, displayContainer.mouseX, displayContainer.mouseY); + } + } + + if (key == Input.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); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad(); + instanceContainer.provide(SongMenu.class).resetGameDataOnLoad(); MusicController.playAt(MusicController.getBeatmap().previewTime, true); - if (UI.getCursor().isBeatmapSkinned()) + if (UI.getCursor().isBeatmapSkinned()) { UI.getCursor().reset(); - game.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition()); + } + displayContainer.switchState(SongMenu.class); } else { SoundController.playSound(SoundEffect.MENUBACK); gameState.setRestart(Game.Restart.FALSE); - game.enterState(Opsu.STATE_GAME); + displayContainer.switchState(Game.class); } - break; - case Input.KEY_R: - // restart - if (input.isKeyDown(Input.KEY_RCONTROL) || input.isKeyDown(Input.KEY_LCONTROL)) { - gameState.setRestart(Game.Restart.MANUAL); - game.enterState(Opsu.STATE_GAME); - } - break; - case Input.KEY_F7: - // TODO d - //Options.setNextFPS(container); - break; - case Input.KEY_F10: - Options.toggleMouseDisabled(); - break; - case Input.KEY_F12: - Utils.takeScreenShot(); - break; + return true; } + + if (key == Input.KEY_R && (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL))) { + gameState.setRestart(Game.Restart.MANUAL); + displayContainer.switchState(Game.class); + return true; + } + + return false; } @Override - public void mousePressed(int button, int x, int y) { - if (button == Input.MOUSE_MIDDLE_BUTTON) - return; + public boolean mousePressed(int button, int x, int y) { + if (super.mousePressed(button, x, y)) { + return true; + } + + if (button == Input.MOUSE_MIDDLE_BUTTON) { + return true; + } boolean loseState = (gameState.getRestart() == Game.Restart.LOSE); if (continueButton.contains(x, y) && !loseState) { SoundController.playSound(SoundEffect.MENUBACK); gameState.setRestart(Game.Restart.FALSE); - game.enterState(Opsu.STATE_GAME); + displayContainer.switchState(Game.class); } else if (retryButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUHIT); gameState.setRestart(Game.Restart.MANUAL); - game.enterState(Opsu.STATE_GAME); + displayContainer.switchState(Game.class); } else if (backButton.contains(x, y)) { SoundController.playSound(SoundEffect.MENUBACK); - ((SongMenu) game.getState(Opsu.STATE_SONGMENU)).resetGameDataOnLoad(); + instanceContainer.provide(SongMenu.class).resetGameDataOnLoad(); if (loseState) MusicController.playAt(MusicController.getBeatmap().previewTime, true); else @@ -179,21 +160,30 @@ public class GamePauseMenu extends BasicGameState { if (UI.getCursor().isBeatmapSkinned()) UI.getCursor().reset(); MusicController.setPitch(1.0f); - game.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition()); + displayContainer.switchState(SongMenu.class); } + + return true; } @Override - public void mouseWheelMoved(int newValue) { - if (Options.isMouseWheelDisabled()) - return; + public boolean mouseWheelMoved(int newValue) { + if (super.mouseWheelMoved(newValue)) { + return true; + } + + if (Options.isMouseWheelDisabled()) { + return true; + } UI.changeVolume((newValue < 0) ? -1 : 1); + return true; } @Override - public void enter(GameContainer container, StateBasedGame game) - throws SlickException { + public void enter() { + super.enter(); + UI.enter(); MusicController.pause(); continueButton.resetHover(); @@ -201,17 +191,23 @@ public class GamePauseMenu extends BasicGameState { backButton.resetHover(); } + @Override + public boolean onCloseRequest() { + SongMenu songmenu = instanceContainer.provide(SongMenu.class); + songmenu.resetTrackOnLoad(); + songmenu.resetGameDataOnLoad(); + displayContainer.switchState(SongMenu.class); + return false; + } + /** * Loads all game pause/fail menu images. */ public void loadImages() { - int width = container.getWidth(); - int height = container.getHeight(); - // initialize buttons - continueButton = new MenuButton(GameImage.PAUSE_CONTINUE.getImage(), width / 2f, height * 0.25f); - retryButton = new MenuButton(GameImage.PAUSE_RETRY.getImage(), width / 2f, height * 0.5f); - backButton = new MenuButton(GameImage.PAUSE_BACK.getImage(), width / 2f, height * 0.75f); + continueButton = new MenuButton(GameImage.PAUSE_CONTINUE.getImage(), displayContainer.width / 2f, displayContainer.height * 0.25f); + retryButton = new MenuButton(GameImage.PAUSE_RETRY.getImage(), displayContainer.width / 2f, displayContainer.height * 0.5f); + backButton = new MenuButton(GameImage.PAUSE_BACK.getImage(), displayContainer.width / 2f, displayContainer.height * 0.75f); final int buttonAnimationDuration = 300; continueButton.setHoverAnimationDuration(buttonAnimationDuration); retryButton.setHoverAnimationDuration(buttonAnimationDuration); @@ -224,4 +220,5 @@ public class GamePauseMenu extends BasicGameState { retryButton.setHoverExpand(); backButton.setHoverExpand(); } + } diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 98ab2278..39a4ce64 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -59,6 +59,7 @@ public class OpsuDanceInjector extends Injector { bind(DownloadsMenu.class).asEagerSingleton(); bind(GameRanking.class).asEagerSingleton(); bind(Game.class).asEagerSingleton(); + bind(GamePauseMenu.class).asEagerSingleton(); } } From 0af6bc8c09bf86aeaa49301209a97ad98d6785ca Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 19 Jan 2017 19:52:13 +0100 Subject: [PATCH 30/38] return to songmenu when closing game ranking screen --- src/itdelatrisu/opsu/states/Game.java | 8 ++++++-- src/itdelatrisu/opsu/states/GameRanking.java | 11 +++++++++++ src/itdelatrisu/opsu/states/SongMenu.java | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index c3d555f6..53200135 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -1894,7 +1894,9 @@ public class Game extends ComplexOpsuState { * Resets all game data and structures. */ public void resetGameData() { - data.clear(); + if (data != null) { + data.clear(); + } objectIndex = 0; breakIndex = 0; breakTime = 0; @@ -1916,7 +1918,9 @@ public class Game extends ComplexOpsuState { autoMousePosition = new Vec2f(); autoMousePressed = false; flashlightRadius = displayContainer.height * 2 / 3; - scoreboardStarStream.clear(); + if (scoreboardStarStream != null) { + scoreboardStarStream.clear(); + } gameFinished = false; gameFinishedTimer.setTime(0); diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index 6a92d44b..fdec21fc 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -220,6 +220,17 @@ public class GameRanking extends BaseOpsuState { } } + @Override + public boolean onCloseRequest() { + SongMenu songmenu = instanceContainer.provide(SongMenu.class); + if (data != null && data.isGameplay()) { + songmenu.resetTrackOnLoad(); + } + songmenu.resetGameDataOnLoad(); + displayContainer.switchState(SongMenu.class); + return false; + } + /** * Returns to the song menu. */ diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index ee06bb49..d1b98ac6 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -1025,7 +1025,7 @@ public class SongMenu extends ComplexOpsuState { if (button != Input.MOUSE_RIGHT_BUTTON) { // view score instanceContainer.provide(GameRanking.class).setGameData(new GameData(focusScores[rank], displayContainer.width, displayContainer.height)); - // TODO d displayContainer.switchState(GameRanking.class); + displayContainer.switchState(GameRanking.class); } else { // score management instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.SCORE, focusScores[rank]); From 84fb44475f0dbd7d01d980a634432cff1bb37638 Mon Sep 17 00:00:00 2001 From: yugecin Date: Thu, 19 Jan 2017 19:55:25 +0100 Subject: [PATCH 31/38] fix array index oob exception when changing dropdown option (fixes #118) --- src/yugecin/opsudance/ui/OptionsOverlay.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/yugecin/opsudance/ui/OptionsOverlay.java b/src/yugecin/opsudance/ui/OptionsOverlay.java index 70e607ac..0aae9e08 100644 --- a/src/yugecin/opsudance/ui/OptionsOverlay.java +++ b/src/yugecin/opsudance/ui/OptionsOverlay.java @@ -30,7 +30,6 @@ import itdelatrisu.opsu.ui.MenuButton; import itdelatrisu.opsu.ui.UI; import org.newdawn.slick.*; import yugecin.opsudance.core.DisplayContainer; -import yugecin.opsudance.core.state.ComplexOpsuState; import yugecin.opsudance.core.state.OverlayOpsuState; public class OptionsOverlay extends OverlayOpsuState { @@ -402,9 +401,11 @@ public class OptionsOverlay extends OverlayOpsuState { if (isListOptionOpen) { if (y > optionStartY && listStartX <= x && x < listStartX + listWidth && listStartY <= y && y < listStartY + listHeight) { - hoverOption.clickListItem(listHoverIndex); - if (listener != null) { - listener.onSaveOption(hoverOption); + if (0 <= listHoverIndex && listHoverIndex < hoverOption.getListItems().length) { + hoverOption.clickListItem(listHoverIndex); + if (listener != null) { + listener.onSaveOption(hoverOption); + } } SoundController.playSound(SoundEffect.MENUCLICK); } From 63660dfe94a01b17da721e2806d65e63626d639a Mon Sep 17 00:00:00 2001 From: yugecin Date: Fri, 20 Jan 2017 00:15:50 +0100 Subject: [PATCH 32/38] added exit confirmations when download is going on --- .../opsudance/core/DisplayContainer.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index fac7d085..e8d84665 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -22,6 +22,8 @@ import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.beatmap.Beatmap; +import itdelatrisu.opsu.downloads.DownloadList; +import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.ui.Fonts; import org.lwjgl.Sys; import org.lwjgl.openal.AL; @@ -102,6 +104,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen private String glVersion; private String glVendor; + private long exitconfirmation; + public DisplayContainer(InstanceContainer instanceContainer, EventBus eventBus) { this.instanceContainer = instanceContainer; this.eventBus = eventBus; @@ -155,7 +159,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen public void run() throws Exception { - while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest())) { + while(!exitRequested && !(Display.isCloseRequested() && state.onCloseRequest()) || !confirmExit()) { delta = getDelta(); timeSinceLastRender += delta; @@ -238,6 +242,23 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen } } + private boolean confirmExit() { + if (System.currentTimeMillis() - exitconfirmation < 10000) { + return true; + } + if (DownloadList.get().hasActiveDownloads()) { + eventBus.post(new BubbleNotificationEvent(DownloadList.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE)); + exitRequested = false; + return false; + } + if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING) { + eventBus.post(new BubbleNotificationEvent(Updater.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE)); + exitRequested = false; + return false; + } + return true; + } + public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception { if (this.width == width && this.height == height) { Display.setFullscreen(fullscreen); From 4bf469d40b25e270bf16faac63a62195724d2f90 Mon Sep 17 00:00:00 2001 From: yugecin Date: Fri, 20 Jan 2017 00:18:25 +0100 Subject: [PATCH 33/38] some more shutdown calls --- src/yugecin/opsudance/OpsuDance.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index e8b5b28a..04b04054 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -19,9 +19,11 @@ package yugecin.opsudance; import itdelatrisu.opsu.Options; 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.render.CurveRenderState; import itdelatrisu.opsu.states.Splash; import org.newdawn.slick.util.Log; import yugecin.opsudance.core.DisplayContainer; @@ -76,6 +78,10 @@ public class OpsuDance { DBController.closeConnections(); DownloadList.get().cancelAllDownloads(); Utils.deleteDirectory(Options.TEMP_DIR); + CurveRenderState.shutdown(); + if (!Options.isWatchServiceEnabled()) { + BeatmapWatchService.destroy(); + } } private boolean rungame() { From 04de1d024fa741990350a03d3e894ddfde775ec9 Mon Sep 17 00:00:00 2001 From: yugecin Date: Fri, 20 Jan 2017 00:25:32 +0100 Subject: [PATCH 34/38] fix not being able to shutdown when download is in progress --- src/yugecin/opsudance/core/DisplayContainer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index e8d84665..4385de56 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -249,11 +249,13 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen if (DownloadList.get().hasActiveDownloads()) { eventBus.post(new BubbleNotificationEvent(DownloadList.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE)); 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)); exitRequested = false; + exitconfirmation = System.currentTimeMillis(); return false; } return true; From aceebb95ca3dc7cd92c54af221d605b8113592f8 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sat, 21 Jan 2017 00:39:56 +0100 Subject: [PATCH 35/38] re-add the runupdate call --- src/yugecin/opsudance/core/Entrypoint.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/yugecin/opsudance/core/Entrypoint.java b/src/yugecin/opsudance/core/Entrypoint.java index 88225e8c..dfba2245 100644 --- a/src/yugecin/opsudance/core/Entrypoint.java +++ b/src/yugecin/opsudance/core/Entrypoint.java @@ -17,6 +17,7 @@ */ package yugecin.opsudance.core; +import itdelatrisu.opsu.downloads.Updater; import yugecin.opsudance.OpsuDance; import yugecin.opsudance.core.inject.OpsuDanceInjector; @@ -27,6 +28,10 @@ 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(); + } } public static long runtime() { From f730935622d33da4e168f18f7bcc927997cd9772 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sat, 21 Jan 2017 01:16:27 +0100 Subject: [PATCH 36/38] use the new errorhandler & bubble notifs --- src/itdelatrisu/opsu/GameImage.java | 16 +++++--- src/itdelatrisu/opsu/Options.java | 20 ++++++---- src/itdelatrisu/opsu/Utils.java | 24 +++++++----- src/itdelatrisu/opsu/audio/MultiClip.java | 4 +- .../opsu/audio/MusicController.java | 15 +++++--- .../opsu/audio/SoundController.java | 12 +++--- .../opsu/beatmap/BeatmapParser.java | 26 +++++++++---- .../opsu/beatmap/BeatmapSetList.java | 7 ++-- .../opsu/beatmap/BeatmapWatchService.java | 9 +++-- src/itdelatrisu/opsu/beatmap/OszUnpacker.java | 9 +++-- src/itdelatrisu/opsu/db/BeatmapDB.java | 38 +++++++++---------- src/itdelatrisu/opsu/db/DBController.java | 6 +-- src/itdelatrisu/opsu/db/ScoreDB.java | 20 +++++----- src/itdelatrisu/opsu/downloads/Download.java | 10 +++-- .../opsu/downloads/DownloadNode.java | 5 ++- src/itdelatrisu/opsu/downloads/Updater.java | 4 +- .../downloads/servers/BloodcatServer.java | 4 +- .../opsu/downloads/servers/HexideServer.java | 4 +- .../opsu/downloads/servers/MengSkyServer.java | 4 +- .../downloads/servers/MnetworkServer.java | 4 +- .../downloads/servers/OsuMirrorServer.java | 4 +- .../downloads/servers/YaSOnlineServer.java | 6 +-- .../opsu/render/CurveRenderState.java | 2 +- .../opsu/render/FrameBufferCache.java | 1 + src/itdelatrisu/opsu/replay/Replay.java | 10 +++-- .../opsu/replay/ReplayImporter.java | 17 ++++++--- src/itdelatrisu/opsu/skins/SkinLoader.java | 7 +++- .../opsu/states/DownloadsMenu.java | 1 - src/itdelatrisu/opsu/states/MainMenu.java | 10 +++-- src/itdelatrisu/opsu/ui/Cursor.java | 5 +-- src/itdelatrisu/opsu/ui/UI.java | 16 -------- src/yugecin/opsudance/OpsuDance.java | 8 ++-- .../opsudance/core/DisplayContainer.java | 2 + .../core/errorhandling/ErrorHandler.java | 12 +++++- .../opsudance/core/events/EventBus.java | 4 ++ 35 files changed, 199 insertions(+), 147 deletions(-) diff --git a/src/itdelatrisu/opsu/GameImage.java b/src/itdelatrisu/opsu/GameImage.java index cd1dd463..17efa2de 100644 --- a/src/itdelatrisu/opsu/GameImage.java +++ b/src/itdelatrisu/opsu/GameImage.java @@ -27,7 +27,11 @@ import java.util.List; import org.newdawn.slick.Animation; import org.newdawn.slick.Image; 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.utils.SlickUtil; /** @@ -706,7 +710,9 @@ public enum GameImage { return; } - ErrorHandler.error(String.format("Could not find default image '%s'.", filename), null, false); + String err = String.format("Could not find default image '%s'.", filename); + Log.warn(err); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } /** @@ -765,7 +771,7 @@ public enum GameImage { img = img.getScaledCopy(0.5f); list.add(img); } catch (SlickException e) { - ErrorHandler.error(String.format("Failed to set image '%s'.", name), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", name), BubbleNotificationEvent.COMMONCOLOR_RED)); break; } } @@ -779,7 +785,7 @@ public enum GameImage { img = img.getScaledCopy(0.5f); list.add(img); } catch (SlickException e) { - ErrorHandler.error(String.format("Failed to set image '%s'.", name), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", name), BubbleNotificationEvent.COMMONCOLOR_RED)); break; } } @@ -806,7 +812,7 @@ public enum GameImage { img = img.getScaledCopy(0.5f); return img; } catch (SlickException e) { - ErrorHandler.error(String.format("Failed to set image '%s'.", filename), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", filename), BubbleNotificationEvent.COMMONCOLOR_RED)); } } } @@ -851,7 +857,7 @@ public enum GameImage { skinImages = null; } } catch (SlickException e) { - ErrorHandler.error(String.format("Failed to destroy beatmap skin images for '%s'.", this.name()), e, true); + ErrorHandler.error(String.format("Failed to destroy beatmap skin images for '%s'.", this.name()), e).show(); } } diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index 03a8c772..e095c5d2 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -60,6 +60,8 @@ import com.sun.jna.platform.win32.Win32Exception; import com.sun.jna.platform.win32.WinReg; import yugecin.opsudance.*; import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.errorhandling.ErrorHandler; +import yugecin.opsudance.core.events.EventBus; import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.movers.factories.ExgonMoverFactory; import yugecin.opsudance.movers.factories.QuadraticBezierMoverFactory; @@ -197,7 +199,7 @@ public class Options { } File dir = new File(rootPath, "opsu"); if (!dir.isDirectory() && !dir.mkdir()) - ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), null, false); + ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), new Exception("empty")).preventReport().show(); return dir; } else return workingDir; @@ -1785,7 +1787,7 @@ public class Options { // use default directory beatmapDir = BEATMAP_DIR; if (!beatmapDir.isDirectory() && !beatmapDir.mkdir()) - ErrorHandler.error(String.format("Failed to create beatmap directory at '%s'.", beatmapDir.getAbsolutePath()), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create beatmap directory at '%s'.", beatmapDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED)); return beatmapDir; } @@ -1800,7 +1802,7 @@ public class Options { oszDir = new File(DATA_DIR, "SongPacks/"); if (!oszDir.isDirectory() && !oszDir.mkdir()) - ErrorHandler.error(String.format("Failed to create song packs directory at '%s'.", oszDir.getAbsolutePath()), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create song packs directory at '%s'.", oszDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED)); return oszDir; } @@ -1815,7 +1817,7 @@ public class Options { replayImportDir = new File(DATA_DIR, "ReplayImport/"); if (!replayImportDir.isDirectory() && !replayImportDir.mkdir()) - ErrorHandler.error(String.format("Failed to create replay import directory at '%s'.", replayImportDir.getAbsolutePath()), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create replay import directory at '%s'.", replayImportDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED)); return replayImportDir; } @@ -1865,7 +1867,7 @@ public class Options { // use default directory skinRootDir = SKIN_ROOT_DIR; if (!skinRootDir.isDirectory() && !skinRootDir.mkdir()) - ErrorHandler.error(String.format("Failed to create skins directory at '%s'.", skinRootDir.getAbsolutePath()), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create skins directory at '%s'.", skinRootDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED)); return skinRootDir; } @@ -1998,7 +2000,9 @@ public class Options { } GameOption.DANCE_HIDE_WATERMARK.setValue(false); } catch (IOException e) { - ErrorHandler.error(String.format("Failed to read file '%s'.", OPTIONS_FILE.getAbsolutePath()), e, false); + String err = String.format("Failed to read file '%s'.", OPTIONS_FILE.getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } @@ -2027,7 +2031,9 @@ public class Options { } writer.close(); } catch (IOException e) { - ErrorHandler.error(String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath()), e, false); + String err = String.format("Failed to write to file '%s'.", OPTIONS_FILE.getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } } diff --git a/src/itdelatrisu/opsu/Utils.java b/src/itdelatrisu/opsu/Utils.java index a66e320d..746a5e68 100644 --- a/src/itdelatrisu/opsu/Utils.java +++ b/src/itdelatrisu/opsu/Utils.java @@ -73,6 +73,9 @@ 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.events.EventBus; +import yugecin.opsudance.events.BubbleNotificationEvent; /** * Contains miscellaneous utilities. @@ -245,14 +248,14 @@ public class Utils { // create the screenshot directory File dir = Options.getScreenshotDir(); if (!dir.isDirectory() && !dir.mkdir()) { - ErrorHandler.error(String.format("Failed to create screenshot directory at '%s'.", dir.getAbsolutePath()), null, false); + EventBus.instance.post(new BubbleNotificationEvent(String.format("Failed to create screenshot directory at '%s'.", dir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED)); return; } // create file name SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss"); - final File file = new File(dir, String.format("screenshot_%s.%s", - date.format(new Date()), Options.getScreenshotFormat())); + final String fileName = String.format("screenshot_%s.%s", date.format(new Date()), Options.getScreenshotFormat()); + final File file = new File(dir, fileName); SoundController.playSound(SoundEffect.SHUTTER); @@ -279,8 +282,9 @@ public class Utils { } } ImageIO.write(image, Options.getScreenshotFormat(), file); + EventBus.instance.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE)); } catch (Exception e) { - ErrorHandler.error("Failed to take a screenshot.", e, true); + ErrorHandler.error("Failed to take a screenshot.", e).show(); } } }.start(); @@ -429,7 +433,7 @@ public class Utils { try { json = new JSONObject(s); } catch (JSONException e) { - ErrorHandler.error("Failed to create JSON object.", e, true); + ErrorHandler.error("Failed to create JSON object.", e).show(); } } return json; @@ -448,7 +452,7 @@ public class Utils { try { json = new JSONArray(s); } catch (JSONException e) { - ErrorHandler.error("Failed to create JSON array.", e, true); + ErrorHandler.error("Failed to create JSON array.", e).show(); } } return json; @@ -490,7 +494,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, true); + ErrorHandler.error("Failed to calculate MD5 hash.", e).show(); } return null; } @@ -514,7 +518,7 @@ public class Utils { * @return true if JAR, false if file */ public static boolean isJarRunning() { - return Opsu.class.getResource(String.format("%s.class", Opsu.class.getSimpleName())).toString().startsWith("jar:"); + return Utils.class.getResource(String.format("%s.class", Utils.class.getSimpleName())).toString().startsWith("jar:"); } /** @@ -526,7 +530,7 @@ public class Utils { return null; try { - return new JarFile(new File(Opsu.class.getProtectionDomain().getCodeSource().getLocation().toURI()), false); + 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; @@ -539,7 +543,7 @@ public class Utils { */ public static File getRunningDirectory() { try { - return new File(Opsu.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); + return new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); } catch (URISyntaxException e) { Log.error("Could not get the running directory.", e); return null; diff --git a/src/itdelatrisu/opsu/audio/MultiClip.java b/src/itdelatrisu/opsu/audio/MultiClip.java index 3193aac7..d314815f 100644 --- a/src/itdelatrisu/opsu/audio/MultiClip.java +++ b/src/itdelatrisu/opsu/audio/MultiClip.java @@ -1,6 +1,6 @@ package itdelatrisu.opsu.audio; -import itdelatrisu.opsu.ErrorHandler; +import yugecin.opsudance.core.errorhandling.ErrorHandler; import java.io.IOException; import java.util.Iterator; @@ -194,7 +194,7 @@ public class MultiClip { try { audioIn.close(); } catch (IOException e) { - ErrorHandler.error(String.format("Could not close AudioInputStream for MultiClip %s.", name), e, true); + ErrorHandler.error(String.format("Could not close AudioInputStream for MultiClip %s.", name), e).show(); } } } diff --git a/src/itdelatrisu/opsu/audio/MusicController.java b/src/itdelatrisu/opsu/audio/MusicController.java index ba4ec00a..e8c6a0ad 100644 --- a/src/itdelatrisu/opsu/audio/MusicController.java +++ b/src/itdelatrisu/opsu/audio/MusicController.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.audio; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.BeatmapParser; @@ -44,8 +43,12 @@ import org.newdawn.slick.MusicListener; import org.newdawn.slick.SlickException; import org.newdawn.slick.openal.Audio; 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.BubbleNotificationEvent; /** * Controller for all music. @@ -152,7 +155,9 @@ public class MusicController { }); playAt(position, loop); } catch (Exception e) { - ErrorHandler.error(String.format("Could not play track '%s'.", file.getName()), e, false); + String err = String.format("Could not play track '%s'.", file.getName()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } @@ -496,9 +501,7 @@ public class MusicController { trackLoader.interrupt(); try { trackLoader.join(); - } catch (InterruptedException e) { - ErrorHandler.error(null, e, true); - } + } catch (InterruptedException ignored) { } } trackLoader = null; @@ -575,7 +578,7 @@ public class MusicController { player = null; } catch (Exception e) { - ErrorHandler.error("Failed to destroy OpenAL.", e, true); + ErrorHandler.error("Failed to destroy OpenAL.", e).show(); } } diff --git a/src/itdelatrisu/opsu/audio/SoundController.java b/src/itdelatrisu/opsu/audio/SoundController.java index 7db7f608..10e8e850 100644 --- a/src/itdelatrisu/opsu/audio/SoundController.java +++ b/src/itdelatrisu/opsu/audio/SoundController.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.audio; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.audio.HitSound.SampleSet; import itdelatrisu.opsu.beatmap.HitObject; @@ -41,6 +40,9 @@ import javax.sound.sampled.LineUnavailableException; 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.BubbleNotificationEvent; /** * Controller for all (non-music) sound components. @@ -99,7 +101,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, true); + ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e).show(); return null; } } @@ -214,7 +216,7 @@ public class SoundController { // menu and game sounds for (SoundEffect s : SoundEffect.values()) { if ((currentFileName = getSoundFileName(s.getFileName())) == null) { - ErrorHandler.error(String.format("Could not find sound file '%s'.", s.getFileName()), null, false); + EventBus.instance.post(new BubbleNotificationEvent("Could not find sound file " + s.getFileName(), BubbleNotificationEvent.COLOR_ORANGE)); continue; } MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3")); @@ -233,7 +235,7 @@ public class SoundController { for (HitSound s : HitSound.values()) { String filename = String.format("%s-%s", ss.getName(), s.getFileName()); if ((currentFileName = getSoundFileName(filename)) == null) { - ErrorHandler.error(String.format("Could not find hit sound file '%s'.", filename), null, false); + EventBus.instance.post(new BubbleNotificationEvent("Could not find hit sound file " + filename, BubbleNotificationEvent.COLOR_ORANGE)); continue; } MultiClip newClip = loadClip(currentFileName, false); @@ -277,7 +279,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, true); + ErrorHandler.error(String.format("Could not start a clip '%s'.", clip.getName()), e).show(); } } } diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java index 3e3fa4f1..97e6442a 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapParser.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapParser.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.beatmap; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.db.BeatmapDB; @@ -35,6 +34,9 @@ import java.util.Map; 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.events.BubbleNotificationEvent; /** * Parser for beatmaps. @@ -243,9 +245,11 @@ public class BeatmapParser { } map.timingPoints.trimToSize(); } catch (IOException e) { - ErrorHandler.error(String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath()), e, false); + String err = String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } catch (NoSuchAlgorithmException e) { - ErrorHandler.error("Failed to get MD5 hash stream.", e, true); + ErrorHandler.error("Failed to get MD5 hash stream.", e).show(); // retry without MD5 hasNoMD5Algorithm = true; @@ -646,9 +650,11 @@ public class BeatmapParser { if (md5stream != null) beatmap.md5Hash = md5stream.getMD5(); } catch (IOException e) { - ErrorHandler.error(String.format("Failed to read file '%s'.", file.getAbsolutePath()), e, false); + String err = String.format("Failed to read file '%s'.", file.getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } catch (NoSuchAlgorithmException e) { - ErrorHandler.error("Failed to get MD5 hash stream.", e, true); + ErrorHandler.error("Failed to get MD5 hash stream.", e).show(); // retry without MD5 hasNoMD5Algorithm = true; @@ -727,7 +733,9 @@ public class BeatmapParser { } beatmap.timingPoints.trimToSize(); } catch (IOException e) { - ErrorHandler.error(String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()), e, false); + String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } @@ -803,9 +811,11 @@ 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), null, true); + objectIndex, beatmap.toString(), beatmap.objects.length), new Exception("no")).show(); } catch (IOException e) { - ErrorHandler.error(String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()), e, false); + String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java index dc9471ce..eda1338a 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapSetList.java @@ -18,11 +18,12 @@ package itdelatrisu.opsu.beatmap; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; 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 java.io.File; import java.io.IOException; @@ -215,7 +216,7 @@ public class BeatmapSetList { try { Utils.deleteToTrash(dir); } catch (IOException e) { - ErrorHandler.error("Could not delete song group.", e, true); + EventBus.instance.post(new BubbleNotificationEvent("Could not delete song group", BubbleNotificationEvent.COLOR_ORANGE)); } if (ws != null) ws.resume(); @@ -270,7 +271,7 @@ public class BeatmapSetList { try { Utils.deleteToTrash(file); } catch (IOException e) { - ErrorHandler.error("Could not delete song.", e, true); + EventBus.instance.post(new BubbleNotificationEvent("Could not delete song", BubbleNotificationEvent.COLOR_ORANGE)); } if (ws != null) ws.resume(); diff --git a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java index 8399cc22..f864c2ad 100644 --- a/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java +++ b/src/itdelatrisu/opsu/beatmap/BeatmapWatchService.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.beatmap; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import java.io.IOException; @@ -42,6 +41,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.events.EventBus; +import yugecin.opsudance.events.BubbleNotificationEvent; /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. @@ -96,7 +97,8 @@ public class BeatmapWatchService { ws = new BeatmapWatchService(); ws.register(Options.getBeatmapDir().toPath()); } catch (IOException e) { - ErrorHandler.error("An I/O exception occurred while creating the watch service.", e, true); + Log.error("Could not create watch service", e); + EventBus.instance.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED)); return; } @@ -117,8 +119,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.instance.post(new BubbleNotificationEvent("An I/O exception occurred while closing the previous watch service.", BubbleNotificationEvent.COMMONCOLOR_RED)); ws = null; - ErrorHandler.error("An I/O exception occurred while closing the previous watch service.", e, true); } } diff --git a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java index 5b9c1071..e1e40f41 100644 --- a/src/itdelatrisu/opsu/beatmap/OszUnpacker.java +++ b/src/itdelatrisu/opsu/beatmap/OszUnpacker.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.beatmap; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import java.io.File; @@ -28,6 +27,9 @@ import java.util.List; 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.events.BubbleNotificationEvent; /** * Unpacker for OSZ (ZIP) archives. @@ -97,8 +99,9 @@ public class OszUnpacker { ZipFile zipFile = new ZipFile(file); zipFile.extractAll(dest.getAbsolutePath()); } catch (ZipException e) { - ErrorHandler.error(String.format("Failed to unzip file %s to dest %s.", - file.getAbsolutePath(), dest.getAbsolutePath()), e, false); + String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } diff --git a/src/itdelatrisu/opsu/db/BeatmapDB.java b/src/itdelatrisu/opsu/db/BeatmapDB.java index 2dbb1e2f..e6e0e4d5 100644 --- a/src/itdelatrisu/opsu/db/BeatmapDB.java +++ b/src/itdelatrisu/opsu/db/BeatmapDB.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.db; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.BeatmapParser; @@ -35,6 +34,7 @@ import java.util.List; import java.util.Map; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Handles connections and queries with the cached beatmap database. @@ -110,7 +110,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, true); + ErrorHandler.error("Failed to prepare beatmap statements.", e).show(); } // retrieve the cache size @@ -132,7 +132,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, true); + ErrorHandler.error("Failed to prepare beatmap statements.", e).show(); } } @@ -170,7 +170,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("Could not create beatmap database.", e, true); + ErrorHandler.error("Coudl not create beatmap database.", e).show(); } } @@ -222,7 +222,7 @@ public class BeatmapDB { ps.close(); } } catch (SQLException e) { - ErrorHandler.error("Failed to update beatmap database.", e, true); + ErrorHandler.error("Failed to update beatmap database.", e).show(); } } @@ -240,7 +240,7 @@ public class BeatmapDB { } rs.close(); } catch (SQLException e) { - ErrorHandler.error("Could not get beatmap cache size.", e, true); + ErrorHandler.error("Could not get beatmap cache size.", e).show(); } } @@ -255,7 +255,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, true); + ErrorHandler.error("Could not update beatmap cache size.", e).show(); } } @@ -273,7 +273,7 @@ public class BeatmapDB { cacheSize = 0; updateCacheSize(); } catch (SQLException e) { - ErrorHandler.error("Could not drop beatmap database.", e, true); + ErrorHandler.error("Could not drop beatmap database.", e).show(); } createDatabase(); } @@ -291,7 +291,7 @@ public class BeatmapDB { cacheSize += insertStmt.executeUpdate(); updateCacheSize(); } catch (SQLException e) { - ErrorHandler.error("Failed to add beatmap to database.", e, true); + ErrorHandler.error("Failed to add beatmap to database.", e).show(); } } @@ -344,7 +344,7 @@ public class BeatmapDB { // update cache size updateCacheSize(); } catch (SQLException e) { - ErrorHandler.error("Failed to add beatmaps to database.", e, true); + ErrorHandler.error("Failed to add beatmaps to database.", e).show(); } } @@ -432,7 +432,7 @@ public class BeatmapDB { } rs.close(); } catch (SQLException e) { - ErrorHandler.error("Failed to load Beatmap from database.", e, true); + ErrorHandler.error("Failed to load Beatmap from database.", e).show(); } } @@ -495,7 +495,7 @@ public class BeatmapDB { } rs.close(); } catch (SQLException e) { - ErrorHandler.error("Failed to load beatmaps from database.", e, true); + ErrorHandler.error("Failed to load beatmaps from database.", e).show(); } } @@ -596,7 +596,7 @@ public class BeatmapDB { rs.close(); return map; } catch (SQLException e) { - ErrorHandler.error("Failed to get last modified map from database.", e, true); + ErrorHandler.error("Failed to get last modified map from database.", e).show(); return null; } } @@ -616,7 +616,7 @@ public class BeatmapDB { cacheSize -= deleteMapStmt.executeUpdate(); updateCacheSize(); } catch (SQLException e) { - ErrorHandler.error("Failed to delete beatmap entry from database.", e, true); + ErrorHandler.error("Failed to delete beatmap entry from database.", e).show(); } } @@ -633,7 +633,7 @@ public class BeatmapDB { cacheSize -= deleteGroupStmt.executeUpdate(); updateCacheSize(); } catch (SQLException e) { - ErrorHandler.error("Failed to delete beatmap group entry from database.", e, true); + ErrorHandler.error("Failed to delete beatmap group entry from database.", e).show(); } } @@ -652,7 +652,7 @@ public class BeatmapDB { 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, true); + beatmap.starRating, beatmap.toString()), e).show(); } } @@ -672,7 +672,7 @@ public class BeatmapDB { updatePlayStatsStmt.executeUpdate(); } catch (SQLException e) { ErrorHandler.error(String.format("Failed to update play statistics for beatmap '%s' in database.", - beatmap.toString()), e, true); + beatmap.toString()), e).show(); } } @@ -691,7 +691,7 @@ public class BeatmapDB { setFavoriteStmt.executeUpdate(); } catch (SQLException e) { ErrorHandler.error(String.format("Failed to update favorite status for beatmap '%s' in database.", - beatmap.toString()), e, true); + beatmap.toString()), e).show(); } } @@ -711,7 +711,7 @@ public class BeatmapDB { connection.close(); connection = null; } catch (SQLException e) { - ErrorHandler.error("Failed to close beatmap database.", e, true); + ErrorHandler.error("Failed to close beatmap database.", e).show(); } } } diff --git a/src/itdelatrisu/opsu/db/DBController.java b/src/itdelatrisu/opsu/db/DBController.java index aebd414b..61e0d5ca 100644 --- a/src/itdelatrisu/opsu/db/DBController.java +++ b/src/itdelatrisu/opsu/db/DBController.java @@ -18,7 +18,7 @@ package itdelatrisu.opsu.db; -import itdelatrisu.opsu.ErrorHandler; +import yugecin.opsudance.core.errorhandling.ErrorHandler; import java.sql.Connection; import java.sql.DriverManager; @@ -39,7 +39,7 @@ public class DBController { try { Class.forName("org.sqlite.JDBC"); } catch (ClassNotFoundException e) { - ErrorHandler.error("Could not load sqlite-JDBC driver.", e, true); + ErrorHandler.error("Could not load sqlite-JDBC driver.", e).show(); } // initialize the databases @@ -65,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, true); + ErrorHandler.error(String.format("Could not connect to database: '%s'.", path), e).show(); return null; } } diff --git a/src/itdelatrisu/opsu/db/ScoreDB.java b/src/itdelatrisu/opsu/db/ScoreDB.java index babf1841..6fa86910 100644 --- a/src/itdelatrisu/opsu/db/ScoreDB.java +++ b/src/itdelatrisu/opsu/db/ScoreDB.java @@ -18,10 +18,10 @@ package itdelatrisu.opsu.db; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.beatmap.Beatmap; +import yugecin.opsudance.core.errorhandling.ErrorHandler; import java.sql.Connection; import java.sql.PreparedStatement; @@ -124,7 +124,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, true); + ErrorHandler.error("Failed to prepare score statements.", e).show(); } } @@ -157,7 +157,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, true); + ErrorHandler.error("Could not create score database.", e).show(); } } @@ -209,7 +209,7 @@ public class ScoreDB { ps.close(); } } catch (SQLException e) { - ErrorHandler.error("Failed to update score database.", e, true); + ErrorHandler.error("Failed to update score database.", e).show(); } } @@ -227,7 +227,7 @@ public class ScoreDB { insertStmt.setString(19, data.playerName); insertStmt.executeUpdate(); } catch (SQLException e) { - ErrorHandler.error("Failed to save score to database.", e, true); + ErrorHandler.error("Failed to save score to database.", e).show(); } } @@ -247,7 +247,7 @@ public class ScoreDB { deleteScoreStmt.setString(21, data.playerName); deleteScoreStmt.executeUpdate(); } catch (SQLException e) { - ErrorHandler.error("Failed to delete score from database.", e, true); + ErrorHandler.error("Failed to delete score from database.", e).show(); } } @@ -267,7 +267,7 @@ public class ScoreDB { deleteSongStmt.setString(5, beatmap.version); deleteSongStmt.executeUpdate(); } catch (SQLException e) { - ErrorHandler.error("Failed to delete scores from database.", e, true); + ErrorHandler.error("Failed to delete scores from database.", e).show(); } } @@ -335,7 +335,7 @@ public class ScoreDB { } rs.close(); } catch (SQLException e) { - ErrorHandler.error("Failed to read scores from database.", e, true); + ErrorHandler.error("Failed to read scores from database.", e).show(); return null; } return getSortedArray(list); @@ -377,7 +377,7 @@ public class ScoreDB { map.put(version, getSortedArray(list)); rs.close(); } catch (SQLException e) { - ErrorHandler.error("Failed to read scores from database.", e, true); + ErrorHandler.error("Failed to read scores from database.", e).show(); return null; } return map; @@ -406,7 +406,7 @@ public class ScoreDB { connection.close(); connection = null; } catch (SQLException e) { - ErrorHandler.error("Failed to close score database.", e, true); + ErrorHandler.error("Failed to close score database.", e).show(); } } } diff --git a/src/itdelatrisu/opsu/downloads/Download.java b/src/itdelatrisu/opsu/downloads/Download.java index 58818490..218533d3 100644 --- a/src/itdelatrisu/opsu/downloads/Download.java +++ b/src/itdelatrisu/opsu/downloads/Download.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import java.io.File; @@ -35,6 +34,9 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.errorhandling.ErrorHandler; +import yugecin.opsudance.core.events.EventBus; +import yugecin.opsudance.events.BubbleNotificationEvent; /** * File download. @@ -142,7 +144,7 @@ public class Download { this.url = new URL(remoteURL); } catch (MalformedURLException e) { this.status = Status.ERROR; - ErrorHandler.error(String.format("Bad download URL: '%s'", remoteURL), e, true); + ErrorHandler.error(String.format("Bad download URL: '%s'", remoteURL), e).show(); return; } this.localPath = localPath; @@ -215,7 +217,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) { - ErrorHandler.error(error, null, false); + EventBus.instance.post(new BubbleNotificationEvent(error, BubbleNotificationEvent.COLOR_ORANGE)); throw new IOException(); } @@ -417,7 +419,7 @@ public class Download { } } catch (IOException e) { this.status = Status.ERROR; - ErrorHandler.error("Failed to cancel download.", e, true); + ErrorHandler.error("Failed to cancel download.", e).show(); } } } diff --git a/src/itdelatrisu/opsu/downloads/DownloadNode.java b/src/itdelatrisu/opsu/downloads/DownloadNode.java index 728dacf5..d8869fe4 100644 --- a/src/itdelatrisu/opsu/downloads/DownloadNode.java +++ b/src/itdelatrisu/opsu/downloads/DownloadNode.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; @@ -35,6 +34,8 @@ 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.events.BubbleNotificationEvent; /** * Node containing song data and a Download object. @@ -402,7 +403,7 @@ 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) { - ErrorHandler.error("Trying to draw download information for button without Download object.", null, false); + EventBus.instance.post(new BubbleNotificationEvent("Trying to draw download information for button without Download object", BubbleNotificationEvent.COLOR_ORANGE)); return; } diff --git a/src/itdelatrisu/opsu/downloads/Updater.java b/src/itdelatrisu/opsu/downloads/Updater.java index 307b8e54..fbd607ea 100644 --- a/src/itdelatrisu/opsu/downloads/Updater.java +++ b/src/itdelatrisu/opsu/downloads/Updater.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.Download.DownloadListener; @@ -38,6 +37,7 @@ 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; /** * Handles automatic program updates. @@ -298,7 +298,7 @@ public class Updater { pb.start(); } catch (IOException e) { status = Status.INTERNAL_ERROR; - ErrorHandler.error("Failed to start new process.", e, true); + ErrorHandler.error("Failed to start new process.", e).show(); } } } diff --git a/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java b/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java index 335982e9..d86a4579 100644 --- a/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/BloodcatServer.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads.servers; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.DownloadNode; @@ -34,6 +33,7 @@ import java.util.Date; import org.json.JSONArray; import org.json.JSONObject; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Download server: http://bloodcat.com/osu/ @@ -97,7 +97,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, true); + ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show(); } return nodes; } diff --git a/src/itdelatrisu/opsu/downloads/servers/HexideServer.java b/src/itdelatrisu/opsu/downloads/servers/HexideServer.java index e9b7c683..f0c6cb7d 100644 --- a/src/itdelatrisu/opsu/downloads/servers/HexideServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/HexideServer.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads.servers; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.DownloadNode; @@ -30,6 +29,7 @@ import java.net.URLEncoder; import org.json.JSONArray; import org.json.JSONObject; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Download server: https://osu.hexide.com/ @@ -128,7 +128,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, true); + ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show(); } return nodes; } diff --git a/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java b/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java index 1c72dff5..a2e298a4 100644 --- a/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/MengSkyServer.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads.servers; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.DownloadNode; @@ -30,6 +29,7 @@ import java.net.URLEncoder; import org.json.JSONArray; import org.json.JSONObject; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Download server: http://osu.mengsky.net/ @@ -101,7 +101,7 @@ public class MengSkyServer extends DownloadServer { resultCount = 1 + (pageTotal - 1) * PAGE_LIMIT; this.totalResults = resultCount; } catch (MalformedURLException | UnsupportedEncodingException e) { - ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e, true); + ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show(); } return nodes; } diff --git a/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java b/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java index 4341512a..e9c2e3c6 100644 --- a/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/MnetworkServer.java @@ -18,9 +18,9 @@ package itdelatrisu.opsu.downloads.servers; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.DownloadNode; +import yugecin.opsudance.core.errorhandling.ErrorHandler; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -120,7 +120,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, true); + ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show(); } return nodes; } diff --git a/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java b/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java index 834f2b9f..435eee2f 100644 --- a/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/OsuMirrorServer.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.downloads.servers; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.DownloadNode; @@ -36,6 +35,7 @@ import java.util.TimeZone; import org.json.JSONArray; import org.json.JSONObject; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Download server: http://loli.al/ @@ -123,7 +123,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, true); + ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show(); } return nodes; } diff --git a/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java b/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java index 3d25459a..9e13dc58 100644 --- a/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java +++ b/src/itdelatrisu/opsu/downloads/servers/YaSOnlineServer.java @@ -17,7 +17,6 @@ */ package itdelatrisu.opsu.downloads.servers; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.downloads.DownloadNode; @@ -34,6 +33,7 @@ import java.util.Iterator; import java.util.List; import org.json.JSONObject; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Download server: http://osu.yas-online.net/ @@ -114,7 +114,7 @@ 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, true); + ErrorHandler.error(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e).show(); return null; } finally { Utils.setSSLCertValidation(true); @@ -186,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, true); + ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show(); } finally { Utils.setSSLCertValidation(true); } diff --git a/src/itdelatrisu/opsu/render/CurveRenderState.java b/src/itdelatrisu/opsu/render/CurveRenderState.java index a70846b6..9ca3a33e 100644 --- a/src/itdelatrisu/opsu/render/CurveRenderState.java +++ b/src/itdelatrisu/opsu/render/CurveRenderState.java @@ -96,7 +96,7 @@ public class CurveRenderState { */ public static void shutdown() { staticState.shutdown(); - FrameBufferCache.shutdown(); + //FrameBufferCache.shutdown(); } /** diff --git a/src/itdelatrisu/opsu/render/FrameBufferCache.java b/src/itdelatrisu/opsu/render/FrameBufferCache.java index c27a80cb..bf1a96aa 100644 --- a/src/itdelatrisu/opsu/render/FrameBufferCache.java +++ b/src/itdelatrisu/opsu/render/FrameBufferCache.java @@ -128,6 +128,7 @@ public class FrameBufferCache { *

* This is necessary for cases when the game gets restarted with a * different resolution without closing the process. + * // TODO d do we still need this */ public static void shutdown() { FrameBufferCache fbcInstance = FrameBufferCache.getInstance(); diff --git a/src/itdelatrisu/opsu/replay/Replay.java b/src/itdelatrisu/opsu/replay/Replay.java index 6f2d9fb4..5ee6e271 100644 --- a/src/itdelatrisu/opsu/replay/Replay.java +++ b/src/itdelatrisu/opsu/replay/Replay.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.replay; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.ScoreData; import itdelatrisu.opsu.Utils; @@ -45,6 +44,9 @@ 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.events.BubbleNotificationEvent; /** * Captures osu! replay data. @@ -273,7 +275,7 @@ public class Replay { File dir = Options.getReplayDir(); if (!dir.isDirectory()) { if (!dir.mkdir()) { - ErrorHandler.error("Failed to create replay directory.", null, false); + EventBus.instance.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED)); return; } } @@ -343,7 +345,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, true); + ErrorHandler.error("LZMA compression failed (possible out-of-memory error).", e).show(); } compressedOut.close(); bout.close(); @@ -357,7 +359,7 @@ public class Replay { writer.close(); } catch (IOException e) { - ErrorHandler.error("Could not save replay data.", e, true); + ErrorHandler.error("Could not save replay data.", e).show(); } } }.start(); diff --git a/src/itdelatrisu/opsu/replay/ReplayImporter.java b/src/itdelatrisu/opsu/replay/ReplayImporter.java index 22e4a7dd..ee901143 100644 --- a/src/itdelatrisu/opsu/replay/ReplayImporter.java +++ b/src/itdelatrisu/opsu/replay/ReplayImporter.java @@ -18,7 +18,7 @@ package itdelatrisu.opsu.replay; -import itdelatrisu.opsu.ErrorHandler; +import com.sun.deploy.security.EnhancedJarVerifier; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.BeatmapSetList; @@ -31,6 +31,8 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.events.EventBus; +import yugecin.opsudance.events.BubbleNotificationEvent; /** * Importer for replay files. @@ -70,7 +72,9 @@ public class ReplayImporter { File replayDir = Options.getReplayDir(); if (!replayDir.isDirectory()) { if (!replayDir.mkdir()) { - ErrorHandler.error(String.format("Failed to create replay directory '%s'.", replayDir.getAbsolutePath()), null, false); + String err = String.format("Failed to create replay directory '%s'.", replayDir.getAbsolutePath()); + Log.error(err); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); return; } } @@ -83,7 +87,9 @@ public class ReplayImporter { r.loadHeader(); } catch (IOException e) { moveToFailedDirectory(file); - ErrorHandler.error(String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName()), e, false); + String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); continue; } Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash); @@ -100,8 +106,9 @@ public class ReplayImporter { } } else { moveToFailedDirectory(file); - ErrorHandler.error(String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName()), null, false); - continue; + String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName()); + Log.error(err); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } } diff --git a/src/itdelatrisu/opsu/skins/SkinLoader.java b/src/itdelatrisu/opsu/skins/SkinLoader.java index b7ac04ec..5c9be6e6 100644 --- a/src/itdelatrisu/opsu/skins/SkinLoader.java +++ b/src/itdelatrisu/opsu/skins/SkinLoader.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.skins; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Utils; @@ -32,6 +31,8 @@ import java.util.LinkedList; import org.newdawn.slick.Color; import org.newdawn.slick.util.Log; +import yugecin.opsudance.core.events.EventBus; +import yugecin.opsudance.events.BubbleNotificationEvent; /** * Loads skin configuration files. @@ -290,7 +291,9 @@ public class SkinLoader { } } } catch (IOException e) { - ErrorHandler.error(String.format("Failed to read file '%s'.", skinFile.getAbsolutePath()), e, false); + String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath()); + Log.error(err, e); + EventBus.instance.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED)); } return skin; diff --git a/src/itdelatrisu/opsu/states/DownloadsMenu.java b/src/itdelatrisu/opsu/states/DownloadsMenu.java index 718be4dd..83a31bf6 100644 --- a/src/itdelatrisu/opsu/states/DownloadsMenu.java +++ b/src/itdelatrisu/opsu/states/DownloadsMenu.java @@ -19,7 +19,6 @@ package itdelatrisu.opsu.states; import itdelatrisu.opsu.GameImage; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.audio.MusicController; diff --git a/src/itdelatrisu/opsu/states/MainMenu.java b/src/itdelatrisu/opsu/states/MainMenu.java index a56418fe..a099e037 100644 --- a/src/itdelatrisu/opsu/states/MainMenu.java +++ b/src/itdelatrisu/opsu/states/MainMenu.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.states; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; @@ -46,10 +45,13 @@ import org.newdawn.slick.Color; 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.DisplayContainer; +import yugecin.opsudance.core.events.EventBus; import yugecin.opsudance.core.inject.InstanceContainer; import yugecin.opsudance.core.state.BaseOpsuState; import yugecin.opsudance.core.state.OpsuState; +import yugecin.opsudance.events.BubbleNotificationEvent; /** * "Main Menu" state. @@ -570,7 +572,8 @@ public class MainMenu extends BaseOpsuState { } catch (UnsupportedOperationException e) { UI.sendBarNotification("The repository web page could not be opened."); } catch (IOException e) { - ErrorHandler.error("Could not browse to repository URI.", e, false); + Log.error("could not browse to repo", e); + displayContainer.eventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE)); } return true; } @@ -581,7 +584,8 @@ public class MainMenu extends BaseOpsuState { } catch (UnsupportedOperationException e) { UI.sendBarNotification("The repository web page could not be opened."); } catch (IOException e) { - ErrorHandler.error("Could not browse to repository URI.", e, false); + Log.error("could not browse to repo", e); + displayContainer.eventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE)); } return true; } diff --git a/src/itdelatrisu/opsu/ui/Cursor.java b/src/itdelatrisu/opsu/ui/Cursor.java index c3025ab7..1b7894c3 100644 --- a/src/itdelatrisu/opsu/ui/Cursor.java +++ b/src/itdelatrisu/opsu/ui/Cursor.java @@ -18,9 +18,7 @@ package itdelatrisu.opsu.ui; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; -import itdelatrisu.opsu.Opsu; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; import itdelatrisu.opsu.audio.MusicController; @@ -37,6 +35,7 @@ import org.newdawn.slick.*; import org.newdawn.slick.state.StateBasedGame; import yugecin.opsudance.Dancer; import yugecin.opsudance.core.DisplayContainer; +import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Updates and draws the cursor. @@ -91,7 +90,7 @@ public class Cursor { IntBuffer tmp = BufferUtils.createIntBuffer(min * min); emptyCursor = new org.lwjgl.input.Cursor(min, min, min/2, min/2, 1, tmp, null); } catch (LWJGLException e) { - ErrorHandler.error("Failed to create hidden cursor.", e, true); + ErrorHandler.error("Failed to create hidden cursor.", e).show(); } } diff --git a/src/itdelatrisu/opsu/ui/UI.java b/src/itdelatrisu/opsu/ui/UI.java index 1afed82e..8c5d5a10 100644 --- a/src/itdelatrisu/opsu/ui/UI.java +++ b/src/itdelatrisu/opsu/ui/UI.java @@ -18,7 +18,6 @@ package itdelatrisu.opsu.ui; -import itdelatrisu.opsu.ErrorHandler; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; @@ -455,19 +454,4 @@ public class UI { Colors.WHITE_ALPHA.a = oldAlphaW; } - /** - * Shows a confirmation dialog (used before exiting the game). - * @param message the message to display - * @return true if user selects "yes", false otherwise - */ - public static boolean showExitConfirmation(String message) { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception e) { - ErrorHandler.error("Could not set system look and feel for exit confirmation.", e, true); - } - int n = JOptionPane.showConfirmDialog(null, message, "Warning", - JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); - return (n != JOptionPane.YES_OPTION); - } } diff --git a/src/yugecin/opsudance/OpsuDance.java b/src/yugecin/opsudance/OpsuDance.java index 04b04054..2fa43c60 100644 --- a/src/yugecin/opsudance/OpsuDance.java +++ b/src/yugecin/opsudance/OpsuDance.java @@ -23,7 +23,6 @@ import itdelatrisu.opsu.beatmap.BeatmapWatchService; import itdelatrisu.opsu.db.DBController; import itdelatrisu.opsu.downloads.DownloadList; import itdelatrisu.opsu.downloads.Updater; -import itdelatrisu.opsu.render.CurveRenderState; import itdelatrisu.opsu.states.Splash; import org.newdawn.slick.util.Log; import yugecin.opsudance.core.DisplayContainer; @@ -78,7 +77,6 @@ public class OpsuDance { DBController.closeConnections(); DownloadList.get().cancelAllDownloads(); Utils.deleteDirectory(Options.TEMP_DIR); - CurveRenderState.shutdown(); if (!Options.isWatchServiceEnabled()) { BeatmapWatchService.destroy(); } @@ -89,7 +87,7 @@ public class OpsuDance { container.setup(); container.resume(); } catch (Exception e) { - ErrorHandler.error("could not initialize GL", e).preventContinue().show(); + ErrorHandler.error("could not initialize GL", e).allowTerminate().preventContinue().show(); return false; } Exception caughtException = null; @@ -100,7 +98,7 @@ public class OpsuDance { } container.teardown(); container.pause(); - return caughtException != null && ErrorHandler.error("update/render error", caughtException).show().shouldIgnoreAndContinue(); + return caughtException != null && ErrorHandler.error("update/render error", caughtException).allowTerminate().show().shouldIgnoreAndContinue(); } private void initDatabase() { @@ -174,7 +172,7 @@ public class OpsuDance { } private void errorAndExit(String errstr) { - ErrorHandler.error(errstr, new Throwable()).preventContinue().show(); + ErrorHandler.error(errstr, new Throwable()).allowTerminate().preventContinue().show(); System.exit(1); } diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 4385de56..4e7f6308 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -24,6 +24,7 @@ import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.downloads.DownloadList; import itdelatrisu.opsu.downloads.Updater; +import itdelatrisu.opsu.render.CurveRenderState; import itdelatrisu.opsu.ui.Fonts; import org.lwjgl.Sys; import org.lwjgl.openal.AL; @@ -222,6 +223,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen GameImage.destroyImages(); GameData.Grade.destroyImages(); Beatmap.destroyBackgroundImageCache(); + CurveRenderState.shutdown(); Display.destroy(); } diff --git a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java index 163a1940..99321ba4 100644 --- a/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java +++ b/src/yugecin/opsudance/core/errorhandling/ErrorHandler.java @@ -52,6 +52,7 @@ public class ErrorHandler { private boolean preventContinue; private boolean preventReport; private boolean ignoreAndContinue; + private boolean allowTerminate; public ErrorHandler(DisplayContainer displayContainer) { this.displayContainer = displayContainer; @@ -95,6 +96,11 @@ public class ErrorHandler { return this; } + public ErrorHandler allowTerminate() { + allowTerminate = true; + return this; + } + public ErrorHandler preventContinue() { preventContinue = true; return this; @@ -127,7 +133,9 @@ public class ErrorHandler { Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(), createReportButton() }; String[] buttons; - if (preventContinue) { + if (!allowTerminate && !preventContinue) { + buttons = new String[] { "Ignore & continue" }; + } else if (preventContinue) { buttons = new String[] { "Terminate" }; } else { buttons = new String[] { "Terminate", "Ignore & continue" }; @@ -145,7 +153,7 @@ public class ErrorHandler { null, buttons, buttons[buttons.length - 1]); - ignoreAndContinue = result == 1; + ignoreAndContinue = !allowTerminate || result == 1; frame.dispose(); return this; diff --git a/src/yugecin/opsudance/core/events/EventBus.java b/src/yugecin/opsudance/core/events/EventBus.java index 51f142a3..5bdf6c98 100644 --- a/src/yugecin/opsudance/core/events/EventBus.java +++ b/src/yugecin/opsudance/core/events/EventBus.java @@ -22,10 +22,14 @@ import java.util.*; @SuppressWarnings("unchecked") public class EventBus { + @Deprecated + public static EventBus instance; // TODO get rid of this + private final List subscribers; public EventBus() { subscribers = new LinkedList<>(); + instance = this; } public void subscribe(Class eventType, EventListener eventListener) { From 95a466f92f8bff8958c3831fccc4b96982bcf958 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sat, 21 Jan 2017 01:17:47 +0100 Subject: [PATCH 37/38] removing now unused classes --- src/itdelatrisu/opsu/Container.java | 184 ----- src/itdelatrisu/opsu/ErrorHandler.java | 242 ------ src/itdelatrisu/opsu/Opsu.java | 309 -------- src/org/newdawn/slick/GameContainer.java | 907 ----------------------- 4 files changed, 1642 deletions(-) delete mode 100644 src/itdelatrisu/opsu/Container.java delete mode 100644 src/itdelatrisu/opsu/ErrorHandler.java delete mode 100644 src/itdelatrisu/opsu/Opsu.java delete mode 100644 src/org/newdawn/slick/GameContainer.java diff --git a/src/itdelatrisu/opsu/Container.java b/src/itdelatrisu/opsu/Container.java deleted file mode 100644 index 63880381..00000000 --- a/src/itdelatrisu/opsu/Container.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * opsu! - an open-source osu! client - * Copyright (C) 2014, 2015 Jeffrey Han - * - * opsu! 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! 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!. If not, see . - */ - -package itdelatrisu.opsu; - -import itdelatrisu.opsu.audio.MusicController; -import itdelatrisu.opsu.audio.SoundController; -import itdelatrisu.opsu.beatmap.Beatmap; -import itdelatrisu.opsu.beatmap.BeatmapGroup; -import itdelatrisu.opsu.beatmap.BeatmapSetList; -import itdelatrisu.opsu.beatmap.BeatmapSortOrder; -import itdelatrisu.opsu.beatmap.BeatmapWatchService; -import itdelatrisu.opsu.downloads.DownloadList; -import itdelatrisu.opsu.downloads.Updater; -import itdelatrisu.opsu.render.CurveRenderState; -import itdelatrisu.opsu.ui.UI; - -import org.lwjgl.opengl.Display; -import org.newdawn.slick.AppGameContainer; -import org.newdawn.slick.Game; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.opengl.InternalTextureLoader; - -/** - * AppGameContainer extension that sends critical errors to ErrorHandler. - */ -public class Container extends AppGameContainer { - /** Exception causing game failure. */ - protected Exception e = null; - - public static Container instance; - - /** - * Create a new container wrapping a game - * - * @param game The game to be wrapped - * @throws SlickException Indicates a failure to initialise the display - */ - public Container(Game game) throws SlickException { - super(game); - instance = this; - } - - /** - * Create a new container wrapping a game - * - * @param game The game to be wrapped - * @param width The width of the display required - * @param height The height of the display required - * @param fullscreen True if we want fullscreen mode - * @throws SlickException Indicates a failure to initialise the display - */ - public Container(Game game, int width, int height, boolean fullscreen) throws SlickException { - super(game, width, height, fullscreen); - } - - @Override - public void start() throws SlickException { - try { - setup(); - ErrorHandler.setGlString(); - getDelta(); - while (running()) - gameLoop(); - } catch (Exception e) { - this.e = e; - } - - // destroy the game container - try { - close_sub(); - } catch (Exception e) { - if (this.e == null) // suppress if caused by a previous exception - this.e = e; - } - destroy(); - - // report any critical errors - if (e != null) { - ErrorHandler.error(null, e, true); - e = null; - forceExit = true; - } - - if (forceExit) { - Opsu.close(); - System.exit(0); - } - } - - @Override - protected void gameLoop() throws SlickException { - int delta = getDelta(); - if (!Display.isVisible() && updateOnlyOnVisible) { - try { Thread.sleep(100); } catch (Exception e) {} - } else { - try { - updateAndRender(delta); - } catch (SlickException e) { - this.e = e; // store exception to display later - running = false; - return; - } - } - updateFPS(); - Display.update(); - if (Display.isCloseRequested()) { - if (game.closeRequested()) - running = false; - } - } - - /** - * Actions to perform before destroying the game container. - */ - private void close_sub() { - // save user options - Options.saveOptions(); - - // reset cursor - UI.getCursor().reset(); - - // destroy images - InternalTextureLoader.get().clear(); - - // reset image references - GameImage.clearReferences(); - GameData.Grade.clearReferences(); - Beatmap.clearBackgroundImageCache(); - - // prevent loading tracks from re-initializing OpenAL - MusicController.reset(); - - // stop any playing track - SoundController.stopTrack(); - - // reset BeatmapSetList data - BeatmapGroup.set(BeatmapGroup.ALL); - BeatmapSortOrder.set(BeatmapSortOrder.TITLE); - if (BeatmapSetList.get() != null) - BeatmapSetList.get().reset(); - - // delete OpenGL objects involved in the Curve rendering - CurveRenderState.shutdown(); - - // destroy watch service - if (!Options.isWatchServiceEnabled()) - BeatmapWatchService.destroy(); - BeatmapWatchService.removeListeners(); - - // delete temporary directory - Utils.deleteDirectory(Options.TEMP_DIR); - } - - @Override - public void exit() { - // show confirmation dialog if any downloads are active - if (forceExit) { - if (DownloadList.get().hasActiveDownloads() && - UI.showExitConfirmation(DownloadList.EXIT_CONFIRMATION)) - return; - if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING && - UI.showExitConfirmation(Updater.EXIT_CONFIRMATION)) - return; - } - - super.exit(); - } -} diff --git a/src/itdelatrisu/opsu/ErrorHandler.java b/src/itdelatrisu/opsu/ErrorHandler.java deleted file mode 100644 index 1ccead20..00000000 --- a/src/itdelatrisu/opsu/ErrorHandler.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * opsu! - an open-source osu! client - * Copyright (C) 2014, 2015 Jeffrey Han - * - * opsu! 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! 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!. If not, see . - */ - -package itdelatrisu.opsu; - -import java.awt.Cursor; -import java.awt.Desktop; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URLEncoder; -import java.util.Properties; - -import javax.swing.JOptionPane; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.UIManager; - -import org.lwjgl.opengl.GL11; -import org.newdawn.slick.util.Log; -import org.newdawn.slick.util.ResourceLoader; - -/** - * Error handler to log and display errors. - */ -public class ErrorHandler { - /** Error popup title. */ - private static final String title = "Error"; - - /** Error popup description text. */ - private static final String - desc = "opsu! has encountered an error.", - descReport = "opsu! has encountered an error. Please report this!"; - - /** Error popup button options. */ - private static final String[] - optionsLog = {"View Error Log", "Close"}, - optionsReport = {"Send Report", "Close"}, - optionsLogReport = {"Send Report", "View Error Log", "Close"}; - - /** Text area for Exception. */ - private static final JTextArea textArea = new JTextArea(15, 100); - static { - textArea.setEditable(false); - textArea.setBackground(UIManager.getColor("Panel.background")); - textArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); - textArea.setTabSize(2); - textArea.setLineWrap(false); - textArea.setWrapStyleWord(true); - } - - /** Scroll pane holding JTextArea. */ - private static final JScrollPane scroll = new JScrollPane(textArea); - - /** Error popup objects. */ - private static final Object[] - message = { desc, scroll }, - messageReport = { descReport, scroll }; - - /** OpenGL string (if any). */ - private static String glString = null; - - // This class should not be instantiated. - private ErrorHandler() {} - - /** - * Sets the OpenGL version string. - */ - public static void setGlString() { - try { - String glVersion = GL11.glGetString(GL11.GL_VERSION); - String glVendor = GL11.glGetString(GL11.GL_VENDOR); - glString = String.format("%s (%s)", glVersion, glVendor); - } catch (Exception e) {} - } - - /** - * Displays an error popup and logs the given error. - * @param error a description of the error - * @param e the exception causing the error - * @param report whether to ask to report the error - */ - public static void error(String error, Throwable e, boolean report) { - if (error == null && e == null) - return; - - // log the error - if (error == null) - Log.error(e); - else if (e == null) - Log.error(error); - else - Log.error(error, e); - - // set the textArea to the error message - textArea.setText(null); - if (error != null) { - textArea.append(error); - textArea.append("\n"); - } - String trace = null; - if (e != null) { - StringWriter sw = new StringWriter(); - e.printStackTrace(new PrintWriter(sw)); - trace = sw.toString(); - textArea.append(trace); - } - - // display popup - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - Desktop desktop = null; - boolean isBrowseSupported = false, isOpenSupported = false; - if (Desktop.isDesktopSupported()) { - desktop = Desktop.getDesktop(); - isBrowseSupported = desktop.isSupported(Desktop.Action.BROWSE); - isOpenSupported = desktop.isSupported(Desktop.Action.OPEN); - } - if (desktop != null && (isOpenSupported || (report && isBrowseSupported))) { // try to open the log file and/or issues webpage - if (report && isBrowseSupported) { // ask to report the error - if (isOpenSupported) { // also ask to open the log - int n = JOptionPane.showOptionDialog(null, messageReport, title, - JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, - null, optionsLogReport, optionsLogReport[2]); - if (n == 0) - desktop.browse(getIssueURI(error, e, trace)); - else if (n == 1) - desktop.open(Options.LOG_FILE); - } else { // only ask to report the error - int n = JOptionPane.showOptionDialog(null, message, title, - JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, - null, optionsReport, optionsReport[1]); - if (n == 0) - desktop.browse(getIssueURI(error, e, trace)); - } - } else { // don't report the error - int n = JOptionPane.showOptionDialog(null, message, title, - JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, - null, optionsLog, optionsLog[1]); - if (n == 0) - desktop.open(Options.LOG_FILE); - } - } else { // display error only - JOptionPane.showMessageDialog(null, report ? messageReport : message, - title, JOptionPane.ERROR_MESSAGE); - } - } catch (Exception e1) { - Log.error("An error occurred in the crash popup.", e1); - } - } - - /** - * Returns the issue reporting URI. - * This will auto-fill the report with the relevant information if possible. - * @param error a description of the error - * @param e the exception causing the error - * @param trace the stack trace - * @return the created URI - */ - private static URI getIssueURI(String error, Throwable e, String trace) { - // generate report information - String issueTitle = (error != null) ? error : e.getMessage(); - StringBuilder sb = new StringBuilder(); - try { - // read version and build date from version file, if possible - Properties props = new Properties(); - props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE)); - String version = props.getProperty("version"); - if (version != null && !version.equals("${pom.version}")) { - sb.append("**Version:** "); - sb.append(version); - String hash = Utils.getGitHash(); - if (hash != null) { - sb.append(" ("); - sb.append(hash.substring(0, 12)); - sb.append(')'); - } - sb.append('\n'); - } - String timestamp = props.getProperty("build.date"); - if (timestamp != null && - !timestamp.equals("${maven.build.timestamp}") && !timestamp.equals("${timestamp}")) { - sb.append("**Build date:** "); - sb.append(timestamp); - sb.append('\n'); - } - } catch (IOException e1) { - Log.warn("Could not read version file.", e1); - } - sb.append("**OS:** "); - sb.append(System.getProperty("os.name")); - sb.append(" ("); - sb.append(System.getProperty("os.arch")); - sb.append(")\n"); - sb.append("**JRE:** "); - sb.append(System.getProperty("java.version")); - sb.append('\n'); - if (glString != null) { - sb.append("**OpenGL Version:** "); - sb.append(glString); - sb.append('\n'); - } - if (error != null) { - sb.append("**Error:** `"); - sb.append(error); - sb.append("`\n"); - } - if (trace != null) { - sb.append("**Stack trace:**"); - sb.append("\n```\n"); - sb.append(trace); - sb.append("```"); - } - - // return auto-filled URI - try { - return URI.create(String.format(Options.ISSUES_URL, - URLEncoder.encode(issueTitle, "UTF-8"), - URLEncoder.encode(sb.toString(), "UTF-8"))); - } catch (UnsupportedEncodingException e1) { - Log.warn("URLEncoder failed to encode the auto-filled issue report URL."); - return URI.create(String.format(Options.ISSUES_URL, "", "")); - } - } -} diff --git a/src/itdelatrisu/opsu/Opsu.java b/src/itdelatrisu/opsu/Opsu.java deleted file mode 100644 index b2c6d410..00000000 --- a/src/itdelatrisu/opsu/Opsu.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * opsu! - an open-source osu! client - * Copyright (C) 2014, 2015 Jeffrey Han - * - * opsu! 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! 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!. If not, see . - */ - -package itdelatrisu.opsu; - -import itdelatrisu.opsu.audio.MusicController; -import itdelatrisu.opsu.db.DBController; -import itdelatrisu.opsu.downloads.DownloadList; -import itdelatrisu.opsu.downloads.Updater; -import itdelatrisu.opsu.states.ButtonMenu; -import itdelatrisu.opsu.states.DownloadsMenu; -import itdelatrisu.opsu.states.Game; -import itdelatrisu.opsu.states.GamePauseMenu; -import itdelatrisu.opsu.states.GameRanking; -import itdelatrisu.opsu.states.MainMenu; -import itdelatrisu.opsu.states.OptionsMenu; -import itdelatrisu.opsu.states.SongMenu; -import itdelatrisu.opsu.states.Splash; -import itdelatrisu.opsu.ui.UI; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Field; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.UnknownHostException; - -import org.newdawn.slick.GameContainer; -import org.newdawn.slick.Input; -import org.newdawn.slick.SlickException; -import org.newdawn.slick.state.StateBasedGame; -import org.newdawn.slick.state.transition.FadeInTransition; -import org.newdawn.slick.state.transition.EasedFadeOutTransition; -import org.newdawn.slick.util.DefaultLogSystem; -import org.newdawn.slick.util.FileSystemLocation; -import org.newdawn.slick.util.Log; -import org.newdawn.slick.util.ResourceLoader; - -/** - * Main class. - *

- * Creates game container, adds all other states, and initializes song data. - */ -public class Opsu extends StateBasedGame { - /** Game states. */ - public static final int - STATE_SPLASH = 0, - STATE_MAINMENU = 1, - STATE_BUTTONMENU = 2, - STATE_SONGMENU = 3, - STATE_GAME = 4, - STATE_GAMEPAUSEMENU = 5, - STATE_GAMERANKING = 6, - STATE_OPTIONSMENU = 7, - STATE_DOWNLOADSMENU = 8; - - /** Server socket for restricting the program to a single instance. */ - private static ServerSocket SERVER_SOCKET; - - /** - * Constructor. - * @param name the program name - */ - public Opsu(String name) { - super(name); - } - - @Override - public void initStatesList(GameContainer container) throws SlickException { - //addState(new Splash(STATE_SPLASH)); - //addState(new MainMenu(STATE_MAINMENU)); - //addState(new ButtonMenu(STATE_BUTTONMENU)); - //addState(new SongMenu(STATE_SONGMENU)); - //addState(new Game(STATE_GAME)); - //addState(new GamePauseMenu(STATE_GAMEPAUSEMENU)); - //addState(new GameRanking(STATE_GAMERANKING)); - //addState(new OptionsMenu(STATE_OPTIONSMENU)); - //addState(new DownloadsMenu(STATE_DOWNLOADSMENU)); - } - - /** - * Launches opsu!. - */ - public static void main(String[] args) { - // log all errors to a file - Log.setVerbose(false); - try { - DefaultLogSystem.out = new PrintStream(new FileOutputStream(Options.LOG_FILE, true)); - } catch (FileNotFoundException e) { - Log.error(e); - } - - // set default exception handler - Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - ErrorHandler.error("** Uncaught Exception! **", e, true); - System.exit(1); - } - }); - - // parse configuration file - Options.parseOptions(); - - // only allow a single instance - if (!Options.noSingleInstance()) { - try { - SERVER_SOCKET = new ServerSocket(Options.getPort(), 1, InetAddress.getLocalHost()); - } catch (UnknownHostException e) { - // shouldn't happen - } catch (IOException e) { - errorAndExit( - null, - String.format( - "opsu! could not be launched for one of these reasons:\n" + - "- An instance of opsu! is already running.\n" + - "- Another program is bound to port %d. " + - "You can change the port opsu! uses by editing the \"Port\" field in the configuration file.", - Options.getPort() - ), - false - ); - } - } - - // load natives - File nativeDir; - if (!Utils.isJarRunning() && ( - (nativeDir = new File("./target/natives/")).isDirectory() || - (nativeDir = new File("./build/natives/")).isDirectory())) - ; - else { - nativeDir = Options.NATIVE_DIR; - try { - new NativeLoader(nativeDir).loadNatives(); - } catch (IOException e) { - Log.error("Error loading natives.", e); - } - } - 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); - } - - // set the resource paths - ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/"))); - - // initialize databases - try { - DBController.init(); - } catch (UnsatisfiedLinkError e) { - errorAndExit(e, "The databases could not be initialized.", true); - } - - // check if just updated - if (args.length >= 2) - Updater.get().setUpdateInfo(args[0], args[1]); - - // check for updates - if (!Options.isUpdaterDisabled()) { - new Thread() { - @Override - public void run() { - try { - Updater.get().checkForUpdates(); - } catch (IOException e) { - Log.warn("Check for updates failed.", e); - } - } - }.start(); - } - - // disable jinput - Input.disableControllers(); - - // start the game - try { - // loop until force exit - while (true) { - Opsu opsu = new Opsu("opsu!"); - Container app = new Container(opsu); - - // basic game settings - //Options.setDisplayMode(app); - String[] icons = { "icon16.png", "icon32.png" }; - try { - app.setIcons(icons); - } catch (Exception e) { - Log.error("could not set icon"); - } - app.setForceExit(true); - - app.start(); - - // run update if available - if (Updater.get().getStatus() == Updater.Status.UPDATE_FINAL) { - close(); - Updater.get().runUpdate(); - break; - } - } - } catch (SlickException e) { - errorAndExit(e, "An error occurred while creating the game container.", true); - } - } - - @Override - public boolean closeRequested() { - int id = this.getCurrentStateID(); - - // intercept close requests in game-related states and return to song menu - if (id == STATE_GAME || id == STATE_GAMEPAUSEMENU || id == STATE_GAMERANKING) { - // start playing track at preview position - SongMenu songMenu = (SongMenu) this.getState(Opsu.STATE_SONGMENU); - if (id == STATE_GAMERANKING) { - GameData data = ((GameRanking) this.getState(Opsu.STATE_GAMERANKING)).getGameData(); - if (data != null && data.isGameplay()) - songMenu.resetTrackOnLoad(); - } else { - if (id == STATE_GAME) { - MusicController.pause(); - MusicController.setPitch(1.0f); - MusicController.resume(); - } else - songMenu.resetTrackOnLoad(); - } - - // reset game data - if (UI.getCursor().isBeatmapSkinned()) - UI.getCursor().reset(); - songMenu.resetGameDataOnLoad(); - - this.enterState(Opsu.STATE_SONGMENU, new EasedFadeOutTransition(), new FadeInTransition()); - return false; - } - - // show confirmation dialog if any downloads are active - if (DownloadList.get().hasActiveDownloads() && - UI.showExitConfirmation(DownloadList.EXIT_CONFIRMATION)) - return false; - if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING && - UI.showExitConfirmation(Updater.EXIT_CONFIRMATION)) - return false; - - return true; - } - - /** - * Closes all resources. - */ - public static void close() { - // close databases - DBController.closeConnections(); - - // cancel all downloads - DownloadList.get().cancelAllDownloads(); - - // close server socket - if (SERVER_SOCKET != null) { - try { - SERVER_SOCKET.close(); - } catch (IOException e) { - ErrorHandler.error("Failed to close server socket.", e, false); - } - } - } - - /** - * Throws an error and exits the application with the given message. - * @param e the exception that caused the crash - * @param message the message to display - * @param report whether to ask to report the error - */ - private static void errorAndExit(Throwable e, String message, boolean report) { - // JARs will not run properly inside directories containing '!' - // http://bugs.java.com/view_bug.do?bug_id=4523159 - if (Utils.isJarRunning() && Utils.getRunningDirectory() != null && - Utils.getRunningDirectory().getAbsolutePath().indexOf('!') != -1) - ErrorHandler.error("JARs cannot be run from some paths containing '!'. Please move or rename the file and try again.", null, false); - else - ErrorHandler.error(message, e, report); - System.exit(1); - } -} diff --git a/src/org/newdawn/slick/GameContainer.java b/src/org/newdawn/slick/GameContainer.java deleted file mode 100644 index 01c7604f..00000000 --- a/src/org/newdawn/slick/GameContainer.java +++ /dev/null @@ -1,907 +0,0 @@ -/* - * Copyright (c) 2013, Slick2D - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of the Slick2D nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -package org.newdawn.slick; - -import java.io.IOException; -import java.util.Properties; - -import org.lwjgl.LWJGLException; -import org.lwjgl.Sys; -import org.lwjgl.input.Cursor; -import org.lwjgl.opengl.Display; -import org.lwjgl.opengl.Drawable; -import org.lwjgl.opengl.Pbuffer; -import org.lwjgl.opengl.PixelFormat; -import org.newdawn.slick.gui.GUIContext; -import org.newdawn.slick.openal.SoundStore; -import org.newdawn.slick.opengl.CursorLoader; -import org.newdawn.slick.opengl.ImageData; -import org.newdawn.slick.opengl.renderer.Renderer; -import org.newdawn.slick.opengl.renderer.SGL; -import org.newdawn.slick.util.Log; -import org.newdawn.slick.util.ResourceLoader; - -/** - * A generic game container that handles the game loop, fps recording and - * managing the input system - * - * @author kevin - */ -public abstract class GameContainer implements GUIContext { - /** The renderer to use for all GL operations */ - protected static SGL GL = Renderer.get(); - /** The shared drawable if any */ - protected static Drawable SHARED_DRAWABLE; - - /** The time the last frame was rendered */ - protected long lastFrame; - /** The last time the FPS recorded */ - protected long lastFPS; - /** The last recorded FPS */ - protected int recordedFPS; - /** The current count of FPS */ - protected int fps; - /** True if we're currently running the game loop */ - protected boolean running = true; - - /** The width of the display */ - protected int width; - /** The height of the display */ - protected int height; - /** The game being managed */ - protected Game game; - - /** The default font to use in the graphics context */ - private Font defaultFont; - /** The graphics context to be passed to the game */ - private Graphics graphics; - - /** The input system to pass to the game */ - protected Input input; - /** The FPS we want to lock to */ - protected int targetFPS = -1; - /** True if we should show the fps */ - private boolean showFPS = true; - /** The minimum logic update interval */ - protected long minimumLogicInterval = 1; - /** The stored delta */ - protected long storedDelta; - /** The maximum logic update interval */ - protected long maximumLogicInterval = 0; - /** The last game started */ - protected Game lastGame; - /** True if we should clear the screen each frame */ - protected boolean clearEachFrame = true; - - /** True if the game is paused */ - protected boolean paused; - /** True if we should force exit */ - protected boolean forceExit = true; - /** True if vsync has been requested */ - protected boolean vsync; - /** Smoothed deltas requested */ - protected boolean smoothDeltas; - /** The number of samples we'll attempt through hardware */ - protected int samples; - - /** True if this context supports multisample */ - protected boolean supportsMultiSample; - - /** True if we should render when not focused */ - protected boolean alwaysRender; - /** True if we require stencil bits */ - protected static boolean stencil; - - /** - * Create a new game container wrapping a given game - * - * @param game The game to be wrapped - */ - protected GameContainer(Game game) { - this.game = game; - lastFrame = getTime(); - - getBuildVersion(); - Log.checkVerboseLogSetting(); - } - - public static void enableStencil() { - stencil = true; - } - - /** - * Set the default font that will be intialised in the graphics held in this container - * - * @param font The font to use as default - */ - public void setDefaultFont(Font font) { - if (font != null) { - this.defaultFont = font; - } else { - Log.warn("Please provide a non null font"); - } - } - - /** - * Indicate whether we want to try to use fullscreen multisampling. This will - * give antialiasing across the whole scene using a hardware feature. - * - * @param samples The number of samples to attempt (2 is safe) - */ - public void setMultiSample(int samples) { - this.samples = samples; - } - - /** - * Check if this hardware can support multi-sampling - * - * @return True if the hardware supports multi-sampling - */ - public boolean supportsMultiSample() { - return supportsMultiSample; - } - - /** - * The number of samples we're attempting to performing using - * hardware multisampling - * - * @return The number of samples requested - */ - public int getSamples() { - return samples; - } - - /** - * Indicate if we should force exitting the VM at the end - * of the game (default = true) - * - * @param forceExit True if we should force the VM exit - */ - public void setForceExit(boolean forceExit) { - this.forceExit = forceExit; - } - - /** - * Indicate if we want to smooth deltas. This feature will report - * a delta based on the FPS not the time passed. This works well with - * vsync. - * - * @param smoothDeltas True if we should report smooth deltas - */ - public void setSmoothDeltas(boolean smoothDeltas) { - this.smoothDeltas = smoothDeltas; - } - - /** - * Check if the display is in fullscreen mode - * - * @return True if the display is in fullscreen mode - */ - public boolean isFullscreen() { - return false; - } - - /** - * Get the aspect ratio of the screen - * - * @return The aspect ratio of the display - */ - public float getAspectRatio() { - return getWidth() / getHeight(); - } - - /** - * Indicate whether we want to be in fullscreen mode. Note that the current - * display mode must be valid as a fullscreen mode for this to work - * - * @param fullscreen True if we want to be in fullscreen mode - * @throws SlickException Indicates we failed to change the display mode - */ - public void setFullscreen(boolean fullscreen) throws SlickException { - } - - /** - * Enable shared OpenGL context. After calling this all containers created - * will shared a single parent context - * - * @throws SlickException Indicates a failure to create the shared drawable - */ - public static void enableSharedContext() throws SlickException { - try { - SHARED_DRAWABLE = new Pbuffer(64, 64, new PixelFormat(8, 0, 0), null); - } catch (LWJGLException e) { - throw new SlickException("Unable to create the pbuffer used for shard context, buffers not supported", e); - } - } - - /** - * Get the context shared by all containers - * - * @return The context shared by all the containers or null if shared context isn't enabled - */ - public static Drawable getSharedContext() { - return SHARED_DRAWABLE; - } - - /** - * Indicate if we should clear the screen at the beginning of each frame. If you're - * rendering to the whole screen each frame then setting this to false can give - * some performance improvements - * - * @param clear True if the the screen should be cleared each frame - */ - public void setClearEachFrame(boolean clear) { - this.clearEachFrame = clear; - } - - /** - * Renitialise the game and the context in which it's being rendered - * - * @throws SlickException Indicates a failure rerun initialisation routines - */ - public void reinit() throws SlickException { - } - - /** - * Pause the game - i.e. suspend updates - */ - public void pause() - { - setPaused(true); - } - - /** - * Resumt the game - i.e. continue updates - */ - public void resume() - { - setPaused(false); - } - - /** - * Check if the container is currently paused. - * - * @return True if the container is paused - */ - public boolean isPaused() { - return paused; - } - - /** - * Indicates if the game should be paused, i.e. if updates - * should be propogated through to the game. - * - * @param paused True if the game should be paused - */ - public void setPaused(boolean paused) - { - this.paused = paused; - } - - /** - * True if this container should render when it has focus - * - * @return True if this container should render when it has focus - */ - public boolean getAlwaysRender () { - return alwaysRender; - } - - /** - * Indicate whether we want this container to render when it has focus - * - * @param alwaysRender True if this container should render when it has focus - */ - public void setAlwaysRender (boolean alwaysRender) { - this.alwaysRender = alwaysRender; - } - - /** - * Get the build number of slick - * - * @return The build number of slick - */ - public static int getBuildVersion() { - try { - Properties props = new Properties(); - props.load(ResourceLoader.getResourceAsStream("version")); - - int build = Integer.parseInt(props.getProperty("build")); - Log.info("Slick Build #"+build); - - return build; - } catch (Exception e) { - Log.info("Unable to determine Slick build number"); - return -1; - } - } - - /** - * Get the default system font - * - * @return The default system font - */ - @Override - public Font getDefaultFont() { - return defaultFont; - } - - /** - * Check if sound effects are enabled - * - * @return True if sound effects are enabled - */ - public boolean isSoundOn() { - return SoundStore.get().soundsOn(); - } - - /** - * Check if music is enabled - * - * @return True if music is enabled - */ - public boolean isMusicOn() { - return SoundStore.get().musicOn(); - } - - /** - * Indicate whether music should be enabled - * - * @param on True if music should be enabled - */ - public void setMusicOn(boolean on) { - SoundStore.get().setMusicOn(on); - } - - /** - * Indicate whether sound effects should be enabled - * - * @param on True if sound effects should be enabled - */ - public void setSoundOn(boolean on) { - SoundStore.get().setSoundsOn(on); - } - - /** - * Retrieve the current default volume for music - * @return the current default volume for music - */ - public float getMusicVolume() { - return SoundStore.get().getMusicVolume(); - } - - /** - * Retrieve the current default volume for sound fx - * @return the current default volume for sound fx - */ - public float getSoundVolume() { - return SoundStore.get().getSoundVolume(); - } - - /** - * Set the default volume for sound fx - * @param volume the new default value for sound fx volume - */ - public void setSoundVolume(float volume) { - SoundStore.get().setSoundVolume(volume); - } - - /** - * Set the default volume for music - * @param volume the new default value for music volume - */ - public void setMusicVolume(float volume) { - SoundStore.get().setMusicVolume(volume); - } - - /** - * Get the width of the standard screen resolution - * - * @return The screen width - */ - @Override - public abstract int getScreenWidth(); - - /** - * Get the height of the standard screen resolution - * - * @return The screen height - */ - @Override - public abstract int getScreenHeight(); - - /** - * Get the width of the game canvas - * - * @return The width of the game canvas - */ - @Override - public int getWidth() { - return width; - } - - /** - * Get the height of the game canvas - * - * @return The height of the game canvas - */ - @Override - public int getHeight() { - return height; - } - - /** - * Set the icon to be displayed if possible in this type of - * container - * - * @param ref The reference to the icon to be displayed - * @throws SlickException Indicates a failure to load the icon - */ - public abstract void setIcon(String ref) throws SlickException; - - /** - * Set the icons to be used for this application. Note that the size of the icon - * defines how it will be used. Important ones to note - * - * Windows window icon must be 16x16 - * Windows alt-tab icon must be 24x24 or 32x32 depending on Windows version (XP=32) - * - * @param refs The reference to the icon to be displayed - * @throws SlickException Indicates a failure to load the icon - */ - public abstract void setIcons(String[] refs) throws SlickException; - - /** - * Get the accurate system time - * - * @return The system time in milliseconds - */ - @Override - public long getTime() { - return (Sys.getTime() * 1000) / Sys.getTimerResolution(); - } - - /** - * Sleep for a given period - * - * @param milliseconds The period to sleep for in milliseconds - */ - public void sleep(int milliseconds) { - long target = getTime()+milliseconds; - while (getTime() < target) { - try { Thread.sleep(1); } catch (Exception e) {} - } - } - - /** - * Set the mouse cursor to be displayed - this is a hardware cursor and hence - * shouldn't have any impact on FPS. - * - * @param ref The location of the image to be loaded for the cursor - * @param hotSpotX The x coordinate of the hotspot within the cursor image - * @param hotSpotY The y coordinate of the hotspot within the cursor image - * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor - */ - @Override - public abstract void setMouseCursor(String ref, int hotSpotX, int hotSpotY) throws SlickException; - - /** - * Set the mouse cursor to be displayed - this is a hardware cursor and hence - * shouldn't have any impact on FPS. - * - * @param data The image data from which the cursor can be construted - * @param hotSpotX The x coordinate of the hotspot within the cursor image - * @param hotSpotY The y coordinate of the hotspot within the cursor image - * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor - */ - @Override - public abstract void setMouseCursor(ImageData data, int hotSpotX, int hotSpotY) throws SlickException; - - /** - * Set the mouse cursor based on the contents of the image. Note that this will not take - * account of render state type changes to images (rotation and such). If these effects - * are required it is recommended that an offscreen buffer be used to produce an appropriate - * image. An offscreen buffer will always be used to produce the new cursor and as such - * this operation an be very expensive - * - * @param image The image to use as the cursor - * @param hotSpotX The x coordinate of the hotspot within the cursor image - * @param hotSpotY The y coordinate of the hotspot within the cursor image - * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor - */ - public abstract void setMouseCursor(Image image, int hotSpotX, int hotSpotY) throws SlickException; - - /** - * Set the mouse cursor to be displayed - this is a hardware cursor and hence - * shouldn't have any impact on FPS. - * - * @param cursor The cursor to use - * @param hotSpotX The x coordinate of the hotspot within the cursor image - * @param hotSpotY The y coordinate of the hotspot within the cursor image - * @throws SlickException Indicates a failure to load the cursor image or create the hardware cursor - */ - @Override - public abstract void setMouseCursor(Cursor cursor, int hotSpotX, int hotSpotY) throws SlickException; - - /** - * Get a cursor based on a image reference on the classpath. The image - * is assumed to be a set/strip of cursor animation frames running from top to - * bottom. - * - * @param ref The reference to the image to be loaded - * @param x The x-coordinate of the cursor hotspot (left {@literal ->} right) - * @param y The y-coordinate of the cursor hotspot (bottom {@literal ->} top) - * @param width The x width of the cursor - * @param height The y height of the cursor - * @param cursorDelays image delays between changing frames in animation - * - * @throws SlickException Indicates a failure to load the image or a failure to create the hardware cursor - */ - public void setAnimatedMouseCursor(String ref, int x, int y, int width, int height, int[] cursorDelays) throws SlickException - { - try { - Cursor cursor; - cursor = CursorLoader.get().getAnimatedCursor(ref, x, y, width, height, cursorDelays); - setMouseCursor(cursor, x, y); - } catch (IOException e) { - throw new SlickException("Failed to set mouse cursor", e); - } catch (LWJGLException e) { - throw new SlickException("Failed to set mouse cursor", e); - } - } - - /** - * Set the default mouse cursor - i.e. the original cursor before any native - * cursor was set - */ - @Override - public abstract void setDefaultMouseCursor(); - - /** - * Get the input system - * - * @return The input system available to this game container - */ - @Override - public Input getInput() { - return input; - } - - /** - * Get the current recorded FPS (frames per second) - * - * @return The current FPS - */ - public int getFPS() { - return recordedFPS; - } - - /** - * Indicate whether mouse cursor should be grabbed or not - * - * @param grabbed True if mouse cursor should be grabbed - */ - public abstract void setMouseGrabbed(boolean grabbed); - - /** - * Check if the mouse cursor is current grabbed. This will cause it not - * to be seen. - * - * @return True if the mouse is currently grabbed - */ - public abstract boolean isMouseGrabbed(); - - /** - * Retrieve the time taken to render the last frame, i.e. the change in time - delta. - * - * @return The time taken to render the last frame - */ - protected int getDelta() { - long time = getTime(); - int delta = (int) (time - lastFrame); - lastFrame = time; - - return delta; - } - - /** - * Updated the FPS counter - */ - protected void updateFPS() { - if (getTime() - lastFPS > 1000) { - lastFPS = getTime(); - recordedFPS = fps; - fps = 0; - } - fps++; - } - - /** - * Set the minimum amount of time in milliseonds that has to - * pass before update() is called on the container game. This gives - * a way to limit logic updates compared to renders. - * - * @param interval The minimum interval between logic updates - */ - public void setMinimumLogicUpdateInterval(int interval) { - minimumLogicInterval = interval; - } - - /** - * Set the maximum amount of time in milliseconds that can passed - * into the update method. Useful for collision detection without - * sweeping. - * - * @param interval The maximum interval between logic updates - */ - public void setMaximumLogicUpdateInterval(int interval) { - maximumLogicInterval = interval; - } - - /** - * Update and render the game - * - * @param delta The change in time since last update and render - * @throws SlickException Indicates an internal fault to the game. - */ - protected void updateAndRender(int delta) throws SlickException { - if (smoothDeltas) { - if (getFPS() != 0) { - delta = 1000 / getFPS(); - } - } - - input.poll(width, height); - - Music.poll(delta); - if (!paused) { - storedDelta += delta; - - if (storedDelta >= minimumLogicInterval) { - try { - if (maximumLogicInterval != 0) { - long cycles = storedDelta / maximumLogicInterval; - for (int i=0;i minimumLogicInterval) { - game.update(this, (int) (remainder % maximumLogicInterval)); - storedDelta = 0; - } else { - storedDelta = remainder; - } - } else { - game.update(this, (int) storedDelta); - storedDelta = 0; - } - - } catch (Throwable e) { -// Log.error(e); - throw new SlickException("Game.update() failure.", e); - } - } - } else { - game.update(this, 0); - } - - if (hasFocus() || getAlwaysRender()) { - if (clearEachFrame) { - GL.glClear(SGL.GL_COLOR_BUFFER_BIT | SGL.GL_DEPTH_BUFFER_BIT); - } - - GL.glLoadIdentity(); - - graphics.resetTransform(); - graphics.resetFont(); - graphics.resetLineWidth(); - graphics.setAntiAlias(false); - try { - game.render(this, graphics); - } catch (Throwable e) { -// Log.error(e); - throw new SlickException("Game.render() failure.", e); - } - graphics.resetTransform(); - - if (showFPS) { - defaultFont.drawString(10, 10, "FPS: "+recordedFPS); - } - - GL.flush(); - } - - if (targetFPS != -1) { - Display.sync(targetFPS); - } - } - - /** - * Indicate if the display should update only when the game is visible - * (the default is true) - * - * @param updateOnlyWhenVisible True if we should updated only when the display is visible - */ - public void setUpdateOnlyWhenVisible(boolean updateOnlyWhenVisible) { - } - - /** - * Check if this game is only updating when visible to the user (default = true) - * - * @return True if the game is only updated when the display is visible - */ - public boolean isUpdatingOnlyWhenVisible() { - return true; - } - - /** - * Initialise the GL context - */ - protected void initGL() { - Log.info("Starting display "+width+"x"+height); - GL.initDisplay(width, height); - - if (input == null) { - input = new Input(height); - } - input.init(height); - // no need to remove listeners? - //input.removeAllListeners(); - if (game instanceof InputListener) { - input.removeListener((InputListener) game); - input.addListener((InputListener) game); - } - - if (graphics != null) { - graphics.setDimensions(getWidth(), getHeight()); - } - lastGame = game; - } - - /** - * Initialise the system components, OpenGL and OpenAL. - * - * @throws SlickException Indicates a failure to create a native handler - */ - protected void initSystem() throws SlickException { - initGL(); - setMusicVolume(1.0f); - setSoundVolume(1.0f); - - graphics = new Graphics(width, height); - defaultFont = graphics.getFont(); - } - - /** - * Enter the orthographic mode - */ - protected void enterOrtho() { - enterOrtho(width, height); - } - - /** - * Indicate whether the container should show the FPS - * - * @param show True if the container should show the FPS - */ - public void setShowFPS(boolean show) { - showFPS = show; - } - - /** - * Check if the FPS is currently showing - * - * @return True if the FPS is showing - */ - public boolean isShowingFPS() { - return showFPS; - } - - /** - * Set the target fps we're hoping to get - * - * @param fps The target fps we're hoping to get - */ - public void setTargetFrameRate(int fps) { - targetFPS = fps; - } - - /** - * Indicate whether the display should be synced to the - * vertical refresh (stops tearing) - * - * @param vsync True if we want to sync to vertical refresh - */ - public void setVSync(boolean vsync) { - this.vsync = vsync; - Display.setVSyncEnabled(vsync); - } - - /** - * True if vsync is requested - * - * @return True if vsync is requested - */ - public boolean isVSyncRequested() { - return vsync; - } - - /** - * True if the game is running - * - * @return True if the game is running - */ - protected boolean running() { - return running; - } - - /** - * Inidcate we want verbose logging - * - * @param verbose True if we want verbose logging (INFO and DEBUG) - */ - public void setVerbose(boolean verbose) { - Log.setVerbose(verbose); - } - - /** - * Cause the game to exit and shutdown cleanly - */ - public void exit() { - running = false; - } - - /** - * Check if the game currently has focus - * - * @return True if the game currently has focus - */ - public abstract boolean hasFocus(); - - /** - * Get the graphics context used by this container. Note that this - * value may vary over the life time of the game. - * - * @return The graphics context used by this container - */ - public Graphics getGraphics() { - return graphics; - } - - /** - * Enter the orthographic mode - * - * @param xsize The size of the panel being used - * @param ysize The size of the panel being used - */ - protected void enterOrtho(int xsize, int ysize) { - GL.enterOrtho(xsize, ysize); - } -} From 978a41116c7a10edf267e4e7d6c525f19bbf5fb2 Mon Sep 17 00:00:00 2001 From: yugecin Date: Sat, 21 Jan 2017 13:11:34 +0100 Subject: [PATCH 38/38] enable cursor --- src/itdelatrisu/opsu/Options.java | 7 +- src/itdelatrisu/opsu/states/Game.java | 130 ++++++++++-------- .../opsu/states/GamePauseMenu.java | 8 +- src/itdelatrisu/opsu/states/GameRanking.java | 5 +- src/itdelatrisu/opsu/ui/Cursor.java | 99 ++----------- src/itdelatrisu/opsu/ui/UI.java | 35 ----- .../opsudance/core/DisplayContainer.java | 22 +++ .../core/inject/OpsuDanceInjector.java | 2 +- src/yugecin/opsudance/utils/GLHelper.java | 23 ++++ 9 files changed, 142 insertions(+), 189 deletions(-) diff --git a/src/itdelatrisu/opsu/Options.java b/src/itdelatrisu/opsu/Options.java index e095c5d2..553c54cb 100644 --- a/src/itdelatrisu/opsu/Options.java +++ b/src/itdelatrisu/opsu/Options.java @@ -467,12 +467,7 @@ public class Options { val = i; } }, - NEW_CURSOR ("Enable New Cursor", "NewCursor", "Use the new cursor style (may cause higher CPU usage).", true) { - @Override - public void click() { - UI.getCursor().reset(); - } - }, + NEW_CURSOR ("Enable New Cursor", "NewCursor", "Use the new cursor style (may cause higher CPU usage).", true), DYNAMIC_BACKGROUND ("Enable Dynamic Backgrounds", "DynamicBackground", "The song background will be used as the main menu background.", true), LOAD_VERBOSE ("Show Detailed Loading Progress", "LoadVerbose", "Display more specific loading information in the splash screen.", false), COLOR_MAIN_MENU_LOGO ("Use cursor color as main menu logo tint", "ColorMainMenuLogo", "Colorful main menu logo", false), diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 53200135..1cfc90c8 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -73,6 +73,7 @@ import yugecin.opsudance.objects.curves.FakeCombinedCurve; import yugecin.opsudance.sbv2.MoveStoryboard; import yugecin.opsudance.ui.OptionsOverlay; import yugecin.opsudance.ui.StoryboardOverlay; +import yugecin.opsudance.utils.GLHelper; /** * "Game" state. @@ -449,38 +450,6 @@ public class Game extends ComplexOpsuState { if (GameMod.FLASHLIGHT.isActive()) Graphics.setCurrent(g); - // "auto" and "autopilot" mods: move cursor automatically - // TODO: this should really be in update(), not render() - autoMousePosition.set(width / 2, height / 2); - autoMousePressed = false; - if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { - Vec2f autoPoint; - if (objectIndex < beatmap.objects.length - Dancer.instance.getPolyMoverFactoryMinBufferSize()) { - Dancer d = Dancer.instance; - d.update(trackPosition, objectIndex); - autoPoint = new Vec2f(d.x, d.y); - if (trackPosition < gameObjects[objectIndex].getTime()) { - autoMousePressed = true; - } - } else { - if (objectIndex < beatmap.objects.length) { - autoPoint = gameObjects[objectIndex].getPointAt(trackPosition); - } else { - // last object - autoPoint = gameObjects[objectIndex - 1].getPointAt(trackPosition); - } - } - - float[] sbPosition = moveStoryboardOverlay.getPoint(trackPosition); - if (sbPosition != null) { - autoPoint.x = sbPosition[0]; - autoPoint.y = sbPosition[1]; - } - - // set mouse coordinates - autoMousePosition.set(autoPoint.x, autoPoint.y); - } - // "flashlight" mod: restricted view of hit objects around cursor if (GameMod.FLASHLIGHT.isActive()) { // render hit objects offscreen @@ -748,22 +717,18 @@ public class Game extends ComplexOpsuState { cursorCirclePulse.drawCentered(pausedMousePosition.x, pausedMousePosition.y); } - if (isReplay) - UI.draw(g, replayX, replayY, replayKeyPressed); - else if (GameMod.AUTO.isActive()) { - UI.draw(g, (int) autoMousePosition.x, (int) autoMousePosition.y, autoMousePressed); + if (isReplay) { + displayContainer.cursor.draw(replayKeyPressed); + } else if (GameMod.AUTO.isActive()) { + displayContainer.cursor.draw(autoMousePressed); if (Options.isMirror() && GameMod.AUTO.isActive()) { - double dx = autoMousePosition.x - Options.width / 2d; - double dy = autoMousePosition.y - Options.height / 2d; - double d = Math.sqrt(dx * dx + dy * dy); - double a = Math.atan2(dy, dx) + Math.PI; - mirrorCursor.draw((int) (Math.cos(a) * d + Options.width / 2), (int) (Math.sin(a) * d + Options.height / 2), autoMousePressed); + mirrorCursor.draw(autoMousePressed); } + } else if (GameMod.AUTOPILOT.isActive()) { + displayContainer.cursor.draw(Utils.isGameKeyPressed()); } - else if (GameMod.AUTOPILOT.isActive()) - UI.draw(g, (int) autoMousePosition.x, (int) autoMousePosition.y, Utils.isGameKeyPressed()); - else - UI.draw(g); + + UI.draw(g); if (!Options.isHideWM()) { Fonts.SMALL.drawString(0.3f, 0.3f, "opsu!dance " + Updater.get().getCurrentVersion() + " by robin_be | https://github.com/yugecin/opsu-dance"); @@ -926,6 +891,58 @@ public class Game extends ComplexOpsuState { } } + @Override + public void update() { + super.update(); + + int trackPosition = MusicController.getPosition(); + + // "auto" and "autopilot" mods: move cursor automatically + autoMousePressed = false; + if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) { + Vec2f autoPoint; + if (objectIndex < beatmap.objects.length - Dancer.instance.getPolyMoverFactoryMinBufferSize()) { + Dancer d = Dancer.instance; + d.update(trackPosition, objectIndex); + autoPoint = new Vec2f(d.x, d.y); + if (trackPosition < gameObjects[objectIndex].getTime()) { + autoMousePressed = true; + } + } else { + if (objectIndex < beatmap.objects.length) { + autoPoint = gameObjects[objectIndex].getPointAt(trackPosition); + } else { + // last object + autoPoint = gameObjects[objectIndex - 1].getPointAt(trackPosition); + } + } + + float[] sbPosition = moveStoryboardOverlay.getPoint(trackPosition); + if (sbPosition != null) { + autoPoint.x = sbPosition[0]; + autoPoint.y = sbPosition[1]; + } + + // set mouse coordinates + autoMousePosition.set(autoPoint.x, autoPoint.y); + } + + if (isReplay) { + displayContainer.cursor.setCursorPosition(displayContainer.delta, replayX, replayY); + } else if (GameMod.AUTO.isActive()) { + displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y); + if (Options.isMirror() && GameMod.AUTO.isActive()) { + double dx = autoMousePosition.x - Options.width / 2d; + double dy = autoMousePosition.y - Options.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)); + } + } else if (GameMod.AUTOPILOT.isActive()) { + displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y); + } + } + /** * Updates the game. * @param mouseX the mouse x coordinate @@ -1078,11 +1095,6 @@ public class Game extends ComplexOpsuState { boolean overlap = (objectIndex + 1 < gameObjects.length && trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]); - if (skippedObject && (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive())) { - Vec2f start = gameObjects[objectIndex - 1].start; - UI.getCursor().setCursorPosition((int) start.x, (int) start.y); - } - // update hit object and check completion status if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition)) { skippedObject = true; @@ -1210,7 +1222,7 @@ public class Game extends ComplexOpsuState { mirrorTo = objectIndex; Options.setMirror(false); } else { - mirrorCursor.resetLocations(); + mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y); mirrorFrom = objectIndex; mirrorTo = gameObjects.length; Options.setMirror(true); @@ -1221,7 +1233,7 @@ public class Game extends ComplexOpsuState { mirrorTo = objectIndex; Options.setMirror(false); } else { - mirrorCursor.resetLocations(); + mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y); mirrorFrom = objectIndex; mirrorTo = mirrorFrom + 1; Options.setMirror(true); @@ -1435,6 +1447,8 @@ public class Game extends ComplexOpsuState { public void enter() { super.enter(); + displayContainer.drawCursor = false; + overlays.clear(); if (Options.isEnableSB()) { overlays.add(optionsOverlay); @@ -1572,8 +1586,9 @@ public class Game extends ComplexOpsuState { } // unhide cursor for "auto" mod and replays - if (GameMod.AUTO.isActive() || isReplay) - UI.getCursor().show(); + if (GameMod.AUTO.isActive() || isReplay) { + GLHelper.showNativeCursor(); + } // load replay frames if (isReplay) { @@ -1683,6 +1698,8 @@ public class Game extends ComplexOpsuState { public void leave() { super.leave(); + displayContainer.drawCursor = true; + MusicController.pause(); MusicController.setPitch(1f); MusicController.resume(); @@ -1705,8 +1722,9 @@ public class Game extends ComplexOpsuState { Cursor.nextMirroredObjColor = Color.white; // re-hide cursor - if (GameMod.AUTO.isActive() || isReplay) - UI.getCursor().hide(); + if (GameMod.AUTO.isActive() || isReplay) { + GLHelper.hideNativeCursor(); + } // replays if (isReplay) diff --git a/src/itdelatrisu/opsu/states/GamePauseMenu.java b/src/itdelatrisu/opsu/states/GamePauseMenu.java index 58d83ef5..642c958e 100644 --- a/src/itdelatrisu/opsu/states/GamePauseMenu.java +++ b/src/itdelatrisu/opsu/states/GamePauseMenu.java @@ -110,9 +110,6 @@ public class GamePauseMenu extends BaseOpsuState { SoundController.playSound(SoundEffect.MENUBACK); instanceContainer.provide(SongMenu.class).resetGameDataOnLoad(); MusicController.playAt(MusicController.getBeatmap().previewTime, true); - if (UI.getCursor().isBeatmapSkinned()) { - UI.getCursor().reset(); - } displayContainer.switchState(SongMenu.class); } else { SoundController.playSound(SoundEffect.MENUBACK); @@ -157,8 +154,9 @@ public class GamePauseMenu extends BaseOpsuState { MusicController.playAt(MusicController.getBeatmap().previewTime, true); else MusicController.resume(); - if (UI.getCursor().isBeatmapSkinned()) - UI.getCursor().reset(); + if (displayContainer.cursor.isBeatmapSkinned()) { + displayContainer.resetCursor(); + } MusicController.setPitch(1.0f); displayContainer.switchState(SongMenu.class); } diff --git a/src/itdelatrisu/opsu/states/GameRanking.java b/src/itdelatrisu/opsu/states/GameRanking.java index fdec21fc..300d6dee 100644 --- a/src/itdelatrisu/opsu/states/GameRanking.java +++ b/src/itdelatrisu/opsu/states/GameRanking.java @@ -63,6 +63,7 @@ public class GameRanking extends BaseOpsuState { public GameRanking(DisplayContainer displayContainer, InstanceContainer instanceContainer) { super(displayContainer); this.instanceContainer = instanceContainer; + } @Override @@ -242,8 +243,8 @@ public class GameRanking extends BaseOpsuState { songMenu.resetTrackOnLoad(); } songMenu.resetGameDataOnLoad(); - if (UI.getCursor().isBeatmapSkinned()) { - UI.getCursor().reset(); + if (displayContainer.cursor.isBeatmapSkinned()) { + displayContainer.resetCursor(); } displayContainer.switchState(SongMenu.class); } diff --git a/src/itdelatrisu/opsu/ui/Cursor.java b/src/itdelatrisu/opsu/ui/Cursor.java index 1b7894c3..f5ad23bf 100644 --- a/src/itdelatrisu/opsu/ui/Cursor.java +++ b/src/itdelatrisu/opsu/ui/Cursor.java @@ -21,28 +21,19 @@ package itdelatrisu.opsu.ui; import itdelatrisu.opsu.GameImage; import itdelatrisu.opsu.Options; import itdelatrisu.opsu.Utils; -import itdelatrisu.opsu.audio.MusicController; import itdelatrisu.opsu.skins.Skin; import itdelatrisu.opsu.ui.animations.AnimationEquation; import java.awt.Point; -import java.nio.IntBuffer; import java.util.LinkedList; -import org.lwjgl.BufferUtils; -import org.lwjgl.LWJGLException; import org.newdawn.slick.*; -import org.newdawn.slick.state.StateBasedGame; import yugecin.opsudance.Dancer; -import yugecin.opsudance.core.DisplayContainer; -import yugecin.opsudance.core.errorhandling.ErrorHandler; /** * Updates and draws the cursor. */ public class Cursor { - /** Empty cursor. */ - private static org.lwjgl.input.Cursor emptyCursor; /** Last cursor coordinates. */ private Point lastPosition; @@ -63,13 +54,10 @@ public class Cursor { private static final float CURSOR_SCALE_TIME = 125; /** Stores all previous cursor locations to display a trail. */ - private LinkedList trail = new LinkedList(); + private LinkedList trail = new LinkedList<>(); private boolean newStyle; - // game-related variables - private static DisplayContainer displayContainer; - public static Color lastObjColor = Color.white; public static Color lastMirroredObjColor = Color.white; public static Color nextObjColor = Color.white; @@ -78,22 +66,6 @@ public class Cursor { private boolean isMirrored; - /** - * Initializes the class. - */ - public static void init(DisplayContainer displayContainer) { - Cursor.displayContainer = displayContainer; - - // create empty cursor to simulate hiding the cursor - try { - int min = org.lwjgl.input.Cursor.getMinCursorSize(); - IntBuffer tmp = BufferUtils.createIntBuffer(min * min); - emptyCursor = new org.lwjgl.input.Cursor(min, min, min/2, min/2, 1, tmp, null); - } catch (LWJGLException e) { - ErrorHandler.error("Failed to create hidden cursor.", e).show(); - } - } - /** * Constructor. */ @@ -102,31 +74,15 @@ public class Cursor { } public Cursor(boolean isMirrored) { - resetLocations(); + resetLocations(0, 0); this.isMirrored = isMirrored; } /** * Draws the cursor. - */ - public void draw() { - /* - int state = game.getCurrentStateID(); - boolean mousePressed = - (((state == Opsu.STATE_GAME || state == Opsu.STATE_GAMEPAUSEMENU) && Utils.isGameKeyPressed()) || - ((input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) && - !(state == Opsu.STATE_GAME && Options.isMouseDisabled()))); - draw(input.getMouseX(), input.getMouseY(), mousePressed); - */ - } - - /** - * Draws the cursor. - * @param mouseX the mouse x coordinate - * @param mouseY the mouse y coordinate * @param mousePressed whether or not the mouse button is pressed */ - public void draw(int mouseX, int mouseY, boolean mousePressed) { + public void draw(boolean mousePressed) { if (Options.isCursorDisabled()) return; @@ -168,8 +124,6 @@ public class Cursor { cursorTrail = cursorTrail.getScaledCopy(cursorScale); } - setCursorPosition(mouseX, mouseY); - Color filter; if (isMirrored) { filter = Dancer.cursorColorMirrorOverride.getMirrorColor(); @@ -191,16 +145,16 @@ public class Cursor { cursorTrailWidth, cursorTrailHeight, cursorTrailRotation); } cursorTrail.drawEmbedded( - mouseX - (cursorTrailWidth / 2f), mouseY - (cursorTrailHeight / 2f), + lastPosition.x - (cursorTrailWidth / 2f), lastPosition.y - (cursorTrailHeight / 2f), cursorTrailWidth, cursorTrailHeight, cursorTrailRotation); cursorTrail.endUse(); // draw the other components if (newStyle && skin.isCursorRotated()) cursor.setRotation(cursorAngle); - cursor.drawCentered(mouseX, mouseY, Options.isCursorOnlyColorTrail() ? Color.white : filter); + cursor.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter); if (hasMiddle) - cursorMiddle.drawCentered(mouseX, mouseY, Options.isCursorOnlyColorTrail() ? Color.white : filter); + cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter); } /** @@ -208,10 +162,10 @@ public class Cursor { * @param mouseX x coordinate to set position to * @param mouseY y coordinate to set position to */ - public void setCursorPosition(int mouseX, int mouseY) { + public void setCursorPosition(int delta, int mouseX, int mouseY) { // TODO: use an image buffer int removeCount = 0; - float FPSmod = Math.max(1000 / displayContainer.renderDelta, 1) / 30f; // TODO + float FPSmod = Math.max(1000 / Math.max(delta, 1), 1) / 30f; // TODO if (newStyle) { // new style: add all points between cursor movements if ((lastPosition.x == 0 && lastPosition.y == 0) || !addCursorPoints(lastPosition.x, lastPosition.y, mouseX, mouseY)) { @@ -297,7 +251,7 @@ public class Cursor { * If the old style cursor is being used, this will do nothing. * @param delta the delta interval since the last call */ - public void update(int delta) { + public void updateAngle(int delta) { cursorAngle += delta / 40f; cursorAngle %= 360; } @@ -305,14 +259,14 @@ public class Cursor { /** * Resets all cursor data and beatmap skins. */ - public void reset() { + public void reset(int mouseX, int mouseY) { // destroy skin images GameImage.CURSOR.destroyBeatmapSkinImage(); GameImage.CURSOR_MIDDLE.destroyBeatmapSkinImage(); GameImage.CURSOR_TRAIL.destroyBeatmapSkinImage(); // reset locations - resetLocations(); + resetLocations(mouseX, mouseY); // reset angles cursorAngle = 0f; @@ -321,14 +275,12 @@ public class Cursor { /** * Resets all cursor location data. */ - public void resetLocations() { + public void resetLocations(int mouseX, int mouseY) { trail.clear(); - if (lastPosition != null) { - for (int i = 0; i < 50; i++) { - trail.add(new Point(lastPosition)); - } + lastPosition = new Point(mouseX, mouseY); + for (int i = 0; i < 50; i++) { + trail.add(new Point(lastPosition)); } - lastPosition = new Point(0, 0); } /** @@ -340,25 +292,4 @@ public class Cursor { GameImage.CURSOR_TRAIL.hasBeatmapSkinImage()); } - /** - * Hides the cursor, if possible. - */ - public void hide() { - if (emptyCursor != null) { - /* - try { - container.setMouseCursor(emptyCursor, 0, 0); - } catch (SlickException e) { - ErrorHandler.error("Failed to hide the cursor.", e, true); - } - */ - } - } - - /** - * Unhides the cursor. - */ - public void show() { - //container.setDefaultMouseCursor(); - } } diff --git a/src/itdelatrisu/opsu/ui/UI.java b/src/itdelatrisu/opsu/ui/UI.java index 8c5d5a10..f2d7f65d 100644 --- a/src/itdelatrisu/opsu/ui/UI.java +++ b/src/itdelatrisu/opsu/ui/UI.java @@ -28,24 +28,16 @@ import itdelatrisu.opsu.replay.ReplayImporter; import itdelatrisu.opsu.ui.animations.AnimatedValue; import itdelatrisu.opsu.ui.animations.AnimationEquation; -import javax.swing.JOptionPane; -import javax.swing.UIManager; - import org.newdawn.slick.Animation; import org.newdawn.slick.Color; -import org.newdawn.slick.GameContainer; import org.newdawn.slick.Graphics; import org.newdawn.slick.Image; -import org.newdawn.slick.Input; -import org.newdawn.slick.state.StateBasedGame; import yugecin.opsudance.core.DisplayContainer; /** * Draws common UI components. */ public class UI { - /** Cursor. */ - private static Cursor cursor = new Cursor(); /** Back button. */ private static MenuButton backButton; @@ -86,10 +78,6 @@ public class UI { public static void init(DisplayContainer displayContainer) { UI.displayContainer = displayContainer; - // initialize cursor - Cursor.init(displayContainer); - cursor.hide(); - // back button if (GameImage.MENU_BACK.getImages() != null) { Animation back = GameImage.MENU_BACK.getAnimation(120); @@ -108,7 +96,6 @@ public class UI { * @param delta the delta interval since the last call. */ public static void update(int delta) { - cursor.update(delta); updateVolumeDisplay(delta); updateBarNotification(delta); tooltipAlpha.update(-delta); @@ -121,22 +108,6 @@ public class UI { public static void draw(Graphics g) { drawBarNotification(g); drawVolume(g); - cursor.draw(); - drawTooltip(g); - } - - /** - * Draws the global UI components: cursor, FPS, volume bar, tooltips, bar notifications. - * @param g the graphics context - * @param mouseX the mouse x coordinate - * @param mouseY the mouse y coordinate - * @param mousePressed whether or not the mouse button is pressed - */ - public static void draw(Graphics g, int mouseX, int mouseY, boolean mousePressed) { - drawBarNotification(g); - drawVolume(g); - cursor.draw(mouseX, mouseY, mousePressed); - drawTooltip(g); } /** @@ -144,16 +115,10 @@ public class UI { */ public static void enter() { backButton.resetHover(); - cursor.resetLocations(); resetBarNotification(); resetTooltip(); } - /** - * Returns the game cursor. - */ - public static Cursor getCursor() { return cursor; } - /** * Returns the 'menu-back' MenuButton. */ diff --git a/src/yugecin/opsudance/core/DisplayContainer.java b/src/yugecin/opsudance/core/DisplayContainer.java index 4e7f6308..35a47aba 100644 --- a/src/yugecin/opsudance/core/DisplayContainer.java +++ b/src/yugecin/opsudance/core/DisplayContainer.java @@ -25,7 +25,9 @@ import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.downloads.DownloadList; import itdelatrisu.opsu.downloads.Updater; import itdelatrisu.opsu.render.CurveRenderState; +import itdelatrisu.opsu.ui.Cursor; import itdelatrisu.opsu.ui.Fonts; +import itdelatrisu.opsu.ui.UI; import org.lwjgl.Sys; import org.lwjgl.openal.AL; import org.lwjgl.opengl.Display; @@ -107,9 +109,14 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen private long exitconfirmation; + public final Cursor cursor; + public boolean drawCursor; + public DisplayContainer(InstanceContainer instanceContainer, EventBus eventBus) { this.instanceContainer = instanceContainer; this.eventBus = eventBus; + this.cursor = new Cursor(); + drawCursor = true; outTransitionListener = new TransitionFinishedListener() { @Override @@ -169,7 +176,11 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen Music.poll(delta); mouseX = input.getMouseX(); mouseY = input.getMouseY(); + state.update(); + if (drawCursor) { + cursor.setCursorPosition(delta, mouseX, mouseY); + } int maxRenderInterval; if (Display.isVisible() && Display.isActive()) { @@ -196,6 +207,12 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen bubNotifState.render(graphics); barNotifState.render(graphics); + cursor.updateAngle(renderDelta); + if (drawCursor) { + cursor.draw(input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)); + } + UI.drawTooltip(graphics); + timeSinceLastRender = 0; Display.update(false); @@ -216,6 +233,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen initGL(); glVersion = GL11.glGetString(GL11.GL_VERSION); glVendor = GL11.glGetString(GL11.GL_VENDOR); + GLHelper.hideNativeCursor(); } public void teardown() { @@ -318,6 +336,10 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen eventBus.post(new ResolutionChangedEvent(this.width, this.height)); } + public void resetCursor() { + cursor.reset(mouseX, mouseY); + } + private int getDelta() { long time = getTime(); int delta = (int) (time - lastFrame); diff --git a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java index 39a4ce64..13f72a50 100644 --- a/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java +++ b/src/yugecin/opsudance/core/inject/OpsuDanceInjector.java @@ -57,8 +57,8 @@ public class OpsuDanceInjector extends Injector { bind(ButtonMenu.class).asEagerSingleton(); bind(SongMenu.class).asEagerSingleton(); bind(DownloadsMenu.class).asEagerSingleton(); - bind(GameRanking.class).asEagerSingleton(); bind(Game.class).asEagerSingleton(); + bind(GameRanking.class).asEagerSingleton(); bind(GamePauseMenu.class).asEagerSingleton(); } diff --git a/src/yugecin/opsudance/utils/GLHelper.java b/src/yugecin/opsudance/utils/GLHelper.java index b1d4a965..66db778b 100644 --- a/src/yugecin/opsudance/utils/GLHelper.java +++ b/src/yugecin/opsudance/utils/GLHelper.java @@ -17,7 +17,10 @@ */ package yugecin.opsudance.utils; +import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; +import org.lwjgl.input.Cursor; +import org.lwjgl.input.Mouse; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.DisplayMode; import org.newdawn.slick.opengl.ImageIOImageData; @@ -25,8 +28,10 @@ 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; public class GLHelper { @@ -85,4 +90,22 @@ public class GLHelper { Display.setIcon(bufs); } + public static void hideNativeCursor() { + try { + int min = Cursor.getMinCursorSize(); + 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(); + } + } + + public static void showNativeCursor() { + try { + Mouse.setNativeCursor(null); + } catch (LWJGLException e) { + ErrorHandler.error("Cannot show native cursor", e).show(); + } + } + }