Merge branch 'master' into replaystuff

# Conflicts:
#	src/itdelatrisu/opsu/Options.java
#	src/itdelatrisu/opsu/ui/Cursor.java
This commit is contained in:
yugecin
2017-03-30 00:05:45 +02:00
95 changed files with 3242 additions and 3216 deletions

View File

@@ -42,12 +42,25 @@ import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.utils.SlickUtil;
import static yugecin.opsudance.options.Options.*;
/**
* Holds game data and renders all related elements.
*/
public class GameData {
@Inject
private Configuration config;
@Inject
private InstanceContainer instanceContainer;
/** Delta multiplier for steady HP drain. */
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;
@@ -383,7 +396,7 @@ public class GameData {
hitResultCount[HIT_100K] = s.katu;
hitResultCount[HIT_MISS] = s.miss;
this.replay = (s.replayString == null) ? null :
new Replay(new File(Options.getReplayDir(), String.format("%s.osr", s.replayString)));
instanceContainer.injectFields(new Replay(new File(config.replayDir, String.format("%s.osr", s.replayString))));
loadImages();
}
@@ -515,7 +528,7 @@ public class GameData {
if (digitWidth <= 1f) {
return;
}
digitWidth = (digitWidth - Options.getSkin().getHitCircleFontOverlap()) * scale;
digitWidth = (digitWidth - SkinService.skin.getHitCircleFontOverlap()) * scale;
float cx = x + ((length - 1) * (digitWidth / 2));
for (int i = 0; i < length; i++) {
@@ -544,7 +557,7 @@ public class GameData {
Image digit = getScoreSymbolImage(c[i]);
if (scale != 1.0f)
digit = digit.getScaledCopy(scale);
cx -= digit.getWidth() + Options.getSkin().getScoreFontOverlap();
cx -= digit.getWidth() + SkinService.skin.getScoreFontOverlap();
digit.setAlpha(alpha);
digit.draw(cx, y);
digit.setAlpha(1f);
@@ -557,7 +570,7 @@ public class GameData {
digit.setAlpha(alpha);
digit.draw(cx, y);
digit.setAlpha(1f);
cx += digit.getWidth() - Options.getSkin().getScoreFontOverlap();
cx += digit.getWidth() - SkinService.skin.getScoreFontOverlap();
}
}
}
@@ -679,7 +692,7 @@ public class GameData {
}
// hit error bar
if (Options.isHitErrorBarEnabled() && !hitErrorList.isEmpty()) {
if (OPTION_SHOW_HIT_ERROR_BAR.state && !hitErrorList.isEmpty()) {
// fade out with last tick
float hitErrorAlpha = 1f;
Color white = new Color(Color.white);
@@ -914,10 +927,8 @@ public class GameData {
spinnerOsu.setAlpha(hitResult.alpha);
spinnerOsu.drawCentered(width / 2, height / 4);
spinnerOsu.setAlpha(1f);
}
// hit lighting
else if (Options.isHitLightingEnabled() && !hitResult.hideResult && hitResult.result != HIT_MISS &&
} else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS &&
// hit lighting
hitResult.result != HIT_SLIDER30 && hitResult.result != HIT_SLIDER10) {
// TODO: add particle system
Image lighting = GameImage.LIGHTING.getImage();
@@ -965,14 +976,14 @@ public class GameData {
private void drawHitAnimations(HitObjectResult hitResult, int trackPosition) {
// fade out slider curve
if (hitResult.result != HIT_SLIDER_REPEAT && hitResult.result != HIT_SLIDER_REPEAT_M && hitResult.curve != null) {
if (!Options.isShrinkingSliders()) {
if (!OPTION_SHRINKING_SLIDERS.state) {
float progress = AnimationEquation.OUT_CUBIC.calc(
(float) Utils.clamp(trackPosition - hitResult.time, 0, HITCIRCLE_FADE_TIME) / HITCIRCLE_FADE_TIME);
float alpha = 1f - progress;
float oldWhiteAlpha = Colors.WHITE_FADE.a;
float oldColorAlpha = hitResult.color.a;
Colors.WHITE_FADE.a = hitResult.color.a = alpha;
hitResult.curve.draw(hitResult.color);
hitResult.curve.draw(hitResult.color, (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) ? 1 : 0, hitResult.curve.getCurvePoints().length);
Colors.WHITE_FADE.a = oldWhiteAlpha;
hitResult.color.a = oldColorAlpha;
}
@@ -987,7 +998,7 @@ public class GameData {
fc.drawCentered(hitResult.x, hitResult.y);
}
if (!Options.isDrawSliderEndCircles()) {
if (!OPTION_DRAW_SLIDER_ENDCIRCLES.state) {
return;
}
}
@@ -1024,7 +1035,7 @@ public class GameData {
}
scaledRepeat.rotate(ang);
scaledRepeat.drawCentered(hitResult.x, hitResult.y, hitResult.color);
if (!Options.isDrawSliderEndCircles()) {
if (!OPTION_DRAW_SLIDER_ENDCIRCLES.state) {
GameImage.HITCIRCLE.getImage().draw(-1000, -1000); // TODO this 'fixes' #114. Why? Get a better solution!
GameImage.HITCIRCLE_OVERLAY.getImage().draw(-1000, -1000);
return;
@@ -1186,7 +1197,7 @@ public class GameData {
}
// combo burst
if (comboBurstIndex > -1 && Options.isComboBurstEnabled()) {
if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) {
int leftX = 0;
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
if (comboBurstX < leftX) {
@@ -1210,7 +1221,7 @@ public class GameData {
comboPopTime = COMBO_POP_TIME;
// hit error bar
if (Options.isHitErrorBarEnabled()) {
if (OPTION_SHOW_HIT_ERROR_BAR.state) {
int trackPosition = MusicController.getPosition();
Iterator<HitErrorInfo> iter = hitErrorList.iterator();
while (iter.hasNext()) {
@@ -1237,21 +1248,22 @@ public class GameData {
comboMax = combo;
// combo bursts (at 30, 60, 100+50x)
if (Options.isComboBurstEnabled() &&
(combo == 30 || combo == 60 || (combo >= 100 && combo % 50 == 0))) {
if (Options.getSkin().isComboBurstRandom())
if (OPTION_SHOW_COMBO_BURSTS.state && (combo == 30 || combo == 60 || (combo >= 100 && combo % 50 == 0))) {
if (SkinService.skin.isComboBurstRandom()) {
comboBurstIndex = (int) (Math.random() * comboBurstImages.length);
else {
if (combo == 30)
} else {
if (combo == 30) {
comboBurstIndex = 0;
else
} else {
comboBurstIndex = (comboBurstIndex + 1) % comboBurstImages.length;
}
}
comboBurstAlpha = 0.8f;
if ((comboBurstIndex % 2) == 0)
if ((comboBurstIndex % 2) == 0) {
comboBurstX = width;
else
} else {
comboBurstX = comboBurstImages[0].getWidth() * -1;
}
}
}
@@ -1277,7 +1289,7 @@ public class GameData {
*/
public void sendSliderRepeatResult(int time, float x, float y, Color color, Curve curve, HitObjectType type) {
hitResultList.add(new HitObjectResult(time, HIT_SLIDER_REPEAT, x, y, color, type, curve, true, true));
if (!Options.isMirror()) {
if (!OPTION_DANCE_MIRROR.state) {
return;
}
float[] m = Utils.mirrorPoint(x, y);
@@ -1294,7 +1306,7 @@ public class GameData {
*/
public void sendSliderStartResult(int time, float x, float y, Color color, Color mirrorColor, boolean expand) {
hitResultList.add(new HitObjectResult(time, HIT_ANIMATION_RESULT, x, y, color, HitObjectType.CIRCLE, null, expand, true));
if (!Options.isMirror()) {
if (!OPTION_DANCE_MIRROR.state) {
return;
}
float[] m = Utils.mirrorPoint(x, y);
@@ -1338,10 +1350,9 @@ public class GameData {
score += hitValue;
incrementComboStreak();
if (!Options.isPerfectHitBurstEnabled())
; // hide perfect hit results
else
if (OPTION_SHOW_PERFECT_HIT.state) {
hitResultList.add(new HitObjectResult(time, result, x, y, null, HitObjectType.SLIDERTICK, null, false, false));
}
}
fullObjectCount++;
}
@@ -1527,7 +1538,7 @@ public class GameData {
if (hitResult == HIT_MISS && (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive()))
return; // "relax" and "autopilot" mods: hide misses
boolean hideResult = (hitResult == HIT_300 || hitResult == HIT_300G || hitResult == HIT_300K) && !Options.isPerfectHitBurstEnabled();
boolean hideResult = (hitResult == HIT_300 || hitResult == HIT_300G || hitResult == HIT_300K) && !OPTION_SHOW_PERFECT_HIT.state;
hitResultList.add(new HitObjectResult(time, hitResult, x, y, color, hitResultType, curve, expand, hideResult));
}

View File

@@ -32,8 +32,11 @@ 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.skinning.SkinService;
import yugecin.opsudance.utils.SlickUtil;
import static yugecin.opsudance.options.Options.*;
/**
* Game images.
*/
@@ -546,7 +549,7 @@ public enum GameImage {
* and UI scale.
*/
private static String[] getSuffixes() {
return (Options.loadHDImages() && uiscale >= 1) ? SUFFIXES_HD : SUFFIXES_SD;
return (OPTION_LOAD_HD_IMAGES.state && uiscale >= 1) ? SUFFIXES_HD : SUFFIXES_SD;
}
@@ -687,11 +690,12 @@ public enum GameImage {
* If the default image has already been loaded, this will do nothing.
*/
public void setDefaultImage() {
if (defaultImage != null || defaultImages != null || Options.getSkin() == null)
if (defaultImage != null || defaultImages != null || SkinService.skin == null) {
return;
}
// try to load skin images
File skinDir = Options.getSkin().getDirectory();
File skinDir = SkinService.skin.getDirectory();
if (filenameFormat != null) {
if (skinDir != null && ((defaultImages = loadImageArray(skinDir)) != null)) {
isSkinned = true;
@@ -739,15 +743,17 @@ public enum GameImage {
* @return true if a new skin image is loaded, false otherwise
*/
public boolean setBeatmapSkinImage(File dir) {
if (dir == null)
if (dir == null) {
return false;
}
// destroy the existing images, if any
destroyBeatmapSkinImage();
// beatmap skins disabled
if (Options.isBeatmapSkinIgnored())
if (OPTION_IGNORE_BEATMAP_SKINS.state) {
return false;
}
// try to load multiple images
if ((skinImages = loadImageArray(dir)) != null) {

File diff suppressed because it is too large Load Diff

View File

@@ -18,17 +18,8 @@
package itdelatrisu.opsu;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.DownloadNode;
import itdelatrisu.opsu.replay.PlaybackSpeed;
import itdelatrisu.opsu.ui.Fonts;
import itdelatrisu.opsu.ui.UI;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
@@ -41,18 +32,13 @@ import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Scanner;
import java.util.jar.JarFile;
import javax.imageio.ImageIO;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
@@ -61,21 +47,15 @@ import javax.net.ssl.X509TrustManager;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Input;
import org.newdawn.slick.state.StateBasedGame;
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;
import yugecin.opsudance.options.Options;
/**
* Contains miscellaneous utilities.
@@ -104,32 +84,6 @@ public class Utils {
// TODO clean this up
// game settings
displayContainer.setFPS(Options.getTargetFPS()); // TODO move this elsewhere
MusicController.setMusicVolume(Options.getMusicVolume() * Options.getMasterVolume());
// load skin
Options.loadSkin();
// initialize game images
for (GameImage img : GameImage.values()) {
if (img.isPreload())
img.setDefaultImage();
}
// initialize game mods
GameMod.init(displayContainer.width, displayContainer.height);
// initialize playback buttons
PlaybackSpeed.init(displayContainer.width, displayContainer.height);
// initialize hit objects
HitObject.init(displayContainer.width, displayContainer.height);
// initialize download nodes
DownloadNode.init(displayContainer.width, displayContainer.height);
// initialize UI components
UI.init(displayContainer);
}
/**
@@ -240,55 +194,6 @@ public class Utils {
return true;
}
/**
* Takes a screenshot.
* @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots
*/
public static void takeScreenShot() {
// create the screenshot directory
File dir = Options.getScreenshotDir();
if (!dir.isDirectory() && !dir.mkdir()) {
EventBus.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 String fileName = String.format("screenshot_%s.%s", date.format(new Date()), Options.getScreenshotFormat());
final File file = new File(dir, fileName);
SoundController.playSound(SoundEffect.SHUTTER);
// copy the screen to file
final int width = Display.getWidth();
final int height = Display.getHeight();
final int bpp = 3; // assuming a 32-bit display with a byte each for red, green, blue, and alpha
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
GL11.glReadBuffer(GL11.GL_FRONT);
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
GL11.glReadPixels(0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer);
new Thread() {
@Override
public void run() {
try {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int i = (x + (width * y)) * bpp;
int r = buffer.get(i) & 0xFF;
int g = buffer.get(i + 1) & 0xFF;
int b = buffer.get(i + 2) & 0xFF;
image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b);
}
}
ImageIO.write(image, Options.getScreenshotFormat(), file);
EventBus.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
} catch (Exception e) {
ErrorHandler.error("Failed to take a screenshot.", e).show();
}
}
}.start();
}
/**
* Returns a human-readable representation of a given number of bytes.
@@ -550,14 +455,6 @@ public class Utils {
}
}
/**
* Returns the current working directory.
* @return the directory
*/
public static File getWorkingDirectory() {
return Paths.get(".").toAbsolutePath().normalize().toFile();
}
/**
* Parses the integer string argument as a boolean:
* {@code 1} is {@code true}, and all other values are {@code false}.
@@ -661,4 +558,19 @@ public class Utils {
};
}
/**
* Returns the file extension of a file.
* @param file the file name
*/
public static String getFileExtension(String file) {
int i = file.lastIndexOf('.');
return (i != -1) ? file.substring(i + 1).toLowerCase() : "";
}
public static boolean isValidGameKey(int key) {
return (key != Keyboard.KEY_ESCAPE && key != Keyboard.KEY_SPACE &&
key != Keyboard.KEY_UP && key != Keyboard.KEY_DOWN &&
key != Keyboard.KEY_F7 && key != Keyboard.KEY_F10 && key != Keyboard.KEY_F12);
}
}

View File

@@ -18,9 +18,8 @@
package itdelatrisu.opsu.audio;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.states.Game;
@@ -50,6 +49,8 @@ import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import static yugecin.opsudance.options.Options.*;
/**
* Controller for all music.
*/
@@ -109,7 +110,7 @@ public class MusicController {
reset();
System.gc();
switch (BeatmapParser.getExtension(beatmap.audioFilename.getName())) {
switch (Utils.getFileExtension(beatmap.audioFilename.getName())) {
case "ogg":
case "mp3":
trackLoader = new Thread() {
@@ -168,7 +169,7 @@ public class MusicController {
*/
public static void playAt(final int position, final boolean loop) {
if (trackExists()) {
setVolume(Options.getMusicVolume() * Options.getMasterVolume());
setVolume(OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f);
trackEnded = false;
pauseTime = 0f;
resetTimingPoint();
@@ -348,9 +349,9 @@ public class MusicController {
*/
public static int getPosition() {
if (isPlaying())
return (int) (player.getPosition() * 1000 + Options.getMusicOffset() + Game.currentMapMusicOffset);
return (int) (player.getPosition() * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset);
else if (isPaused())
return Math.max((int) (pauseTime * 1000 + Options.getMusicOffset() + Game.currentMapMusicOffset), 0);
return Math.max((int) (pauseTime * 1000 + OPTION_MUSIC_OFFSET.val + Game.currentMapMusicOffset), 0);
else
return 0;
}
@@ -443,13 +444,9 @@ public class MusicController {
playAt((preview) ? lastBeatmap.previewTime : 0, false);
}
/**
* Plays the theme song.
*/
public static void playThemeSong() {
Beatmap beatmap = Options.getThemeBeatmap();
if (beatmap != null) {
play(beatmap, false, false);
public static void playThemeSong(Beatmap themeBeatmap) {
if (themeBeatmap != null) {
play(themeBeatmap, false, false);
themePlaying = true;
}
}
@@ -470,7 +467,7 @@ public class MusicController {
* @param multiplier the volume multiplier when the track is dimmed
*/
public static void toggleTrackDimmed(float multiplier) {
float volume = Options.getMusicVolume() * Options.getMasterVolume();
float volume = OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f;
dimLevel = (isTrackDimmed()) ? 1f : multiplier;
trackDimmed = !trackDimmed;
setVolume(volume);

View File

@@ -18,12 +18,10 @@
package itdelatrisu.opsu.audio;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.audio.HitSound.SampleSet;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.downloads.Download;
import itdelatrisu.opsu.downloads.Download.DownloadListener;
import itdelatrisu.opsu.ui.UI;
import java.io.File;
import java.io.IOException;
@@ -44,6 +42,10 @@ import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
/**
* Controller for all (non-music) sound components.
@@ -190,7 +192,7 @@ public class SoundController {
*/
private static String getSoundFileName(String filename) {
String wav = String.format("%s.wav", filename), mp3 = String.format("%s.mp3", filename);
File skinDir = Options.getSkin().getDirectory();
File skinDir = SkinService.skin.getDirectory();
if (skinDir != null) {
File skinWAV = new File(skinDir, wav), skinMP3 = new File(skinDir, mp3);
if (skinWAV.isFile())
@@ -209,8 +211,9 @@ public class SoundController {
* Loads all sound files.
*/
public static void init() {
if (Options.isSoundDisabled())
if (OPTION_DISABLE_SOUNDS.state) {
return;
}
currentFileIndex = 0;
@@ -290,7 +293,7 @@ public class SoundController {
* @param s the sound effect
*/
public static void playSound(SoundComponent s) {
playClip(s.getClip(), Options.getEffectVolume() * Options.getMasterVolume(), null);
playClip(s.getClip(), OPTION_EFFECT_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f, null);
}
/**
@@ -303,16 +306,16 @@ public class SoundController {
if (hitSound < 0)
return;
if (Options.getSampleVolumeOverride() > 0) {
sampleVolumeMultiplier = Options.getSampleVolumeOverride();
if (OPTION_SAMPLE_VOLUME_OVERRIDE.val > 0) {
sampleVolumeMultiplier = OPTION_SAMPLE_VOLUME_OVERRIDE.val / 100f;
}
float volume = Options.getHitSoundVolume() * sampleVolumeMultiplier * Options.getMasterVolume();
float volume = OPTION_HITSOUND_VOLUME.val / 100f * sampleVolumeMultiplier * OPTION_MASTER_VOLUME.val / 100f;
if (volume == 0f)
return;
// play all sounds
if (hitSound == HitObject.SOUND_NORMAL || Options.getSkin().isLayeredHitSounds()) {
if (hitSound == HitObject.SOUND_NORMAL || SkinService.skin.isLayeredHitSounds()) {
HitSound.setSampleSet(sampleSet);
playClip(HitSound.NORMAL.getClip(), volume, null);
}
@@ -333,7 +336,7 @@ public class SoundController {
* @param s the hit sound
*/
public static void playHitSound(SoundComponent s) {
playClip(s.getClip(), Options.getHitSoundVolume() * sampleVolumeMultiplier * Options.getMasterVolume(), null);
playClip(s.getClip(), OPTION_HITSOUND_VOLUME.val / 100f * sampleVolumeMultiplier * OPTION_MASTER_VOLUME.val / 100f, null);
}
/**
@@ -370,15 +373,16 @@ public class SoundController {
* @return true if playing, false otherwise
* @throws SlickException if any error occurred
*/
public static synchronized boolean playTrack(String url, String name, boolean isMP3, LineListener listener)
public static synchronized boolean playTrack(Configuration config, String url, String name, boolean isMP3, LineListener listener)
throws SlickException {
// stop previous track
stopTrack();
// download new track
File dir = Options.TEMP_DIR;
if (!dir.isDirectory())
File dir = config.TEMP_DIR;
if (!dir.isDirectory()) {
dir.mkdir();
}
String filename = String.format("%s.%s", name, isMP3 ? "mp3" : "wav");
final File downloadFile = new File(dir, filename);
boolean complete;
@@ -406,7 +410,7 @@ public class SoundController {
try {
AudioInputStream audioIn = AudioSystem.getAudioInputStream(downloadFile);
currentTrack = loadClip(filename, audioIn, isMP3);
playClip(currentTrack, Options.getMusicVolume() * Options.getMasterVolume(), listener);
playClip(currentTrack, OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f, listener);
return true;
} catch (Exception e) {
throw new SlickException(String.format("Failed to load clip '%s'.", url));

View File

@@ -18,8 +18,6 @@
package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Options;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
@@ -30,6 +28,8 @@ import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import org.newdawn.slick.util.Log;
import static yugecin.opsudance.options.Options.*;
/**
* Beatmap structure storing data parsed from OSU files.
*/
@@ -264,7 +264,7 @@ public class Beatmap implements Comparable<Beatmap> {
* @return the song title
*/
public String getTitle() {
return (Options.useUnicodeMetadata() && !titleUnicode.isEmpty()) ? titleUnicode : title;
return (OPTION_SHOW_UNICODE.state && !titleUnicode.isEmpty()) ? titleUnicode : title;
}
/**
@@ -273,25 +273,23 @@ public class Beatmap implements Comparable<Beatmap> {
* @return the song artist
*/
public String getArtist() {
return (Options.useUnicodeMetadata() && !artistUnicode.isEmpty()) ? artistUnicode : artist;
return (OPTION_SHOW_UNICODE.state && !artistUnicode.isEmpty()) ? artistUnicode : artist;
}
/**
* Returns the list of combo colors (max 8).
* If the beatmap does not provide colors, the skin colors will be returned instead.
* @return the combo colors
* @return the combo colors, or null if this beatmap does not have combo colors specified.
*/
public Color[] getComboColors() {
return (combo != null) ? combo : Options.getSkin().getComboColors();
return combo;
}
/**
* Returns the slider border color.
* If the beatmap does not provide a color, the skin color will be returned instead.
* @return the slider border color
* @return the slider border color, or null if this beatmap does not have a slider border color specified.
*/
public Color getSliderBorderColor() {
return (sliderBorder != null) ? sliderBorder : Options.getSkin().getSliderBorderColor();
return sliderBorder;
}
/**

View File

@@ -18,7 +18,6 @@
package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.db.BeatmapDB;
import itdelatrisu.opsu.io.MD5InputStreamWrapper;
@@ -36,55 +35,69 @@ 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.BarNotificationEvent;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
/**
* Parser for beatmaps.
*/
public class BeatmapParser {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
/** The string lookup database. */
private static HashMap<String, String> stringdb = new HashMap<String, String>();
/** The expected pattern for beatmap directories, used to find beatmap set IDs. */
private static final String DIR_MSID_PATTERN = "^\\d+ .*";
private final String DIR_MSID_PATTERN = "^\\d+ .*";
/** The current file being parsed. */
private static File currentFile;
private File currentFile;
/** The current directory number while parsing. */
private static int currentDirectoryIndex = -1;
private int currentDirectoryIndex = -1;
/** The total number of directories to parse. */
private static int totalDirectories = -1;
private int totalDirectories = -1;
/** Parser statuses. */
public enum Status { NONE, PARSING, CACHE, INSERTING };
/** The current status. */
private static Status status = Status.NONE;
private Status status = Status.NONE;
/** If no Provider supports a MessageDigestSpi implementation for the MD5 algorithm. */
private static boolean hasNoMD5Algorithm = false;
private boolean hasNoMD5Algorithm = false;
// This class should not be instantiated.
private BeatmapParser() {}
@Inject
public BeatmapParser() {
}
/**
* Invokes parser for each OSU file in a root directory and
* adds the beatmaps to a new BeatmapSetList.
* @param root the root directory (search has depth 1)
*/
public static void parseAllFiles(File root) {
public void parseAll() {
// create a new BeatmapSetList
BeatmapSetList.create();
// create a new watch service
if (Options.isWatchServiceEnabled())
BeatmapWatchService.create();
if (OPTION_ENABLE_WATCH_SERVICE.state) {
BeatmapWatchService.create(instanceContainer);
}
// parse all directories
parseDirectories(root.listFiles());
parseDirectories(config.beatmapDir.listFiles());
}
/**
@@ -93,7 +106,7 @@ public class BeatmapParser {
* @param dirs the array of directories to parse
* @return the last BeatmapSetNode parsed, or null if none
*/
public static BeatmapSetNode parseDirectories(File[] dirs) {
public BeatmapSetNode parseDirectories(File[] dirs) {
if (dirs == null)
return null;
@@ -111,7 +124,7 @@ public class BeatmapParser {
List<Beatmap> parsedBeatmaps = new LinkedList<Beatmap>(); // loaded from parser
// watch service
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
BeatmapWatchService ws = BeatmapWatchService.get();
// parse directories
BeatmapSetNode lastNode = null;
@@ -215,7 +228,7 @@ public class BeatmapParser {
return lastNode;
}
public static void parseOnlyTimingPoints(Beatmap map) {
public void parseOnlyTimingPoints(Beatmap map) {
if (map == null || map.getFile() == null || !map.getFile().exists()) {
return;
}
@@ -259,7 +272,7 @@ public class BeatmapParser {
}
}
private static void parseSectionTimingPoints(Beatmap beatmap, String line) {
private void parseSectionTimingPoints(Beatmap beatmap, String line) {
TimingPoint timingPoint = new TimingPoint(line);
if(!timingPoint.isInherited()) {
int bpm = Math.round(60000 / timingPoint.getBeatLength());
@@ -282,7 +295,7 @@ public class BeatmapParser {
* @param parseObjects if true, hit objects will be fully parsed now
* @return the new beatmap
*/
private static Beatmap parseFile(File file, File dir, ArrayList<Beatmap> beatmaps, boolean parseObjects) {
private Beatmap parseFile(File file, File dir, ArrayList<Beatmap> beatmaps, boolean parseObjects) {
Beatmap beatmap = new Beatmap(file);
beatmap.timingPoints = new ArrayList<TimingPoint>();
@@ -523,7 +536,7 @@ public class BeatmapParser {
switch (tokens[0]) {
case "0": // background
tokens[2] = tokens[2].replaceAll("^\"|\"$", "");
String ext = BeatmapParser.getExtension(tokens[2]);
String ext = Utils.getFileExtension(tokens[2]);
if (ext.equals("jpg") || ext.equals("png"))
beatmap.bg = new File(dir, getDBString(tokens[2]));
break;
@@ -767,6 +780,9 @@ public class BeatmapParser {
// combo info
Color[] combo = beatmap.getComboColors();
if (combo == null) {
combo = SkinService.skin.getComboColors();
}
int comboIndex = 0; // color index
int comboNumber = 1; // combo number
@@ -832,7 +848,7 @@ public class BeatmapParser {
* Splits line into two strings: tag, value.
* If no ':' character is present, null will be returned.
*/
private static String[] tokenize(String line) {
private String[] tokenize(String line) {
int index = line.indexOf(':');
if (index == -1) {
Log.debug(String.format("Failed to tokenize line: '%s'.", line));
@@ -845,19 +861,10 @@ public class BeatmapParser {
return tokens;
}
/**
* Returns the file extension of a file.
* @param file the file name
*/
public static String getExtension(String file) {
int i = file.lastIndexOf('.');
return (i != -1) ? file.substring(i + 1).toLowerCase() : "";
}
/**
* Returns the name of the current file being parsed, or null if none.
*/
public static String getCurrentFileName() {
public String getCurrentFileName() {
if (status == Status.PARSING)
return (currentFile != null) ? currentFile.getName() : null;
else
@@ -868,7 +875,7 @@ public class BeatmapParser {
* Returns the progress of file parsing, or -1 if not parsing.
* @return the completion percent [0, 100] or -1
*/
public static int getParserProgress() {
public int getParserProgress() {
if (currentDirectoryIndex == -1 || totalDirectories == -1)
return -1;
@@ -878,7 +885,9 @@ public class BeatmapParser {
/**
* Returns the current parser status.
*/
public static Status getStatus() { return status; }
public Status getStatus() {
return status;
}
/**
* Returns the String object in the database for the given String.
@@ -894,4 +903,5 @@ public class BeatmapParser {
} else
return DBString;
}
}

View File

@@ -18,7 +18,6 @@
package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.db.BeatmapDB;
@@ -210,7 +209,7 @@ public class BeatmapSetList {
BeatmapDB.delete(dir.getName());
// delete the associated directory
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
BeatmapWatchService ws = BeatmapWatchService.get();
if (ws != null)
ws.pause();
try {
@@ -265,9 +264,10 @@ public class BeatmapSetList {
BeatmapDB.delete(file.getParentFile().getName(), file.getName());
// delete the associated file
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
if (ws != null)
BeatmapWatchService ws = BeatmapWatchService.get();
if (ws != null) {
ws.pause();
}
try {
Utils.deleteToTrash(file);
} catch (IOException e) {

View File

@@ -20,12 +20,14 @@ package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.GameData.Grade;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ui.Colors;
import itdelatrisu.opsu.ui.Fonts;
import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
/**
* Node in an BeatmapSetList representing a beatmap set.
@@ -78,14 +80,14 @@ public class BeatmapSetNode {
Beatmap beatmap = beatmapSet.get(expanded ? beatmapIndex : 0);
bg.setAlpha(0.9f);
Color bgColor;
Color textColor = Options.getSkin().getSongSelectInactiveTextColor();
Color textColor = SkinService.skin.getSongSelectInactiveTextColor();
// get drawing parameters
if (expanded) {
x -= bg.getWidth() / 10f;
if (focus) {
bgColor = Color.white;
textColor = Options.getSkin().getSongSelectActiveTextColor();
textColor = SkinService.skin.getSongSelectActiveTextColor();
} else
bgColor = Colors.BLUE_BUTTON;
} else if (beatmapSet.isPlayed())
@@ -105,7 +107,7 @@ public class BeatmapSetNode {
}
// draw text
if (Options.useUnicodeMetadata()) { // load glyphs
if (OPTION_SHOW_UNICODE.state) {
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
Fonts.loadGlyphs(Fonts.DEFAULT, beatmap.artistUnicode);
}

View File

@@ -18,8 +18,6 @@
package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Options;
import java.io.IOException;
import java.nio.file.ClosedWatchServiceException;
import java.nio.file.FileSystems;
@@ -42,7 +40,11 @@ import java.util.concurrent.Executors;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import static yugecin.opsudance.options.Options.*;
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
@@ -88,14 +90,14 @@ public class BeatmapWatchService {
* Creates a new watch service instance (overwriting any previous instance),
* registers the beatmap directory, and starts processing events.
*/
public static void create() {
public static void create(InstanceContainer instanceContainer) {
// close the existing watch service
destroy();
// create a new watch service
try {
ws = new BeatmapWatchService();
ws.register(Options.getBeatmapDir().toPath());
ws = instanceContainer.provide(BeatmapWatchService.class);
ws.register(instanceContainer.provide(Configuration.class).beatmapDir.toPath());
} catch (IOException e) {
Log.error("Could not create watch service", e);
EventBus.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED));
@@ -126,9 +128,14 @@ public class BeatmapWatchService {
}
/**
* Returns the single instance of this class.
* Returns the single instance of this class, or null if not enabled.
*/
public static BeatmapWatchService get() { return ws; }
public static BeatmapWatchService get() {
if (!OPTION_ENABLE_WATCH_SERVICE.state) {
return null;
}
return ws;
}
/** Watch service listener interface. */
public interface BeatmapWatchServiceListener {

View File

@@ -18,8 +18,6 @@
package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.Options;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
@@ -29,20 +27,27 @@ import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
/**
* Unpacker for OSZ (ZIP) archives.
*/
public class OszUnpacker {
@Inject
private Configuration config;
/** The index of the current file being unpacked. */
private static int fileIndex = -1;
private int fileIndex = -1;
/** The total number of files to unpack. */
private static File[] files;
private File[] files;
// This class should not be instantiated.
private OszUnpacker() {}
@Inject
public OszUnpacker() {
}
/**
* Invokes the unpacker for each OSZ archive in a root directory.
@@ -51,11 +56,11 @@ public class OszUnpacker {
* @return an array containing the new (unpacked) directories, or null
* if no OSZs found
*/
public static File[] unpackAllFiles(File root, File dest) {
public File[] unpackAll() {
List<File> dirs = new ArrayList<File>();
// find all OSZ files
files = root.listFiles(new FilenameFilter() {
files = config.oszDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".osz");
@@ -67,13 +72,13 @@ public class OszUnpacker {
}
// unpack OSZs
BeatmapWatchService ws = (Options.isWatchServiceEnabled()) ? BeatmapWatchService.get() : null;
BeatmapWatchService ws = BeatmapWatchService.get();
if (ws != null)
ws.pause();
for (File file : files) {
fileIndex++;
String dirName = file.getName().substring(0, file.getName().lastIndexOf('.'));
File songDir = new File(dest, dirName);
File songDir = new File(config.beatmapDir, dirName);
if (!songDir.isDirectory()) {
songDir.mkdir();
unzip(file, songDir);
@@ -94,7 +99,7 @@ public class OszUnpacker {
* @param file the ZIP archive
* @param dest the destination directory
*/
private static void unzip(File file, File dest) {
private void unzip(File file, File dest) {
try {
ZipFile zipFile = new ZipFile(file);
zipFile.extractAll(dest.getAbsolutePath());
@@ -108,7 +113,7 @@ public class OszUnpacker {
/**
* Returns the name of the current file being unpacked, or null if none.
*/
public static String getCurrentFileName() {
public String getCurrentFileName() {
if (files == null || fileIndex == -1)
return null;
@@ -119,10 +124,11 @@ public class OszUnpacker {
* Returns the progress of file unpacking, or -1 if not unpacking.
* @return the completion percent [0, 100] or -1
*/
public static int getUnpackerProgress() {
public int getUnpackerProgress() {
if (files == null || fileIndex == -1)
return -1;
return (fileIndex + 1) * 100 / files.length;
}
}

View File

@@ -18,7 +18,6 @@
package itdelatrisu.opsu.db;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapParser;
@@ -35,11 +34,13 @@ import java.util.Map;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration;
/**
* Handles connections and queries with the cached beatmap database.
*/
public class BeatmapDB {
/**
* Current database version.
* This value should be changed whenever the database format changes.
@@ -91,12 +92,16 @@ public class BeatmapDB {
// This class should not be instantiated.
private BeatmapDB() {}
private static Configuration config; // TODO
/**
* Initializes the database connection.
*/
public static void init() {
public static void init(Configuration config) {
BeatmapDB.config = config;
// create a database connection
connection = DBController.createConnection(Options.BEATMAP_DB.getPath());
connection = DBController.createConnection(config.BEATMAP_DB.getPath());
if (connection == null)
return;

View File

@@ -19,6 +19,7 @@
package itdelatrisu.opsu.db;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -34,7 +35,7 @@ public class DBController {
/**
* Initializes all databases.
*/
public static void init() {
public static void init(Configuration config) {
// load the sqlite-JDBC driver using the current class loader
try {
Class.forName("org.sqlite.JDBC");
@@ -43,8 +44,8 @@ public class DBController {
}
// initialize the databases
BeatmapDB.init();
ScoreDB.init();
BeatmapDB.init(config);
ScoreDB.init(config);
}
/**

View File

@@ -18,10 +18,10 @@
package itdelatrisu.opsu.db;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.beatmap.Beatmap;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.options.Configuration;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -83,9 +83,9 @@ public class ScoreDB {
/**
* Initializes the database connection.
*/
public static void init() {
public static void init(Configuration config) {
// create a database connection
connection = DBController.createConnection(Options.SCORE_DB.getPath());
connection = DBController.createConnection(config.SCORE_DB.getPath());
if (connection == null)
return;

View File

@@ -19,7 +19,6 @@
package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.downloads.Download.DownloadListener;
@@ -35,13 +34,21 @@ import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
import static yugecin.opsudance.options.Options.*;
/**
* Node containing song data and a Download object.
*/
public class DownloadNode {
@Inject
private Configuration config;
/** The associated Download object. */
private Download download;
@@ -272,7 +279,7 @@ public class DownloadNode {
String url = server.getDownloadURL(beatmapSetID);
if (url == null)
return;
String path = String.format("%s%c%d", Options.getOSZDir(), File.separatorChar, beatmapSetID);
String path = String.format("%s%c%d", config.oszDir, File.separatorChar, beatmapSetID);
String rename = String.format("%d %s - %s.osz", beatmapSetID, artist, title);
Download download = new Download(url, path, rename);
download.setListener(new DownloadListener() {
@@ -287,8 +294,9 @@ public class DownloadNode {
}
});
this.download = download;
if (Options.useUnicodeMetadata()) // load glyphs
if (OPTION_SHOW_UNICODE.state) {
Fonts.loadGlyphs(Fonts.LARGE, getTitle());
}
}
/**
@@ -318,7 +326,7 @@ public class DownloadNode {
* If configured, the Unicode string will be returned instead.
*/
public String getTitle() {
return (Options.useUnicodeMetadata() && titleUnicode != null && !titleUnicode.isEmpty()) ? titleUnicode : title;
return (OPTION_SHOW_UNICODE.state && titleUnicode != null && !titleUnicode.isEmpty()) ? titleUnicode : title;
}
/**
@@ -326,7 +334,7 @@ public class DownloadNode {
* If configured, the Unicode string will be returned instead.
*/
public String getArtist() {
return (Options.useUnicodeMetadata() && artistUnicode != null && !artistUnicode.isEmpty()) ? artistUnicode : artist;
return (OPTION_SHOW_UNICODE.state && artistUnicode != null && !artistUnicode.isEmpty()) ? artistUnicode : artist;
}
/**
@@ -375,7 +383,7 @@ public class DownloadNode {
// text
// TODO: if the title/artist line is too long, shorten it (e.g. add "...") instead of just clipping
if (Options.useUnicodeMetadata()) { // load glyphs
if (OPTION_SHOW_UNICODE.state) {
Fonts.loadGlyphs(Fonts.BOLD, getTitle());
Fonts.loadGlyphs(Fonts.BOLD, getArtist());
}

View File

@@ -18,10 +18,8 @@
package itdelatrisu.opsu.downloads;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.Download.DownloadListener;
import itdelatrisu.opsu.ui.UI;
import java.io.File;
import java.io.IOException;
@@ -39,23 +37,27 @@ import org.newdawn.slick.util.Log;
import org.newdawn.slick.util.ResourceLoader;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.options.Configuration;
/**
* Handles automatic program updates.
*/
public class Updater {
/** The single instance of this class. */
private static Updater updater = new Updater();
@Inject
private Configuration config;
private static Updater updater;
public static Updater get() {
return updater;
}
/** The exit confirmation message. */
public static final String EXIT_CONFIRMATION = "An opsu! update is being downloaded.\nAre you sure you want to quit opsu!?";
/**
* Returns the single instance of this class.
*/
public static Updater get() { return updater; }
/** Updater status. */
public enum Status {
INITIAL (""),
@@ -117,11 +119,10 @@ public class Updater {
return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion();
}
/**
* Constructor.
*/
private Updater() {
@Inject
public Updater() {
status = Status.INITIAL;
updater = this;
}
/**
@@ -144,7 +145,7 @@ public class Updater {
Date date = null;
try {
Properties props = new Properties();
props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE));
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
String build = props.getProperty("build.date");
if (build == null || build.equals("${timestamp}") || build.equals("${maven.build.timestamp}"))
date = new Date();
@@ -206,23 +207,23 @@ public class Updater {
* @throws IOException if an I/O exception occurs
*/
public void checkForUpdates() throws IOException {
if (status != Status.INITIAL || Options.USE_XDG)
if (status != Status.INITIAL || config.USE_XDG)
return;
status = Status.CHECKING;
// get current version
Properties props = new Properties();
props.load(ResourceLoader.getResourceAsStream(Options.VERSION_FILE));
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
if ((currentVersion = getVersion(props)) == null)
return;
// get latest version
String s = null;
try {
s = Utils.readDataFromUrl(new URL(Options.VERSION_REMOTE));
s = Utils.readDataFromUrl(new URL(config.VERSION_REMOTE));
} catch (UnknownHostException e) {
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", Options.VERSION_REMOTE));
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", config.VERSION_REMOTE));
}
if (s == null) {
status = Status.CONNECTION_ERROR;

View File

@@ -34,11 +34,17 @@ import java.util.Date;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
/**
* Download server: http://bloodcat.com/osu/
*/
public class BloodcatServer extends DownloadServer {
@Inject
public InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "Bloodcat";
@@ -54,8 +60,9 @@ public class BloodcatServer extends DownloadServer {
/** Total result count from the last query. */
private int totalResults = -1;
/** Constructor. */
public BloodcatServer() {}
@Inject
public BloodcatServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -82,12 +89,12 @@ public class BloodcatServer extends DownloadServer {
nodes = new DownloadNode[arr.length()];
for (int i = 0; i < nodes.length; i++) {
JSONObject item = arr.getJSONObject(i);
nodes[i] = new DownloadNode(
nodes[i] = instanceContainer.injectFields(new DownloadNode(
item.getInt("id"), formatDate(item.getString("synced")), //"date"
item.getString("title"), item.isNull("titleU") ? null : item.getString("titleU"), //"titleUnicode"
item.getString("artist"), item.isNull("artistU") ? null : item.getString("artistU"), //"artistUnicode"
item.getString("creator")
);
));
}
// store total result count

View File

@@ -30,6 +30,8 @@ import java.net.URLEncoder;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
/**
* Download server: https://osu.hexide.com/
@@ -37,6 +39,10 @@ import yugecin.opsudance.core.errorhandling.ErrorHandler;
* <i>This server went offline in 2016.</i>
*/
public class HexideServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "Hexide";
@@ -58,8 +64,9 @@ public class HexideServer extends DownloadServer {
/** Total result count from the last query. */
private int totalResults = -1;
/** Constructor. */
public HexideServer() {}
@Inject
public HexideServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -117,10 +124,10 @@ public class HexideServer extends DownloadServer {
artist = creator = "?";
}
}
nodes[i] = new DownloadNode(
nodes[i] = instanceContainer.injectFields(new DownloadNode(
item.getInt("ranked_id"), item.getString("date"),
title, null, artist, null, creator
);
));
}
// store total result count

View File

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

View File

@@ -21,6 +21,8 @@ package itdelatrisu.opsu.downloads.servers;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.downloads.DownloadNode;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -36,6 +38,10 @@ import java.util.regex.Pattern;
* Download server: http://osu.uu.gl/
*/
public class MnetworkServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "Mnetwork";
@@ -51,8 +57,9 @@ public class MnetworkServer extends DownloadServer {
/** Beatmap pattern. */
private Pattern BEATMAP_PATTERN = Pattern.compile("^(\\d+) ([^-]+) - (.+)\\.osz$");
/** Constructor. */
public MnetworkServer() {}
@Inject
public MnetworkServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -112,7 +119,7 @@ public class MnetworkServer extends DownloadServer {
if (!m.matches())
continue;
nodeList.add(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, ""));
nodeList.add(instanceContainer.injectFields(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, "")));
}
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);

View File

@@ -36,6 +36,8 @@ import java.util.TimeZone;
import org.json.JSONArray;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
/**
* Download server: http://loli.al/
@@ -43,6 +45,10 @@ import yugecin.opsudance.core.errorhandling.ErrorHandler;
* <i>This server went offline in August 2015.</i>
*/
public class OsuMirrorServer extends DownloadServer {
@Inject
private InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "osu!Mirror";
@@ -67,8 +73,9 @@ public class OsuMirrorServer extends DownloadServer {
/** Lookup table from beatmap set ID -> server download ID. */
private HashMap<Integer, Integer> idTable = new HashMap<Integer, Integer>();
/** Constructor. */
public OsuMirrorServer() {}
@Inject
public OsuMirrorServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -106,12 +113,12 @@ public class OsuMirrorServer extends DownloadServer {
JSONObject item = arr.getJSONObject(i);
int beatmapSetID = item.getInt("OSUSetid");
int serverID = item.getInt("id");
nodes[i] = new DownloadNode(
nodes[i] = instanceContainer.injectFields(new DownloadNode(
beatmapSetID, formatDate(item.getString("ModifyDate")),
item.getString("Title"), null,
item.getString("Artist"), null,
item.getString("Mapper")
);
));
idTable.put(beatmapSetID, serverID);
if (serverID > maxServerID)
maxServerID = serverID;

View File

@@ -34,11 +34,17 @@ import java.util.List;
import org.json.JSONObject;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
/**
* Download server: http://osu.yas-online.net/
*/
public class YaSOnlineServer extends DownloadServer {
@Inject
public InstanceContainer instanceContainer;
/** Server name. */
private static final String SERVER_NAME = "YaS Online";
@@ -66,8 +72,9 @@ public class YaSOnlineServer extends DownloadServer {
/** Max server download ID seen (for approximating total pages). */
private int maxServerID = 0;
/** Constructor. */
public YaSOnlineServer() {}
@Inject
public YaSOnlineServer() {
}
@Override
public String getName() { return SERVER_NAME; }
@@ -176,7 +183,7 @@ public class YaSOnlineServer extends DownloadServer {
if (serverID > maxServerID)
maxServerID = serverID;
nodeList.add(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, ""));
nodeList.add(instanceContainer.injectFields(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, "")));
}
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);

View File

@@ -20,9 +20,7 @@ package itdelatrisu.opsu.objects;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.objects.curves.Vec2f;
@@ -30,16 +28,20 @@ import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.ui.Colors;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import yugecin.opsudance.Dancer;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.render.GameObjectRenderer;
import static yugecin.opsudance.options.Options.*;
/**
* Data type representing a circle object.
*/
public class Circle extends GameObject {
/** The diameter of hit circles. */
public static float diameter;
@Inject
private GameObjectRenderer gameObjectRenderer;
/** The associated HitObject. */
private HitObject hitObject;
@@ -62,18 +64,6 @@ public class Circle extends GameObject {
private int comboColorIndex;
/**
* Initializes the Circle data type with map modifiers, images, and dimensions.
* @param circleDiameter the circle diameter
*/
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));
GameImage.HITCIRCLE_OVERLAY.setImage(GameImage.HITCIRCLE_OVERLAY.getImage().getScaledCopy(diameterInt, diameterInt));
GameImage.APPROACHCIRCLE.setImage(GameImage.APPROACHCIRCLE.getImage().getScaledCopy(diameterInt, diameterInt));
}
/**
* Constructor.
* @param hitObject the associated HitObject
@@ -129,16 +119,10 @@ public class Circle extends GameObject {
float oldAlpha = Colors.WHITE_FADE.a;
Colors.WHITE_FADE.a = color.a = alpha;
if (timeDiff >= 0 && !GameMod.HIDDEN.isActive() && Options.isDrawApproach())
GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
GameImage.HITCIRCLE.getImage().drawCentered(x, y, color);
boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();
if (!overlayAboveNumber)
GameImage.HITCIRCLE_OVERLAY.getImage().drawCentered(x, y, Colors.WHITE_FADE);
data.drawSymbolNumber(hitObject.getComboNumber(), x, y,
GameImage.HITCIRCLE.getImage().getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha);
if (overlayAboveNumber)
GameImage.HITCIRCLE_OVERLAY.getImage().drawCentered(x, y, Colors.WHITE_FADE);
if (timeDiff >= 0) {
gameObjectRenderer.renderApproachCircle(x, y, color, approachScale);
}
gameObjectRenderer.renderHitCircle(x, y, color, hitObject.getComboNumber(), alpha);
Colors.WHITE_FADE.a = oldAlpha;
@@ -172,7 +156,7 @@ public class Circle extends GameObject {
@Override
public boolean mousePressed(int x, int y, int trackPosition) {
double distance = Math.hypot(this.x - x, this.y - y);
if (distance < diameter / 2) {
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
int timeDiff = trackPosition - hitObject.getTime();
int result = hitResult(timeDiff);
@@ -195,7 +179,7 @@ public class Circle extends GameObject {
if (trackPosition > time + hitResultOffset[GameData.HIT_50]) {
if (isAutoMod) {// "auto" mod: catch any missed notes due to lag
data.sendHitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false);
if (Options.isMirror() && GameMod.AUTO.isActive()) {
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
float[] m = Utils.mirrorPoint(x, y);
data.sendHitResult(time, GameData.HIT_300, m[0], m[1], mirrorColor, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false, false);
}
@@ -210,7 +194,7 @@ public class Circle extends GameObject {
else if (isAutoMod) {
if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) {
data.sendHitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false);
if (Options.isMirror() && GameMod.AUTO.isActive()) {
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
float[] m = Utils.mirrorPoint(x, y);
data.sendHitResult(time, GameData.HIT_300, m[0], m[1], mirrorColor, comboEnd, hitObject, HitObjectType.CIRCLE, true, 0, null, false, false);
}

View File

@@ -22,7 +22,6 @@ import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.HitObject;
@@ -37,11 +36,23 @@ import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.Dancer;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
/**
* Data type representing a slider object.
*/
public class Slider extends GameObject {
@Inject
private DisplayContainer displayContainer;
@Inject
private GameObjectRenderer gameObjectRenderer;
/** Slider ball frames. */
private static Image[] sliderBallImages;
@@ -54,9 +65,6 @@ public class Slider extends GameObject {
/** Follow circle radius. */
private static float followRadius;
/** The diameter of hit circles. */
private static float diameter;
/** The associated HitObject. */
private HitObject hitObject;
@@ -116,9 +124,6 @@ public class Slider extends GameObject {
private static final int FOLLOW_EXPAND_TIME = 150;
private static final int FOLLOW_SHRINK_TIME = 100;
/** Container dimensions. */
private static int containerWidth, containerHeight;
private int repeats;
private static Color curveColor = new Color(0, 0, 0, 20);
@@ -134,14 +139,9 @@ public class Slider extends GameObject {
* @param circleDiameter the circle diameter
* @param beatmap the associated beatmap
*/
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;
followRadius = diameter / 2 * 3f;
public static void init(float circleDiameter, Beatmap beatmap) {
followRadius = circleDiameter / 2 * 3f;
int diameterInt = (int) circleDiameter;
// slider ball
if (GameImage.SLIDER_BALL.hasBeatmapSkinImages() ||
@@ -216,11 +216,9 @@ public class Slider extends GameObject {
double fadeinScale = (timeDiff - approachTime + fadeInTime) / (double) fadeInTime;
float alpha = Utils.clamp(1 - (float) fadeinScale, 0, 1);
float decorationsAlpha = Utils.clamp(-2.0f * (float) fadeinScale, 0, 1);
boolean overlayAboveNumber = Options.getSkin().isHitCircleOverlayAboveNumber();
boolean overlayAboveNumber = SkinService.skin.isHitCircleOverlayAboveNumber();
float oldAlpha = Colors.WHITE_FADE.a;
Colors.WHITE_FADE.a = color.a = alpha;
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
Image hitCircle = GameImage.HITCIRCLE.getImage();
Vec2f endPos = curve.pointAt(1);
float oldWhiteFadeAlpha = Colors.WHITE_FADE.a;
@@ -236,11 +234,11 @@ public class Slider extends GameObject {
color.a = alpha;
// end circle (only draw if ball still has to go there)
if (Options.isDrawSliderEndCircles() && isCurveCompletelyDrawn && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) {
if (OPTION_DRAW_SLIDER_ENDCIRCLES.state && isCurveCompletelyDrawn && currentRepeats < repeatCount - (repeatCount % 2 == 0 ? 1 : 0)) {
Color circleColor = new Color(color);
Color overlayColor = new Color(Colors.WHITE_FADE);
if (currentRepeats == 0) {
if (Options.isSliderSnaking()) {
if (OPTION_SNAKING_SLIDERS.state) {
// fade in end circle using decorationsAlpha when snaking sliders are enabled
circleColor.a = overlayColor.a = sliderAlpha * decorationsAlpha;
}
@@ -249,8 +247,8 @@ public class Slider extends GameObject {
circleColor.a = overlayColor.a = sliderAlpha * getCircleAlphaAfterRepeat(trackPosition, true);
}
Vec2f endCircPos = curve.pointAt(1f);
hitCircle.drawCentered(endCircPos.x, endCircPos.y, circleColor);
hitCircleOverlay.drawCentered(endCircPos.x, endCircPos.y, overlayColor);
gameObjectRenderer.renderHitCircleOnly(endCircPos.x, endCircPos.y, circleColor);
gameObjectRenderer.renderHitCircleOverlayOnly(endCircPos.x, endCircPos.y, overlayColor);
}
g.pushTransform();
@@ -267,10 +265,11 @@ public class Slider extends GameObject {
}
// start circle, only draw if ball still has to go there
if (!sliderClickedInitial || (Options.isDrawSliderEndCircles() && currentRepeats < repeatCount - (repeatCount % 2 == 1 ? 1 : 0))) {
hitCircle.drawCentered(x, y, firstCircleColor);
if (!overlayAboveNumber || sliderClickedInitial)
hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor);
if (!sliderClickedInitial || (OPTION_DRAW_SLIDER_ENDCIRCLES.state && currentRepeats < repeatCount - (repeatCount % 2 == 1 ? 1 : 0))) {
gameObjectRenderer.renderHitCircleOnly(x, y, firstCircleColor);
if (!overlayAboveNumber || sliderClickedInitial) {
gameObjectRenderer.renderHitCircleOverlayOnly(x, y, startCircleOverlayColor);
}
}
g.popTransform();
@@ -297,12 +296,11 @@ public class Slider extends GameObject {
// draw combo number and overlay if not initially clicked
if (!sliderClickedInitial) {
data.drawSymbolNumber(hitObject.getComboNumber(), x, y,
hitCircle.getWidth() * 0.40f / data.getDefaultSymbolImage(0).getHeight(), alpha);
gameObjectRenderer.renderComboNumberOnly(x, y, hitObject.getComboNumber(), alpha);
if (overlayAboveNumber) {
startCircleOverlayColor.a = sliderAlpha;
hitCircleOverlay.drawCentered(x, y, startCircleOverlayColor);
gameObjectRenderer.renderHitCircleOverlayOnly(x, y, startCircleOverlayColor);
}
}
@@ -314,7 +312,7 @@ public class Slider extends GameObject {
Image arrow = GameImage.REVERSEARROW.getImage();
arrow = arrow.getScaledCopy((float) (1 + 0.2d * ((trackPosition + sliderTime * tcurRepeat) % 292) / 292));
if (tcurRepeat == 0) {
arrow.setAlpha(Options.isSliderSnaking() ? decorationsAlpha : 1f);
arrow.setAlpha(OPTION_SNAKING_SLIDERS.state ? decorationsAlpha : 1f);
} else {
if (!sliderClickedInitial) {
continue;
@@ -339,8 +337,8 @@ public class Slider extends GameObject {
if (mirror) {
g.rotate(x, y, -180f);
}
if (!GameMod.HIDDEN.isActive() && Options.isDrawApproach()) {
GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
if (!GameMod.HIDDEN.isActive() && OPTION_DANCE_DRAW_APPROACH.state) {
gameObjectRenderer.renderApproachCircle(x, y, color, approachScale);
}
g.popTransform();
} else {
@@ -362,7 +360,7 @@ public class Slider extends GameObject {
Image sliderBallFrame = sliderBallImages[(int) (t * sliderTime * 60 / 1000) % sliderBallImages.length];
float angle = (float) (Math.atan2(c2.y - c.y, c2.x - c.x) * 180 / Math.PI);
sliderBallFrame.setRotation(angle);
if (Options.getSkin().isAllowSliderBallTint()) {
if (SkinService.skin.isAllowSliderBallTint()) {
sliderBallFrame.drawCentered(c.x, c.y, color);
} else {
sliderBallFrame.drawCentered(c.x, c.y);
@@ -373,13 +371,13 @@ public class Slider extends GameObject {
float followCircleScale = 1f + (tickExpandTime / (float) TICK_EXPAND_TIME) * 0.1f;
float followAlpha = 1f;
if (followCircleActive && followExpandTime < FOLLOW_EXPAND_TIME) {
followExpandTime += DisplayContainer.instance.renderDelta;
followExpandTime += displayContainer.renderDelta;
followCircleScale *= 0.5f;
float progress = AnimationEquation.OUT_QUAD.calc((float) followExpandTime / FOLLOW_EXPAND_TIME);
followCircleScale = followCircleScale + followCircleScale * progress;
followAlpha = progress;
} else if (!followCircleActive) {
followExpandTime -= DisplayContainer.instance.renderDelta;
followExpandTime -= displayContainer.renderDelta;
if (followExpandTime > FOLLOW_SHRINK_TIME) {
followExpandTime = FOLLOW_SHRINK_TIME;
}
@@ -394,7 +392,7 @@ public class Slider extends GameObject {
float oldAlphaBlack = Colors.BLACK_ALPHA.a;
Colors.BLACK_ALPHA.a = 0.75f;
g.setColor(Colors.BLACK_ALPHA);
g.fillRect(0, 0, containerWidth, containerHeight);
g.fillRect(0, 0, displayContainer.width, displayContainer.height);
Colors.BLACK_ALPHA.a = oldAlphaBlack;
}
}
@@ -459,27 +457,28 @@ public class Slider extends GameObject {
}
private boolean drawSliderTrack(int trackPosition, double snakingSliderProgress) {
double curveIntervalTo = Options.isSliderSnaking() ? snakingSliderProgress : 1d;
double curveIntervalTo = OPTION_SNAKING_SLIDERS.state ? snakingSliderProgress : 1d;
double curveIntervalFrom = 0d;
if (Options.isShrinkingSliders()) {
if (OPTION_SHRINKING_SLIDERS.state) {
double sliderprogress = (trackPosition - getTime() - ((double) sliderTime * (repeats - 1))) / (double) sliderTime;
if (sliderprogress > 0) {
curveIntervalFrom = sliderprogress;
}
}
int curvelen = curve.getCurvePoints().length;
if (Options.isMergingSliders()) {
if (Options.isShrinkingSliders() && curveIntervalFrom > 0) {
if (repeats % 2 == 0) {
game.spliceSliderCurve(baseSliderFrom + (int) ((1d - curveIntervalFrom) * curvelen) - 1, baseSliderFrom + curvelen);
if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) {
if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0) {
if (hitObject.getRepeatCount() % 2 == 0) {
game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) ((1d - curveIntervalFrom) * curvelen));
} else {
game.setSlidercurveFrom(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1);
game.addMergedSliderPointsToRender(baseSliderFrom + (int) (curveIntervalFrom * curvelen) + 1, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
}
} else {
game.addMergedSliderPointsToRender(baseSliderFrom, baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
}
game.setSlidercurveTo(baseSliderFrom + (int) (curveIntervalTo * curve.getCurvePoints().length));
} else {
if (Options.isShrinkingSliders() && curveIntervalFrom > 0 && repeats % 2 == 0) {
if (Options.isFallbackSliders()) {
if (OPTION_SHRINKING_SLIDERS.state && curveIntervalFrom > 0 && repeats % 2 == 0) {
if (OPTION_FALLBACK_SLIDERS.state) {
curveIntervalTo = 1d - curveIntervalFrom;
} else {
curve.splice((int) ((1d - curveIntervalFrom) * curvelen), curvelen);
@@ -590,7 +589,7 @@ public class Slider extends GameObject {
data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
cx, cy, color, comboEnd, hitObject, type, sliderHeldToEnd,
currentRepeats + 1, curve, sliderHeldToEnd);
if (Options.isMirror() && GameMod.AUTO.isActive()) {
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
float[] m = Utils.mirrorPoint(cx, cy);
data.sendHitResult(hitObject.getTime() + (int) sliderTimeTotal, result,
m[0], m[1], mirrorColor, comboEnd, hitObject, type, sliderHeldToEnd,
@@ -606,7 +605,7 @@ public class Slider extends GameObject {
return false;
double distance = Math.hypot(this.x - x, this.y - y);
if (distance < diameter / 2) {
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
int[] hitResultOffset = game.getHitResultOffsets();
@@ -691,9 +690,6 @@ public class Slider extends GameObject {
// calculate and send slider result
hitResult();
if (Options.isMergingSliders()) {
game.setSlidercurveFrom(baseSliderFrom + curve.getCurvePoints().length + 1);
}
return true;
}

View File

@@ -22,7 +22,6 @@ import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameData.HitObjectType;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
@@ -32,10 +31,10 @@ import itdelatrisu.opsu.states.Game;
import itdelatrisu.opsu.ui.Colors;
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;
import yugecin.opsudance.skinning.SkinService;
/**
* Data type representing a spinner object.
@@ -189,7 +188,7 @@ public class Spinner extends GameObject {
float alpha = Utils.clamp(1 - (float) timeDiff / fadeInTime, 0f, 1f);
// darken screen
if (Options.getSkin().isSpinnerFadePlayfield()) {
if (SkinService.skin.isSpinnerFadePlayfield()) {
float oldAlpha = Colors.BLACK_ALPHA.a;
if (timeDiff > 0)
Colors.BLACK_ALPHA.a *= alpha;

View File

@@ -19,8 +19,6 @@
package itdelatrisu.opsu.objects.curves;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.render.CurveRenderState;
import itdelatrisu.opsu.skins.Skin;
@@ -31,7 +29,9 @@ import org.lwjgl.opengl.GLContext;
import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
/**
* Representation of a curve.
@@ -43,7 +43,7 @@ public abstract class Curve {
protected static float CURVE_POINTS_SEPERATION = 2.5f;
/** The curve border color. */
private static Color borderColor;
protected static Color borderColor;
/** Whether mmsliders are supported. */
private static boolean mmsliderSupported = false;
@@ -58,7 +58,7 @@ public abstract class Curve {
protected float[] sliderX, sliderY;
/** Per-curve render-state used for the new style curve renders. */
private CurveRenderState renderState;
protected CurveRenderState renderState;
/** Points along the curve (set by inherited classes). */
public Vec2f[] curve;
@@ -103,11 +103,10 @@ public abstract class Curve {
ContextCapabilities capabilities = GLContext.getCapabilities();
mmsliderSupported = capabilities.OpenGL30;
if (mmsliderSupported)
if (mmsliderSupported) {
CurveRenderState.init(width, height, circleDiameter);
else {
if (Options.getSkin().getSliderStyle() != Skin.STYLE_PEPPYSLIDER)
Log.warn("New slider style requires OpenGL 3.0.");
} else if (SkinService.skin.getSliderStyle() != Skin.STYLE_PEPPYSLIDER) {
Log.warn("New slider style requires OpenGL 3.0.");
}
}
@@ -134,8 +133,8 @@ public abstract class Curve {
if (curve == null)
return;
// peppysliders
if (Options.isFallbackSliders() || Options.getSkin().getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
if (OPTION_FALLBACK_SLIDERS.state || SkinService.skin.getSliderStyle() == Skin.STYLE_PEPPYSLIDER || !mmsliderSupported) {
// peppysliders
Image hitCircle = GameImage.HITCIRCLE.getImage();
Image hitCircleOverlay = GameImage.HITCIRCLE_OVERLAY.getImage();
for (int i = from; i < to; i++)
@@ -145,19 +144,17 @@ public abstract class Curve {
for (int i = from; i < to; i++)
hitCircle.drawCentered(curve[i].x, curve[i].y, fallbackSliderColor);
fallbackSliderColor.a = a;
}
// mmsliders
else {
} else {
// mmsliders
if (renderState == null)
renderState = new CurveRenderState(hitObject, curve, this instanceof FakeCombinedCurve);
renderState = new CurveRenderState(hitObject, curve, false);
renderState.draw(color, borderColor, from, to);
}
}
public void splice(int from, int to) {
if (renderState == null)
renderState = new CurveRenderState(hitObject, curve, this instanceof FakeCombinedCurve);
renderState = new CurveRenderState(hitObject, curve, false);
renderState.splice(from, to);
}

View File

@@ -18,15 +18,15 @@
package itdelatrisu.opsu.render;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.objects.Circle;
import itdelatrisu.opsu.objects.curves.Vec2f;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Iterator;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.EXTFramebufferObject;
@@ -37,6 +37,9 @@ import org.lwjgl.opengl.GL20;
import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.render.GameObjectRenderer;
import static yugecin.opsudance.options.Options.*;
/**
* Hold the temporary render state that needs to be restored again after the new
@@ -69,6 +72,8 @@ public class CurveRenderState {
private int spliceFrom;
private int spliceTo;
protected List<Integer> pointsToRender;
private final int mirrors;
/**
@@ -96,7 +101,7 @@ public class CurveRenderState {
*/
public static void shutdown() {
staticState.shutdown();
//FrameBufferCache.shutdown();
FrameBufferCache.shutdown();
}
/**
@@ -108,7 +113,7 @@ public class CurveRenderState {
this.hitObject = hitObject;
this.curve = curve;
if (isKnorkeSlider) {
this.mirrors = Options.getMergingSlidersMirrorPool();
this.mirrors = OPTION_MERGING_SLIDERS_MIRROR_POOL.val;
} else {
this.mirrors = 1;
}
@@ -138,6 +143,14 @@ public class CurveRenderState {
lastPointDrawn = -1; // force redraw
}
public void draw(Color color, Color borderColor, List<Integer> pointsToRender) {
lastPointDrawn = -1;
firstPointDrawn = -1;
this.pointsToRender = pointsToRender;
draw(color, borderColor, 0, curve.length);
this.pointsToRender = null;
}
/**
* Draw a curve to the screen that's tinted with `color`. The first time
* this is called this caches the image result of the curve and on subsequent
@@ -303,7 +316,7 @@ public class CurveRenderState {
double diff_x = x - last_x;
double diff_y = y - last_y;
float dist = Utils.distance(x, y, last_x, last_y);
if (dist < Circle.diameter / 8) {
if (dist < GameObjectRenderer.instance.getCircleDiameter() / 8) {
x = (float) (x - diff_x / 2);
y = (float) (y - diff_y / 2);
} else {
@@ -344,11 +357,15 @@ public class CurveRenderState {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
}
int max = mirrors;
if (!Options.isMirror()) {
if (!OPTION_DANCE_MIRROR.state) {
max = 1;
}
for (int i = 0; i < max; i++) {
renderCurve(from, to, i);
if (pointsToRender == null) {
renderCurve(from, to, i);
} else {
renderCurve(i);
}
}
GL11.glFlush();
GL20.glDisableVertexAttribArray(staticState.texCoordLoc);
@@ -370,6 +387,16 @@ public class CurveRenderState {
}
}
private void renderCurve(int mirror) {
Iterator<Integer> iter = pointsToRender.iterator();
while (iter.hasNext()) {
for (int i = iter.next() * 2, end = iter.next() * 2 - 1; i < end; ++i) {
final int index = i + curve.length * 2 * mirror;
GL11.glDrawArrays(GL11.GL_TRIANGLE_FAN, index * (NewCurveStyleState.DIVIDES + 2), NewCurveStyleState.DIVIDES + 2);
}
}
}
/**
* Fill {@code buff} with the texture coordinates and positions for a cone
* that has its center at the coordinates {@code (x1,y1)}.

View File

@@ -18,7 +18,6 @@
package itdelatrisu.opsu.replay;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.beatmap.Beatmap;
@@ -46,7 +45,9 @@ import org.newdawn.slick.util.Log;
import lzma.streams.LzmaOutputStream;
import yugecin.opsudance.core.errorhandling.ErrorHandler;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
/**
* Captures osu! replay data.
@@ -55,6 +56,10 @@ import yugecin.opsudance.events.BubbleNotificationEvent;
* @author smoogipooo (https://github.com/smoogipooo/osu-Replay-API/)
*/
public class Replay {
@Inject
public Configuration config;
/** The associated file. */
private File file;
@@ -272,16 +277,13 @@ public class Replay {
*/
public void save() {
// create replay directory
File dir = Options.getReplayDir();
if (!dir.isDirectory()) {
if (!dir.mkdir()) {
EventBus.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
EventBus.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
// write file in new thread
final File file = new File(dir, String.format("%s.osr", getReplayFilename()));
final File file = new File(config.replayDir, String.format("%s.osr", getReplayFilename()));
new Thread() {
@Override
public void run() {

View File

@@ -18,7 +18,6 @@
package itdelatrisu.opsu.replay;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.beatmap.Beatmap;
import itdelatrisu.opsu.beatmap.BeatmapSetList;
import itdelatrisu.opsu.db.ScoreDB;
@@ -31,32 +30,42 @@ import java.nio.file.StandardCopyOption;
import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.events.EventBus;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.options.Configuration;
/**
* Importer for replay files.
*/
public class ReplayImporter {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
/** The subdirectory (within the replay import directory) to move replays that could not be imported. */
private static final String FAILED_IMPORT_DIR = "failed";
private final String FAILED_IMPORT_DIR = "failed";
/** The index of the current file being imported. */
private static int fileIndex = -1;
private int fileIndex = -1;
/** The total number of replays to import. */
private static File[] files;
private File[] files;
// This class should not be instantiated.
private ReplayImporter() {}
@Inject
public ReplayImporter() {
}
/**
* Invokes the importer for each OSR file in a directory, adding the replay
* Invokes the importer for each OSR file in the replay import dir, adding the replay
* to the score database and moving the file into the replay directory.
* @param dir the directory
*/
public static void importAllReplaysFromDir(File dir) {
public void importAll() {
// find all OSR files
files = dir.listFiles(new FilenameFilter() {
files = config.replayImportDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".osr");
@@ -68,20 +77,17 @@ public class ReplayImporter {
}
// get replay directory
File replayDir = Options.getReplayDir();
if (!replayDir.isDirectory()) {
if (!replayDir.mkdir()) {
String err = String.format("Failed to create replay directory '%s'.", replayDir.getAbsolutePath());
Log.error(err);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath());
Log.error(err);
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
return;
}
// import OSRs
for (File file : files) {
fileIndex++;
Replay r = new Replay(file);
Replay r = instanceContainer.injectFields(new Replay(file));
try {
r.loadHeader();
} catch (IOException e) {
@@ -97,11 +103,11 @@ public class ReplayImporter {
ScoreDB.addScore(r.getScoreData(beatmap));
// move to replay directory
File moveToFile = new File(replayDir, String.format("%s.osr", r.getReplayFilename()));
File moveToFile = new File(config.replayDir, String.format("%s.osr", r.getReplayFilename()));
try {
Files.move(file.toPath(), moveToFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
Log.warn(String.format("Failed to move replay '%s' to the replay directory '%s'.", file, replayDir), e);
Log.warn(String.format("Failed to move replay '%s' to the replay directory '%s'.", file, config.replayDir), e);
}
} else {
moveToFailedDirectory(file);
@@ -119,8 +125,8 @@ public class ReplayImporter {
* Moves a replay file into the failed import directory.
* @param file the file to move
*/
private static void moveToFailedDirectory(File file) {
File dir = new File(Options.getReplayImportDir(), FAILED_IMPORT_DIR);
private void moveToFailedDirectory(File file) {
File dir = new File(config.replayImportDir, FAILED_IMPORT_DIR);
dir.mkdir();
File moveToFile = new File(dir, file.getName());
try {
@@ -133,7 +139,7 @@ public class ReplayImporter {
/**
* Returns the name of the current file being imported, or null if none.
*/
public static String getCurrentFileName() {
public String getCurrentFileName() {
if (files == null || fileIndex == -1)
return null;
@@ -144,10 +150,11 @@ public class ReplayImporter {
* Returns the progress of replay importing, or -1 if not importing.
* @return the completion percent [0, 100] or -1
*/
public static int getLoadingProgress() {
public int getLoadingProgress() {
if (files == null || fileIndex == -1)
return -1;
return (fileIndex + 1) * 100 / files.length;
}
}

View File

@@ -20,9 +20,7 @@ package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;

View File

@@ -19,7 +19,6 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
@@ -60,6 +59,7 @@ import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.options.Configuration;
/**
* Downloads menu.
@@ -72,6 +72,15 @@ public class DownloadsMenu extends ComplexOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
@Inject
private OszUnpacker oszUnpacker;
@Inject
private BeatmapParser beatmapParser;
/** Delay time, in milliseconds, between each search. */
private static final int SEARCH_DELAY = 700;
@@ -82,12 +91,7 @@ public class DownloadsMenu extends ComplexOpsuState {
private static final int MIN_REQUEST_INTERVAL = 300;
/** Available beatmap download servers. */
private static final DownloadServer[] SERVERS = {
new BloodcatServer(),
new YaSOnlineServer(),
new MnetworkServer(),
new MengSkyServer()
};
private final DownloadServer[] SERVERS;
/** The current list of search results. */
private DownloadNode[] resultList;
@@ -276,9 +280,9 @@ public class DownloadsMenu extends ComplexOpsuState {
/** Imports all packed beatmaps. */
private void importBeatmaps() {
// invoke unpacker and parser
File[] dirs = OszUnpacker.unpackAllFiles(Options.getOSZDir(), Options.getBeatmapDir());
File[] dirs = oszUnpacker.unpackAll();
if (dirs != null && dirs.length > 0) {
this.importedNode = BeatmapParser.parseDirectories(dirs);
this.importedNode = beatmapParser.parseDirectories(dirs);
if (importedNode != null) {
// send notification
EventBus.post(new BarNotificationEvent((dirs.length == 1) ? "Imported 1 new song." :
@@ -290,6 +294,16 @@ public class DownloadsMenu extends ComplexOpsuState {
}
}
@Inject
public DownloadsMenu(InstanceContainer instanceContainer) {
SERVERS = new DownloadServer[] {
instanceContainer.provide(BloodcatServer.class),
instanceContainer.provide(YaSOnlineServer.class),
instanceContainer.provide(MnetworkServer.class),
instanceContainer.provide(MengSkyServer.class),
};
}
@Override
public void revalidate() {
super.revalidate();
@@ -665,6 +679,7 @@ public class DownloadsMenu extends ComplexOpsuState {
try {
previewID = -1;
boolean playing = SoundController.playTrack(
config,
url,
Integer.toString(node.getID()),
true,

View File

@@ -18,12 +18,7 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.*;
import itdelatrisu.opsu.audio.HitSound;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
@@ -34,7 +29,6 @@ import itdelatrisu.opsu.beatmap.HitObject;
import itdelatrisu.opsu.beatmap.TimingPoint;
import itdelatrisu.opsu.db.BeatmapDB;
import itdelatrisu.opsu.db.ScoreDB;
import itdelatrisu.opsu.downloads.Updater;
import itdelatrisu.opsu.objects.Circle;
import itdelatrisu.opsu.objects.DummyObject;
import itdelatrisu.opsu.objects.GameObject;
@@ -76,11 +70,17 @@ import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.options.Options;
import yugecin.opsudance.render.GameObjectRenderer;
import yugecin.opsudance.sbv2.MoveStoryboard;
import yugecin.opsudance.skinning.SkinService;
import yugecin.opsudance.ui.OptionsOverlay;
import yugecin.opsudance.ui.StoryboardOverlay;
import yugecin.opsudance.utils.GLHelper;
import static yugecin.opsudance.options.Options.*;
/**
* "Game" state.
*/
@@ -89,6 +89,12 @@ public class Game extends ComplexOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private GameObjectRenderer gameObjectRenderer;
@Inject
private BeatmapParser beatmapParser;
public static boolean isInGame; // TODO delete this when #79 is fixed
/** Game restart states. */
public enum Restart {
@@ -330,7 +336,7 @@ public class Game extends ComplexOpsuState {
super();
mirrorCursor = new Cursor(true);
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.storyboardOptions);
this.optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.storyboardOptions);
this.storyboardOverlay = new StoryboardOverlay(displayContainer, moveStoryboardOverlay, optionsOverlay, this);
storyboardOverlay.show();
moveStoryboardOverlay.show();
@@ -364,7 +370,8 @@ public class Game extends ComplexOpsuState {
scoreboardStarStream.setDurationSpread(700, 100);
// create the associated GameData object
data = new GameData(displayContainer.width, displayContainer.height);
data = instanceContainer.injectFields(new GameData(displayContainer.width, displayContainer.height));
gameObjectRenderer.setGameData(data);
}
@@ -386,17 +393,6 @@ public class Game extends ComplexOpsuState {
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();
@@ -409,7 +405,7 @@ public class Game extends ComplexOpsuState {
int trackPosition = MusicController.getPosition();
if (isLeadIn()) {
trackPosition -= leadInTime - currentMapMusicOffset - Options.getMusicOffset();
trackPosition -= leadInTime - currentMapMusicOffset - OPTION_MUSIC_OFFSET.val;
}
if (pauseTime > -1) // returning from pause screen
trackPosition = pauseTime;
@@ -427,15 +423,15 @@ public class Game extends ComplexOpsuState {
}
// background
if (!Options.isRemoveBG() && GameMod.AUTO.isActive()) {
float dimLevel = Options.getBackgroundDim();
if (!OPTION_DANCE_REMOVE_BG.state && GameMod.AUTO.isActive()) {
float dimLevel = (100 - OPTION_BACKGROUND_DIM.val) / 100f;
if (trackPosition < firstObjectTime) {
if (timeDiff < approachTime)
dimLevel += (1f - dimLevel) * ((float) timeDiff / approachTime);
else
dimLevel = 1f;
}
if (Options.isDefaultPlayfieldForced() || !beatmap.drawBackground(width, height, dimLevel, false)) {
if (OPTION_FORCE_DEFAULT_PLAYFIELD.state || !beatmap.drawBackground(width, height, dimLevel, false)) {
Image playfield = GameImage.PLAYFIELD.getImage();
playfield.setAlpha(dimLevel);
playfield.draw();
@@ -462,7 +458,7 @@ public class Game extends ComplexOpsuState {
if (GameMod.FLASHLIGHT.isActive()) {
// render hit objects offscreen
Graphics.setCurrent(gOffscreen);
int trackPos = (isLeadIn()) ? (leadInTime - Options.getMusicOffset()) * -1 : trackPosition;
int trackPos = (isLeadIn()) ? (leadInTime - OPTION_MUSIC_OFFSET.val) * -1 : trackPosition;
drawHitObjects(gOffscreen, trackPos);
// restore original graphics context
@@ -519,7 +515,7 @@ public class Game extends ComplexOpsuState {
Colors.BLACK_ALPHA.a = a;
}
if (!Options.isHideUI() || !GameMod.AUTO.isActive()) {
if (!OPTION_DANCE_HIDE_UI.state || !GameMod.AUTO.isActive()) {
data.drawGameElements(g, true, objectIndex == 0, 1f);
}
@@ -557,7 +553,7 @@ public class Game extends ComplexOpsuState {
// non-break
else {
if (!GameMod.AUTO.isActive() || !Options.isHideUI()) {
if (!GameMod.AUTO.isActive() || !OPTION_DANCE_HIDE_UI.state) {
// game elements
float gameElementAlpha = 1f;
if (gameFinished) {
@@ -590,7 +586,7 @@ public class Game extends ComplexOpsuState {
}
if (isLeadIn())
trackPosition = (leadInTime - Options.getMusicOffset()) * -1; // render approach circles during song lead-in
trackPosition = (leadInTime - OPTION_MUSIC_OFFSET.val) * -1; // render approach circles during song lead-in
// countdown
if (beatmap.countdown > 0) {
@@ -691,15 +687,15 @@ public class Game extends ComplexOpsuState {
}
}
if (!Options.isHideUI() && GameMod.AUTO.isActive())
if (!OPTION_DANCE_HIDE_UI.state && GameMod.AUTO.isActive())
GameImage.UNRANKED.getImage().drawCentered(width / 2, height * 0.077f);
// draw replay speed button
if (isReplay || (!Options.isHideUI()&& GameMod.AUTO.isActive()))
if (isReplay || (!OPTION_DANCE_HIDE_UI.state&& GameMod.AUTO.isActive()))
playbackSpeed.getButton().draw();
// draw music position bar (for replay seeking)
if (isReplay && Options.isReplaySeekingEnabled()) {
if (isReplay && OPTION_REPLAY_SEEKING.state) {
g.setColor((musicPositionBarContains(displayContainer.mouseX, displayContainer.mouseY)) ? MUSICBAR_HOVER : MUSICBAR_NORMAL);
g.fillRoundRect(musicBarX, musicBarY, musicBarWidth, musicBarHeight, 4);
if (!isLeadIn()) {
@@ -729,7 +725,7 @@ public class Game extends ComplexOpsuState {
displayContainer.cursor.draw(replayKeyPressed);
} else if (GameMod.AUTO.isActive()) {
displayContainer.cursor.draw(autoMousePressed);
if (Options.isMirror() && GameMod.AUTO.isActive()) {
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
mirrorCursor.draw(autoMousePressed);
}
} else if (GameMod.AUTOPILOT.isActive()) {
@@ -876,7 +872,7 @@ public class Game extends ComplexOpsuState {
}
// update in-game scoreboard
if (!Options.isHideUI() && previousScores != null && trackPosition > firstObjectTime) {
if (!OPTION_DANCE_HIDE_UI.state && previousScores != null && trackPosition > firstObjectTime) {
// show scoreboard if selected, and always in break
// hide when game ends
if ((scoreboardVisible || breakTime > 0) && !gameFinished) {
@@ -945,7 +941,7 @@ public class Game extends ComplexOpsuState {
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()) {
if (OPTION_DANCE_MIRROR.state && 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);
@@ -970,7 +966,7 @@ public class Game extends ComplexOpsuState {
boolean complete = objectIndex >= gameObjects.length;
if (GameMod.AUTO.isActive() && complete) {
if (gameObjects.length > 0) {
complete = trackPosition >= gameObjects[gameObjects.length - 1].getEndTime() + Options.getMapEndDelay();
complete = trackPosition >= gameObjects[gameObjects.length - 1].getEndTime() + OPTION_MAP_END_DELAY.val * 100;
}
}
if (complete || (MusicController.trackEnded() && objectIndex > 0)) {
@@ -1115,7 +1111,9 @@ public class Game extends ComplexOpsuState {
objectIndex++; // done, so increment object index
storyboardOverlay.updateIndex(objectIndex);
if (objectIndex >= mirrorTo) {
Options.setMirror(false);
if (OPTION_DANCE_MIRROR.state) {
OPTION_DANCE_MIRROR.toggle();
}
}
} else
break;
@@ -1147,12 +1145,14 @@ public class Game extends ComplexOpsuState {
// game keys
if (!Keyboard.isRepeatEvent()) {
int keys = ReplayFrame.KEY_NONE;
if (key == Options.getGameKeyLeft())
if (key == OPTION_KEY_LEFT.intval) {
keys = ReplayFrame.KEY_K1;
else if (key == Options.getGameKeyRight())
} else if (key == OPTION_KEY_RIGHT.intval) {
keys = ReplayFrame.KEY_K2;
if (keys != ReplayFrame.KEY_NONE)
}
if (keys != ReplayFrame.KEY_NONE) {
gameKeyPressed(keys, mouseX, mouseY, trackPosition);
}
}
switch (key) {
@@ -1195,8 +1195,10 @@ public class Game extends ComplexOpsuState {
break;
}
int position = (pauseTime > -1) ? pauseTime : trackPosition;
if (Options.setCheckpoint(position / 1000)) {
int time = (pauseTime > -1) ? pauseTime : trackPosition;
time /= 1000;
if (0 <= time && time < 3600) {
OPTION_CHECKPOINT.setValue(time);
SoundController.playSound(SoundEffect.MENUCLICK);
EventBus.post(new BarNotificationEvent("Checkpoint saved."));
}
@@ -1205,7 +1207,7 @@ public class Game extends ComplexOpsuState {
case Input.KEY_L:
// load checkpoint
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
int checkpoint = Options.getCheckpoint();
int checkpoint = OPTION_CHECKPOINT.val * 1000;
if (checkpoint == 0 || checkpoint > beatmap.endTime)
break; // invalid checkpoint
loadCheckpoint(checkpoint);
@@ -1227,31 +1229,29 @@ public class Game extends ComplexOpsuState {
UI.changeVolume(-1);
break;
case Input.KEY_TAB:
if (!Options.isHideUI()) {
if (!OPTION_DANCE_HIDE_UI.state) {
scoreboardVisible = !scoreboardVisible;
}
break;
case Input.KEY_M:
if (Options.isMirror()) {
if (OPTION_DANCE_MIRROR.state) {
mirrorTo = objectIndex;
Options.setMirror(false);
} else {
mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
mirrorFrom = objectIndex;
mirrorTo = gameObjects.length;
Options.setMirror(true);
}
OPTION_DANCE_MIRROR.toggle();
break;
case Input.KEY_P:
if (Options.isMirror()) {
if (OPTION_DANCE_MIRROR.state) {
mirrorTo = objectIndex;
Options.setMirror(false);
} else {
mirrorCursor.resetLocations((int) autoMousePosition.x, (int) autoMousePosition.y);
mirrorFrom = objectIndex;
mirrorTo = mirrorFrom + 1;
Options.setMirror(true);
}
OPTION_DANCE_MIRROR.toggle();
break;
case Input.KEY_MINUS:
currentMapMusicOffset += 5;
@@ -1301,7 +1301,7 @@ public class Game extends ComplexOpsuState {
}
// replay seeking
else if (Options.isReplaySeekingEnabled() && !GameMod.AUTO.isActive() && musicPositionBarContains(x, y)) {
else if (OPTION_REPLAY_SEEKING.state && !GameMod.AUTO.isActive() && musicPositionBarContains(x, y)) {
SoundController.mute(true); // mute sounds while seeking
float pos = (y - musicBarY) / musicBarHeight * beatmap.endTime;
MusicController.setPosition((int) pos);
@@ -1310,12 +1310,12 @@ public class Game extends ComplexOpsuState {
return true;
}
if (Options.isMouseDisabled()) {
if (OPTION_DISABLE_MOUSE_BUTTONS.state) {
return true;
}
// mouse wheel: pause the game
if (button == Input.MOUSE_MIDDLE_BUTTON && !Options.isMouseWheelDisabled()) {
if (button == Input.MOUSE_MIDDLE_BUTTON && !OPTION_DISABLE_MOUSE_WHEEL.state) {
int trackPosition = MusicController.getPosition();
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= beatmap.objects[0].getTime()) {
pausedMousePosition = new Vec2f(x, y);
@@ -1389,7 +1389,7 @@ public class Game extends ComplexOpsuState {
return true;
}
if (Options.isMouseDisabled()) {
if (OPTION_DISABLE_MOUSE_BUTTONS.state) {
return true;
}
@@ -1419,12 +1419,14 @@ public class Game extends ComplexOpsuState {
}
int keys = ReplayFrame.KEY_NONE;
if (key == Options.getGameKeyLeft())
if (key == OPTION_KEY_LEFT.intval) {
keys = ReplayFrame.KEY_K1;
else if (key == Options.getGameKeyRight())
} else if (key == OPTION_KEY_RIGHT.intval) {
keys = ReplayFrame.KEY_K2;
if (keys != ReplayFrame.KEY_NONE)
}
if (keys != ReplayFrame.KEY_NONE) {
gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition());
}
return true;
}
@@ -1449,7 +1451,7 @@ public class Game extends ComplexOpsuState {
return true;
}
if (Options.isMouseWheelDisabled()) {
if (OPTION_DISABLE_MOUSE_WHEEL.state) {
return true;
}
@@ -1461,7 +1463,7 @@ public class Game extends ComplexOpsuState {
@Override
public void enter() {
overlays.clear();
if (Options.isEnableSB()) {
if (OPTION_DANCE_ENABLE_SB.state) {
overlays.add(optionsOverlay);
overlays.add(moveStoryboardOverlay);
overlays.add(storyboardOverlay);
@@ -1537,7 +1539,7 @@ public class Game extends ComplexOpsuState {
}
// load epilepsy warning img
epiImgTime = Options.getEpilepsyWarningLength();
epiImgTime = OPTION_EPILEPSY_WARNING.val * 100;
if (epiImgTime > 0) {
epiImg = GameImage.EPILEPSY_WARNING.getImage();
float desWidth = displayContainer.width / 2;
@@ -1584,7 +1586,11 @@ public class Game extends ComplexOpsuState {
}
// initialize object maps
CursorColorOverrides.comboColors = ObjectColorOverrides.comboColors = beatmap.getComboColors();
Color[] comboColors = beatmap.getComboColors();
if (comboColors == null) {
comboColors = SkinService.skin.getComboColors();
}
CursorColorOverrides.comboColors = ObjectColorOverrides.comboColors = comboColors;
for (int i = 0; i < beatmap.objects.length; i++) {
HitObject hitObject = beatmap.objects[i];
@@ -1604,12 +1610,13 @@ public class Game extends ComplexOpsuState {
}
try {
if (hitObject.isCircle())
gameObjects[i] = new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
else if (hitObject.isSlider())
gameObjects[i] = new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
else if (hitObject.isSpinner())
if (hitObject.isCircle()) {
gameObjects[i] = instanceContainer.injectFields(new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
} else if (hitObject.isSlider()) {
gameObjects[i] = instanceContainer.injectFields(new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
} else if (hitObject.isSpinner()) {
gameObjects[i] = new Spinner(hitObject, this, data);
}
} catch (Exception e) {
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
Log.error(message, e);
@@ -1688,7 +1695,7 @@ public class Game extends ComplexOpsuState {
MusicController.pause();
if (gameObjects.length > 0) {
int leadIntime = Options.getMapStartDelay() - gameObjects[0].getTime();
int leadIntime = OPTION_MAP_START_DELAY.val * 100 - gameObjects[0].getTime();
if (leadIntime > 0) {
this.leadInTime = Math.max(leadIntime, this.leadInTime);
}
@@ -1696,7 +1703,10 @@ public class Game extends ComplexOpsuState {
this.leadInTime += epiImgTime;
SoundController.mute(false);
if (Options.isMergingSliders()) {
if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state) {
if (!OPTION_SHRINKING_SLIDERS.state) {
knorkesliders = null; // workaround for issue-130
}
if (knorkesliders == null) {
// let's create knorkesliders
List<Vec2f> curvepoints = new ArrayList<>();
@@ -1721,9 +1731,6 @@ public class Game extends ComplexOpsuState {
}
}
slidercurveFrom = 0;
slidercurveTo = 0;
Dancer.instance.setGameObjects(gameObjects);
storyboardOverlay.setGameObjects(gameObjects);
if (!skippedToCheckpoint) {
@@ -1752,7 +1759,7 @@ public class Game extends ComplexOpsuState {
MusicController.setPitch(1f);
MusicController.resume();
if (Options.isEnableSB()) {
if (OPTION_DANCE_ENABLE_SB.state) {
storyboardOverlay.onLeave();
}
@@ -1779,19 +1786,8 @@ public class Game extends ComplexOpsuState {
GameMod.loadModState(previousMods);
}
private int slidercurveFrom;
private int slidercurveTo;
public void setSlidercurveFrom(int slidercurveFrom) {
this.slidercurveFrom = Math.max(slidercurveFrom, this.slidercurveFrom);
}
public void setSlidercurveTo(int slidercurveTo) {
this.slidercurveTo = Math.max(slidercurveTo, this.slidercurveTo);
}
public void spliceSliderCurve(int from, int to) {
this.knorkesliders.splice(from, to);
public void addMergedSliderPointsToRender(int from, int to) {
knorkesliders.addRange(from, to);
}
/**
@@ -1800,15 +1796,18 @@ public class Game extends ComplexOpsuState {
* @param trackPosition the track position
*/
private void drawHitObjects(Graphics g, int trackPosition) {
gameObjectRenderer.initForFrame();
// draw result objects
if (!Options.isHideObjects()) {
if (!OPTION_DANCE_HIDE_OBJECTS.state) {
data.drawHitResults(trackPosition);
}
if (Options.isMergingSliders() && knorkesliders != null) {
knorkesliders.draw(Color.white, this.slidercurveFrom, this.slidercurveTo);
if (!OPTION_FALLBACK_SLIDERS.state && OPTION_MERGING_SLIDERS.state && knorkesliders != null) {
knorkesliders.draw(Color.white);
knorkesliders.initForFrame();
/*
if (Options.isMirror()) {
if (OPTION_DANCE_MIRROR.state) {
g.pushTransform();
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
knorkesliders.draw(Color.white, this.slidercurveFrom, this.slidercurveTo);
@@ -1833,7 +1832,7 @@ public class Game extends ComplexOpsuState {
stack.add(index);
// draw follow points
if (!Options.isFollowPointEnabled() || loseState || !Options.isHideObjects())
if (!OPTION_SHOW_FOLLOW_POINTS.state || loseState || !OPTION_DANCE_HIDE_OBJECTS.state)
continue;
if (beatmap.objects[index].isSpinner()) {
lastObjectIndex = -1;
@@ -1898,9 +1897,9 @@ public class Game extends ComplexOpsuState {
// normal case
if (!loseState) {
if (!Options.isHideObjects()) {
if (!OPTION_DANCE_HIDE_OBJECTS.state) {
gameObj.draw(g, trackPosition, false);
if (Options.isMirror() && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
g.pushTransform();
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
gameObj.draw(g, trackPosition, true);
@@ -1950,9 +1949,10 @@ public class Game extends ComplexOpsuState {
}
this.beatmap = beatmap;
Display.setTitle(String.format("opsu!dance - %s", beatmap.toString()));
if (beatmap.breaks == null)
if (beatmap.breaks == null) {
BeatmapDB.load(beatmap, BeatmapDB.LOAD_ARRAY);
BeatmapParser.parseHitObjects(beatmap);
}
beatmapParser.parseHitObjects(beatmap);
HitSound.setDefaultSampleSet(beatmap.sampleSet);
}
@@ -2053,22 +2053,26 @@ public class Game extends ComplexOpsuState {
* Set map modifiers.
*/
private void setMapModifiers() {
// fixed difficulty overrides
float circleSize = OPTION_FIXED_CS.val / 10f;
float approachRate = OPTION_FIXED_AR.val / 10f;
float overallDifficulty = OPTION_FIXED_OD.val / 10f;
float HPDrainRate = OPTION_FIXED_HP.val / 10f;
// map-based properties, re-initialized each game
float multiplier = GameMod.getDifficultyMultiplier();
float circleSize = Math.min(beatmap.circleSize * multiplier, 10f);
float approachRate = Math.min(beatmap.approachRate * multiplier, 10f);
float overallDifficulty = Math.min(beatmap.overallDifficulty * multiplier, 10f);
float HPDrainRate = Math.min(beatmap.HPDrainRate * multiplier, 10f);
// fixed difficulty overrides
if (Options.getFixedCS() > 0f)
circleSize = Options.getFixedCS();
if (Options.getFixedAR() > 0f)
approachRate = Options.getFixedAR();
if (Options.getFixedOD() > 0f)
overallDifficulty = Options.getFixedOD();
if (Options.getFixedHP() > 0f)
HPDrainRate = Options.getFixedHP();
if (circleSize == 0f) {
circleSize = Math.min(beatmap.circleSize * multiplier, 10f);
}
if (approachRate == 0f) {
approachRate = Math.min(beatmap.approachRate * multiplier, 10f);
}
if (overallDifficulty == 0f) {
overallDifficulty = Math.min(beatmap.overallDifficulty * multiplier, 10f);
}
if (HPDrainRate == 0f) {
HPDrainRate = Math.min(beatmap.HPDrainRate * multiplier, 10f);
}
// Stack modifier scales with hit object size
// StackOffset = HitObjectRadius / 10
@@ -2077,11 +2081,14 @@ public class Game extends ComplexOpsuState {
HitObject.setStackOffset(diameter * STACK_OFFSET_MODIFIER);
// initialize objects
Circle.init(diameter);
Slider.init(displayContainer, diameter, beatmap);
gameObjectRenderer.initForGame(data, diameter);
Slider.init(gameObjectRenderer.getCircleDiameter(), beatmap);
Spinner.init(displayContainer, overallDifficulty);
Curve.init(displayContainer.width, displayContainer.height, diameter, (Options.isBeatmapSkinIgnored()) ?
Options.getSkin().getSliderBorderColor() : beatmap.getSliderBorderColor());
Color sliderBorderColor = SkinService.skin.getSliderBorderColor();
if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) {
sliderBorderColor = beatmap.getSliderBorderColor();
}
Curve.init(displayContainer.width, displayContainer.height, diameter, sliderBorderColor);
// approachRate (hit object approach time)
if (approachRate < 5)

View File

@@ -19,7 +19,6 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.audio.SoundEffect;
@@ -35,6 +34,8 @@ import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.BaseOpsuState;
import static yugecin.opsudance.options.Options.*;
/**
* "Game Pause/Fail" state.
* <p>
@@ -93,9 +94,9 @@ public class GamePauseMenu extends BaseOpsuState {
// game keys
if (!Keyboard.isRepeatEvent()) {
if (key == Options.getGameKeyLeft()) {
if (key == OPTION_KEY_LEFT.intval) {
mousePressed(Input.MOUSE_LEFT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
} else if (key == Options.getGameKeyRight()) {
} else if (key == OPTION_KEY_RIGHT.intval) {
mousePressed(Input.MOUSE_RIGHT_BUTTON, displayContainer.mouseX, displayContainer.mouseY);
}
}
@@ -166,7 +167,7 @@ public class GamePauseMenu extends BaseOpsuState {
return true;
}
if (Options.isMouseWheelDisabled()) {
if (OPTION_DISABLE_MOUSE_WHEEL.state) {
return true;
}

View File

@@ -19,7 +19,6 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
@@ -54,6 +53,8 @@ import yugecin.opsudance.core.state.OpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.events.BubbleNotificationEvent;
import static yugecin.opsudance.options.Options.*;
/**
* "Main Menu" state.
* <p>
@@ -64,6 +65,9 @@ public class MainMenu extends BaseOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Updater updater;
/** Idle time, in milliseconds, before returning the logo to its original position. */
private static final short LOGO_IDLE_DELAY = 10000;
@@ -232,9 +236,9 @@ public class MainMenu extends BaseOpsuState {
// draw background
Beatmap beatmap = MusicController.getBeatmap();
if (Options.isDynamicBackgroundEnabled() &&
if (OPTION_DYNAMIC_BACKGROUND.state &&
beatmap != null && beatmap.drawBackground(width, height, bgAlpha.getValue(), true))
;
;
else {
Image bg = GameImage.MENU_BG.getImage();
bg.setAlpha(bgAlpha.getValue());
@@ -262,7 +266,7 @@ public class MainMenu extends BaseOpsuState {
}
// draw logo (pulsing)
Color color = Options.isColorMainMenuLogo() ? Cursor.lastCursorColor : Color.white;
Color color = OPTION_COLOR_MAIN_MENU_LOGO.state ? Cursor.lastCursorColor : Color.white;
Float position = MusicController.getBeatProgress();
boolean renderPiece = position != null;
if (position == null) {
@@ -315,12 +319,13 @@ public class MainMenu extends BaseOpsuState {
}
// draw update button
if (Updater.get().showButton()) {
Updater.Status status = Updater.get().getStatus();
if (status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING)
if (updater.showButton()) {
Updater.Status status = updater.getStatus();
if (status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING) {
updateButton.draw();
else if (status == Updater.Status.UPDATE_DOWNLOADED)
} else if (status == Updater.Status.UPDATE_DOWNLOADED) {
restartButton.draw();
}
}
// draw text
@@ -328,11 +333,11 @@ public class MainMenu extends BaseOpsuState {
g.setFont(Fonts.MEDIUM);
float lineHeight = Fonts.MEDIUM.getLineHeight() * 0.925f;
g.drawString(String.format("Loaded %d songs and %d beatmaps.",
BeatmapSetList.get().getMapSetCount(), BeatmapSetList.get().getMapCount()), marginX, topMarginY);
if (MusicController.isTrackLoading())
BeatmapSetList.get().getMapSetCount(), BeatmapSetList.get().getMapCount()), marginX, topMarginY);
if (MusicController.isTrackLoading()) {
g.drawString("Track loading...", marginX, topMarginY + lineHeight);
else if (MusicController.trackExists()) {
if (Options.useUnicodeMetadata()) { // load glyphs
} else if (MusicController.trackExists()) {
if (OPTION_SHOW_UNICODE.state) {
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.titleUnicode);
Fonts.loadGlyphs(Fonts.MEDIUM, beatmap.artistUnicode);
}
@@ -365,7 +370,7 @@ public class MainMenu extends BaseOpsuState {
repoButton.hoverUpdate(delta, mouseX, mouseY);
danceRepoButton.hoverUpdate(delta, mouseX, mouseY);
}
if (Updater.get().showButton()) {
if (updater.showButton()) {
updateButton.autoHoverUpdate(delta, true);
restartButton.autoHoverUpdate(delta, false);
}
@@ -387,7 +392,7 @@ public class MainMenu extends BaseOpsuState {
// fade in background
Beatmap beatmap = MusicController.getBeatmap();
if (!(Options.isDynamicBackgroundEnabled() && beatmap != null && beatmap.isBackgroundLoading()))
if (!(OPTION_DYNAMIC_BACKGROUND.state && beatmap != null && beatmap.isBackgroundLoading()))
bgAlpha.update(delta);
// check measure progress
@@ -445,8 +450,8 @@ public class MainMenu extends BaseOpsuState {
UI.updateTooltip(delta, "Next track", false);
else if (musicPrevious.contains(mouseX, mouseY))
UI.updateTooltip(delta, "Previous track", false);
else if (Updater.get().showButton()) {
Updater.Status status = Updater.get().getStatus();
else if (updater.showButton()) {
Updater.Status status = updater.getStatus();
if (((status == Updater.Status.UPDATE_AVAILABLE || status == Updater.Status.UPDATE_DOWNLOADING) && updateButton.contains(mouseX, mouseY)) ||
(status == Updater.Status.UPDATE_DOWNLOADED && restartButton.contains(mouseX, mouseY)))
UI.updateTooltip(delta, status.getDescription(), true);
@@ -466,10 +471,10 @@ public class MainMenu extends BaseOpsuState {
UI.enter();
if (!enterNotification) {
if (Updater.get().getStatus() == Updater.Status.UPDATE_AVAILABLE) {
if (updater.getStatus() == Updater.Status.UPDATE_AVAILABLE) {
EventBus.post(new BarNotificationEvent("An opsu! update is available."));
enterNotification = true;
} else if (Updater.get().justUpdated()) {
} else if (updater.justUpdated()) {
EventBus.post(new BarNotificationEvent("opsu! is now up to date!"));
enterNotification = true;
}
@@ -547,10 +552,12 @@ public class MainMenu extends BaseOpsuState {
lastMeasureProgress = 0f;
if (!previous.isEmpty()) {
instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
if (Options.isDynamicBackgroundEnabled())
if (OPTION_DYNAMIC_BACKGROUND.state) {
bgAlpha.setTime(0);
} else
}
} else {
MusicController.setPosition(0);
}
EventBus.post(new BarNotificationEvent("<< Previous"));
return true;
}
@@ -565,7 +572,7 @@ public class MainMenu extends BaseOpsuState {
// repository button actions
if (repoButton != null && repoButton.contains(x, y)) {
try {
Desktop.getDesktop().browse(Options.REPOSITORY_URI);
Desktop.getDesktop().browse(config.REPOSITORY_URI);
} catch (UnsupportedOperationException e) {
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
} catch (IOException e) {
@@ -577,7 +584,7 @@ public class MainMenu extends BaseOpsuState {
if (danceRepoButton != null && danceRepoButton.contains(x, y)) {
try {
Desktop.getDesktop().browse(Options.DANCE_REPOSITORY_URI);
Desktop.getDesktop().browse(config.DANCE_REPOSITORY_URI);
} catch (UnsupportedOperationException e) {
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
} catch (IOException e) {
@@ -588,11 +595,11 @@ public class MainMenu extends BaseOpsuState {
}
// update button actions
if (Updater.get().showButton()) {
Updater.Status status = Updater.get().getStatus();
if (updater.showButton()) {
Updater.Status status = updater.getStatus();
if (updateButton.contains(x, y) && status == Updater.Status.UPDATE_AVAILABLE) {
SoundController.playSound(SoundEffect.MENUHIT);
Updater.get().startDownload();
updater.startDownload();
updateButton.removeHoverEffects();
updateButton.setHoverAnimationDuration(800);
updateButton.setHoverAnimationEquation(AnimationEquation.IN_OUT_QUAD);
@@ -600,7 +607,7 @@ public class MainMenu extends BaseOpsuState {
return true;
} else if (restartButton.contains(x, y) && status == Updater.Status.UPDATE_DOWNLOADED) {
SoundController.playSound(SoundEffect.MENUHIT);
Updater.get().prepareUpdate();
updater.prepareUpdate();
displayContainer.exitRequested = true;
return true;
}
@@ -719,8 +726,9 @@ public class MainMenu extends BaseOpsuState {
if (!isTheme && !sameAudio)
previous.add(node.index);
}
if (Options.isDynamicBackgroundEnabled() && !sameAudio && !MusicController.isThemePlaying())
if (OPTION_DYNAMIC_BACKGROUND.state && !sameAudio && !MusicController.isThemePlaying()) {
bgAlpha.setTime(0);
}
}
/**

View File

@@ -1,237 +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 <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.Options.GameOption;
import yugecin.opsudance.ui.OptionsOverlay.OptionTab;
public class OptionsMenu {
public static final OptionTab[] normalOptions = new OptionTab[] {
new OptionTab("GENERAL", null),
new OptionTab("GENERAL", new GameOption[]{
GameOption.DISABLE_UPDATER,
GameOption.ENABLE_WATCH_SERVICE
}),
new OptionTab("LANGUAGE", new GameOption[]{
GameOption.SHOW_UNICODE,
}),
new OptionTab("GRAPHICS", null),
new OptionTab("RENDERER", new GameOption[] {
GameOption.SCREEN_RESOLUTION,
GameOption.ALLOW_LARGER_RESOLUTIONS,
GameOption.FULLSCREEN,
GameOption.TARGET_UPS,
GameOption.TARGET_FPS,
GameOption.SHOW_FPS,
GameOption.USE_FPS_DELTAS,
GameOption.SCREENSHOT_FORMAT,
}),
new OptionTab("SLIDER OPTIONS", new GameOption[]{
GameOption.SNAKING_SLIDERS,
GameOption.FALLBACK_SLIDERS,
GameOption.SHRINKING_SLIDERS,
GameOption.MERGING_SLIDERS,
//GameOption.MERGING_SLIDERS_MIRROR_POOL,
GameOption.DRAW_SLIDER_ENDCIRCLES,
}),
new OptionTab("SKIN", null),
new OptionTab("SKIN", new GameOption[]{
GameOption.SKIN,
GameOption.IGNORE_BEATMAP_SKINS,
GameOption.DYNAMIC_BACKGROUND,
GameOption.LOAD_HD_IMAGES,
GameOption.LOAD_VERBOSE,
GameOption.COLOR_MAIN_MENU_LOGO,
}),
new OptionTab("CURSOR", new GameOption[]{
GameOption.CURSOR_SIZE,
GameOption.NEW_CURSOR,
GameOption.DISABLE_CURSOR
// TODO use combo colour as tint for slider ball option
}),
new OptionTab("AUDIO", null),
new OptionTab("VOLUME", new GameOption[]{
GameOption.MASTER_VOLUME,
GameOption.MUSIC_VOLUME,
GameOption.EFFECT_VOLUME,
GameOption.HITSOUND_VOLUME,
GameOption.SAMPLE_VOLUME_OVERRIDE,
}),
new OptionTab("MISC", new GameOption[] {
GameOption.MUSIC_OFFSET,
GameOption.DISABLE_SOUNDS,
GameOption.ENABLE_THEME_SONG
}),
new OptionTab("GAMEPLAY", null),
new OptionTab("GENERAL", new GameOption[] {
GameOption.BACKGROUND_DIM,
GameOption.FORCE_DEFAULT_PLAYFIELD,
GameOption.SHOW_HIT_LIGHTING,
GameOption.SHOW_HIT_ANIMATIONS,
GameOption.SHOW_COMBO_BURSTS,
GameOption.SHOW_PERFECT_HIT,
GameOption.SHOW_FOLLOW_POINTS,
GameOption.SHOW_HIT_ERROR_BAR,
GameOption.MAP_START_DELAY,
GameOption.MAP_END_DELAY,
GameOption.EPILEPSY_WARNING,
}),
new OptionTab("INPUT", null),
new OptionTab("KEY MAPPING", new GameOption[]{
GameOption.KEY_LEFT,
GameOption.KEY_RIGHT,
}),
new OptionTab("MOUSE", new GameOption[] {
GameOption.DISABLE_MOUSE_WHEEL,
GameOption.DISABLE_MOUSE_BUTTONS,
}),
new OptionTab("CUSTOM", null),
new OptionTab("DIFFICULTY", new GameOption[]{
GameOption.FIXED_CS,
GameOption.FIXED_HP,
GameOption.FIXED_AR,
GameOption.FIXED_OD,
}),
new OptionTab("MISC", new GameOption[] {
GameOption.CHECKPOINT,
GameOption.REPLAY_SEEKING,
}),
new OptionTab("DANCE", null),
new OptionTab("MOVER", 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,
}),
new OptionTab("SPINNER", new GameOption[]{
GameOption.DANCE_SPINNER,
GameOption.DANCE_SPINNER_DELAY,
}),
new OptionTab("SLIDER OPTIONS", new GameOption[]{
GameOption.DANCE_LAZY_SLIDERS,
GameOption.DANCE_CIRLCE_IN_SLOW_SLIDERS,
GameOption.DANCE_CIRLCE_IN_LAZY_SLIDERS,
}),
new OptionTab("CIRCLE MOVEMENTS", new GameOption[]{
GameOption.DANCE_CIRCLE_STREAMS,
GameOption.DANCE_ONLY_CIRCLE_STACKS,
}),
new OptionTab("MIRROR", new GameOption[] {
GameOption.DANCE_MIRROR,
}),
new OptionTab("ADVANCED DISPLAY", null),
new OptionTab("OBJECTS", new GameOption[]{
GameOption.DANCE_DRAW_APPROACH,
GameOption.DANCE_OBJECT_COLOR_OVERRIDE,
GameOption.DANCE_OBJECT_COLOR_OVERRIDE_MIRRORED,
GameOption.DANCE_RGB_OBJECT_INC,
GameOption.DANCE_HIDE_OBJECTS,
}),
new OptionTab("CURSOR", new GameOption[]{
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,
}),
new OptionTab("MISC", new GameOption[] {
GameOption.DANCE_HIDE_UI,
GameOption.DANCE_REMOVE_BG,
GameOption.DANCE_ENABLE_SB,
}),
new OptionTab ("PIPPI", null),
new OptionTab ("GENERAL", new GameOption[]{
GameOption.PIPPI_ENABLE,
GameOption.PIPPI_RADIUS_PERCENT,
}),
new OptionTab ("ANGLE MULTIPLIERS", new GameOption[]{
GameOption.PIPPI_ANGLE_INC_MUL,
GameOption.PIPPI_ANGLE_INC_MUL_SLIDER,
}),
new OptionTab ("MISC", new GameOption[] {
GameOption.PIPPI_SLIDER_FOLLOW_EXPAND,
GameOption.PIPPI_PREVENT_WOBBLY_STREAMS,
})
};
public static final OptionTab[] storyboardOptions = new 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,
}),
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,
})
};
}

View File

@@ -18,13 +18,8 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameData;
import itdelatrisu.opsu.*;
import itdelatrisu.opsu.GameData.Grade;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.GameMod;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.ScoreData;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.MultiClip;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
@@ -74,8 +69,12 @@ import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.inject.InstanceContainer;
import yugecin.opsudance.core.state.ComplexOpsuState;
import yugecin.opsudance.events.BarNotificationEvent;
import yugecin.opsudance.options.Configuration;
import yugecin.opsudance.options.OptionGroups;
import yugecin.opsudance.ui.OptionsOverlay;
import static yugecin.opsudance.options.Options.*;
/**
* "Song Selection" state.
* <p>
@@ -87,6 +86,15 @@ public class SongMenu extends ComplexOpsuState {
@Inject
private InstanceContainer instanceContainer;
@Inject
private Configuration config;
@Inject
private OszUnpacker oszUnpacker;
@Inject
private BeatmapParser beatmapParser;
/** The max number of song buttons to be shown on each screen. */
public static final int MAX_SONG_BUTTONS = 6;
@@ -236,18 +244,11 @@ public class SongMenu extends ComplexOpsuState {
/** Reloads all beatmaps. */
private void reloadBeatmaps() {
File beatmapDir = Options.getBeatmapDir();
if (fullReload) {
// clear the beatmap cache
BeatmapDB.clearDatabase();
// invoke unpacker
OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir);
oszUnpacker.unpackAll();
}
// invoke parser
BeatmapParser.parseAllFiles(beatmapDir);
beatmapParser.parseAll();
}
}
@@ -329,7 +330,7 @@ public class SongMenu extends ComplexOpsuState {
public SongMenu(DisplayContainer displayContainer) {
super();
optionsOverlay = new OptionsOverlay(displayContainer, OptionsMenu.normalOptions);
optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.normalOptions);
overlays.add(optionsOverlay);
}
@@ -599,7 +600,7 @@ public class SongMenu extends ComplexOpsuState {
// song info text
if (songInfo == null) {
songInfo = focusNode.getInfo();
if (Options.useUnicodeMetadata()) { // load glyphs
if (OPTION_SHOW_UNICODE.state) {
Beatmap beatmap = focusNode.getBeatmapSet().get(0);
Fonts.loadGlyphs(Fonts.LARGE, beatmap.titleUnicode);
Fonts.loadGlyphs(Fonts.LARGE, beatmap.artistUnicode);
@@ -740,7 +741,7 @@ public class SongMenu extends ComplexOpsuState {
// initialize song list
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
} else
MusicController.playThemeSong();
MusicController.playThemeSong(config.themeBeatmap);
reloadThread = null;
}
int mouseX = displayContainer.mouseX;
@@ -1028,7 +1029,7 @@ public class SongMenu extends ComplexOpsuState {
SoundController.playSound(SoundEffect.MENUHIT);
if (button != Input.MOUSE_RIGHT_BUTTON) {
// view score
instanceContainer.provide(GameRanking.class).setGameData(new GameData(focusScores[rank], displayContainer.width, displayContainer.height));
instanceContainer.provide(GameRanking.class).setGameData(instanceContainer.injectFields(new GameData(focusScores[rank], displayContainer.width, displayContainer.height)));
displayContainer.switchState(GameRanking.class);
} else {
// score management

View File

@@ -19,7 +19,6 @@
package itdelatrisu.opsu.states;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.audio.MusicController;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapParser;
@@ -28,8 +27,6 @@ import itdelatrisu.opsu.beatmap.OszUnpacker;
import itdelatrisu.opsu.replay.ReplayImporter;
import itdelatrisu.opsu.ui.UI;
import java.io.File;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
@@ -38,6 +35,8 @@ import org.newdawn.slick.util.Log;
import yugecin.opsudance.core.inject.Inject;
import yugecin.opsudance.core.state.BaseOpsuState;
import static yugecin.opsudance.options.Options.*;
/**
* "Splash Screen" state.
* <p>
@@ -48,6 +47,15 @@ public class Splash extends BaseOpsuState {
@Inject
private SongMenu songMenu;
@Inject
private ReplayImporter replayImporter;
@Inject
private OszUnpacker oszUnpacker;
@Inject
private BeatmapParser beatmapParser;
/** Whether or not loading has completed. */
private boolean finished;
@@ -78,18 +86,10 @@ public class Splash extends BaseOpsuState {
thread = new Thread() {
@Override
public void run() {
File beatmapDir = Options.getBeatmapDir();
oszUnpacker.unpackAll();
beatmapParser.parseAll();
replayImporter.importAll();
// unpack all OSZ archives
OszUnpacker.unpackAllFiles(Options.getOSZDir(), beatmapDir);
// parse song directory
BeatmapParser.parseAllFiles(beatmapDir);
// import replays
ReplayImporter.importAllReplaysFromDir(Options.getReplayImportDir());
// load sounds
SoundController.init();
finished = true;
@@ -108,14 +108,14 @@ public class Splash extends BaseOpsuState {
// initialize song list
if (BeatmapSetList.get().size() == 0) {
MusicController.playThemeSong();
MusicController.playThemeSong(config.themeBeatmap);
displayContainer.switchStateInstantly(MainMenu.class);
return;
}
BeatmapSetList.get().init();
if (Options.isThemeSongEnabled()) {
MusicController.playThemeSong();
if (OPTION_ENABLE_THEME_SONG.state) {
MusicController.playThemeSong(config.themeBeatmap);
} else {
songMenu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
}

View File

@@ -19,9 +19,7 @@
package itdelatrisu.opsu.ui;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.skins.Skin;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import java.awt.Point;
@@ -29,6 +27,9 @@ import java.util.LinkedList;
import org.newdawn.slick.*;
import yugecin.opsudance.Dancer;
import yugecin.opsudance.skinning.SkinService;
import static yugecin.opsudance.options.Options.*;
/**
* Updates and draws the cursor.
@@ -66,11 +67,6 @@ public class Cursor {
private boolean isMirrored;
private Color filter;
/**
* Constructor.
*/
public Cursor() {
this(false);
}
@@ -80,29 +76,25 @@ public class Cursor {
this.isMirrored = isMirrored;
}
public Cursor(Color filter) {
this(false);
this.filter = filter;
}
/**
* Draws the cursor.
* @param mousePressed whether or not the mouse button is pressed
*/
public void draw(boolean mousePressed) {
if (Options.isCursorDisabled())
if (OPTION_DISABLE_CURSOR.state) {
return;
}
// determine correct cursor image
Image cursor, cursorMiddle = null, cursorTrail;
boolean beatmapSkinned = GameImage.CURSOR.hasBeatmapSkinImage();
boolean hasMiddle;
Skin skin = Options.getSkin();
if (beatmapSkinned) {
newStyle = true; // osu! currently treats all beatmap cursors as new-style cursors
hasMiddle = GameImage.CURSOR_MIDDLE.hasBeatmapSkinImage();
} else
newStyle = hasMiddle = Options.isNewCursorEnabled();
} else {
newStyle = hasMiddle = OPTION_NEW_CURSOR.state;
}
if (beatmapSkinned || newStyle) {
cursor = GameImage.CURSOR.getImage();
cursorTrail = GameImage.CURSOR_TRAIL.getImage();
@@ -115,7 +107,7 @@ public class Cursor {
// scale cursor
float cursorScaleAnimated = 1f;
if (skin.isCursorExpanded()) {
if (SkinService.skin.isCursorExpanded()) {
if (lastCursorPressState != mousePressed) {
lastCursorPressState = mousePressed;
lastCursorPressTime = System.currentTimeMillis();
@@ -125,7 +117,7 @@ public class Cursor {
Utils.clamp(System.currentTimeMillis() - lastCursorPressTime, 0, CURSOR_SCALE_TIME) / CURSOR_SCALE_TIME);
cursorScaleAnimated = 1f + ((mousePressed) ? cursorScaleChange : CURSOR_SCALE_CHANGE - cursorScaleChange);
}
float cursorScale = cursorScaleAnimated * Options.getCursorScale();
float cursorScale = cursorScaleAnimated * OPTION_CURSOR_SIZE.val / 100f;
if (cursorScale != 1f) {
cursor = cursor.getScaledCopy(cursorScale);
cursorTrail = cursorTrail.getScaledCopy(cursorScale);
@@ -138,19 +130,15 @@ public class Cursor {
lastCursorColor = filter = Dancer.cursorColorOverride.getColor();
}
if (this.filter != null) {
filter = this.filter;
}
// draw a fading trail
float alpha = 0f;
float t = 2f / trail.size();
int cursorTrailWidth = cursorTrail.getWidth(), cursorTrailHeight = cursorTrail.getHeight();
float cursorTrailRotation = (skin.isCursorTrailRotated()) ? cursorAngle : 0;
float cursorTrailRotation = (SkinService.skin.isCursorTrailRotated()) ? cursorAngle : 0;
cursorTrail.startUse();
for (Point p : trail) {
alpha += t;
cursorTrail.setImageColor(filter.r, filter.g, filter.b, alpha * 0.1f);
cursorTrail.setImageColor(filter.r, filter.g, filter.b, alpha);
cursorTrail.drawEmbedded(
p.x - (cursorTrailWidth / 2f), p.y - (cursorTrailHeight / 2f),
cursorTrailWidth, cursorTrailHeight, cursorTrailRotation);
@@ -161,11 +149,13 @@ public class Cursor {
cursorTrail.endUse();
// draw the other components
if (newStyle && skin.isCursorRotated())
if (newStyle && SkinService.skin.isCursorRotated()) {
cursor.setRotation(cursorAngle);
cursor.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter);
if (hasMiddle)
cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, Options.isCursorOnlyColorTrail() ? Color.white : filter);
}
cursor.drawCentered(lastPosition.x, lastPosition.y, OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL.state ? Color.white : filter);
if (hasMiddle) {
cursorMiddle.drawCentered(lastPosition.x, lastPosition.y, OPTION_DANCE_CURSOR_ONLY_COLOR_TRAIL.state ? Color.white : filter);
}
}
/**
@@ -194,7 +184,7 @@ public class Cursor {
removeCount = trail.size() - max;
}
int cursortraillength = Options.getCursorTrailOverride();
int cursortraillength = OPTION_DANCE_CURSOR_TRAIL_OVERRIDE.val;
if (cursortraillength > 20) {
removeCount = trail.size() - cursortraillength;
}

View File

@@ -93,8 +93,9 @@ public class DropdownMenu<E> extends Component {
* @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)
if (index < 0 || items.length <= index) {
throw new IllegalArgumentException();
}
this.selectedItemIndex = index;
}
@@ -252,7 +253,7 @@ public class DropdownMenu<E> extends Component {
return;
}
this.expanded = (idx == -1) && !expanded;
if (idx >= 0 && selectedItemIndex != idx) {
if (0 <= idx && idx < items.length && selectedItemIndex != idx) {
this.selectedItemIndex = idx;
itemSelected(idx, items[selectedItemIndex]);
}

View File

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

View File

@@ -19,7 +19,6 @@
package itdelatrisu.opsu.ui;
import itdelatrisu.opsu.GameImage;
import itdelatrisu.opsu.Options;
import itdelatrisu.opsu.Utils;
import itdelatrisu.opsu.audio.SoundController;
import itdelatrisu.opsu.beatmap.BeatmapParser;
@@ -28,14 +27,14 @@ import itdelatrisu.opsu.replay.ReplayImporter;
import itdelatrisu.opsu.ui.animations.AnimatedValue;
import itdelatrisu.opsu.ui.animations.AnimationEquation;
import org.newdawn.slick.Animation;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import yugecin.opsudance.core.DisplayContainer;
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
import yugecin.opsudance.ui.BackButton;
import static yugecin.opsudance.options.Options.*;
/**
* Draws common UI components.
*/
@@ -70,9 +69,6 @@ public class UI {
*/
public static void init(DisplayContainer displayContainer) {
UI.displayContainer = displayContainer;
}
public static void revalidate() {
backButton = new BackButton(displayContainer);
}
@@ -151,7 +147,7 @@ public class UI {
img.drawCentered(displayContainer.width - img.getWidth() / 2f + xOffset, displayContainer.height / 2f);
float barHeight = img.getHeight() * 0.9f;
float volume = Options.getMasterVolume();
float volume = OPTION_MASTER_VOLUME.val / 100f;
g.setColor(Color.white);
g.fillRoundRect(
displayContainer.width - (img.getWidth() * 0.368f) + xOffset,
@@ -179,7 +175,8 @@ public class UI {
*/
public static void changeVolume(int units) {
final float UNIT_OFFSET = 0.05f;
Options.setMasterVolume(Utils.clamp(Options.getMasterVolume() + (UNIT_OFFSET * units), 0f, 1f));
float volume = Utils.clamp(OPTION_MASTER_VOLUME.val / 100f + (UNIT_OFFSET * units), 0f, 1f);
OPTION_MASTER_VOLUME.setValue((int) (volume * 100f));
if (volumeDisplay == -1)
volumeDisplay = 0;
else if (volumeDisplay >= VOLUME_DISPLAY_TIME / 10)
@@ -196,6 +193,9 @@ public class UI {
int progress;
// determine current action
//
/*
TODO
if ((file = OszUnpacker.getCurrentFileName()) != null) {
text = "Unpacking new beatmaps...";
progress = OszUnpacker.getUnpackerProgress();
@@ -211,12 +211,17 @@ public class UI {
progress = SoundController.getLoadingProgress();
} else
return;
*/
if (true) {
return; // TODO
}
// draw loading info
float marginX = displayContainer.width * 0.02f, marginY = displayContainer.height * 0.02f;
float lineY = displayContainer.height - marginY;
int lineOffsetY = Fonts.MEDIUM.getLineHeight();
if (Options.isLoadVerbose()) {
if (OPTION_LOAD_VERBOSE.state) {
// verbose: display percentages and file names
Fonts.MEDIUM.drawString(
marginX, lineY - (lineOffsetY * 2),