2014-06-30 04:17:04 +02:00
/ *
* opsu ! - an open - source osu ! client
2015-01-16 18:05:44 +01:00
* Copyright ( C ) 2014 , 2015 Jeffrey Han
2014-06-30 04:17:04 +02:00
*
* 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/>.
* /
2015-01-21 05:56:10 +01:00
package itdelatrisu.opsu ;
2014-06-30 04:17:04 +02:00
2015-03-27 01:45:33 +01:00
import itdelatrisu.opsu.audio.MusicController ;
2015-05-17 03:25:19 +02:00
import itdelatrisu.opsu.beatmap.Beatmap ;
2015-05-24 05:48:28 +02:00
import itdelatrisu.opsu.skins.Skin ;
import itdelatrisu.opsu.skins.SkinLoader ;
2015-05-29 07:55:57 +02:00
import itdelatrisu.opsu.ui.UI ;
2015-03-27 01:45:33 +01:00
2014-06-30 04:17:04 +02:00
import java.io.BufferedReader ;
import java.io.BufferedWriter ;
import java.io.File ;
import java.io.FileOutputStream ;
import java.io.FileReader ;
import java.io.IOException ;
import java.io.OutputStreamWriter ;
2015-01-16 19:42:54 +01:00
import java.net.URI ;
2014-06-30 04:17:04 +02:00
import java.text.SimpleDateFormat ;
import java.util.Date ;
2014-07-19 09:31:54 +02:00
import java.util.Locale ;
2014-07-09 04:17:48 +02:00
import java.util.concurrent.TimeUnit ;
2014-06-30 04:17:04 +02:00
2014-07-18 05:58:37 +02:00
import org.lwjgl.input.Keyboard ;
2014-06-30 04:17:04 +02:00
import org.newdawn.slick.GameContainer ;
import org.newdawn.slick.Input ;
import org.newdawn.slick.SlickException ;
2015-05-24 05:48:28 +02:00
import org.newdawn.slick.util.ClasspathLocation ;
import org.newdawn.slick.util.FileSystemLocation ;
2014-06-30 04:17:04 +02:00
import org.newdawn.slick.util.Log ;
2015-05-24 05:48:28 +02:00
import org.newdawn.slick.util.ResourceLoader ;
2014-06-30 04:17:04 +02:00
/ * *
2015-01-21 05:56:10 +01:00
* Handles all user options .
2014-06-30 04:17:04 +02:00
* /
2015-01-21 05:56:10 +01:00
public class Options {
2015-02-13 21:03:17 +01:00
/** The config directory. */
private static final File CONFIG_DIR = getXDGBaseDir ( " XDG_CONFIG_HOME " , " .config " ) ;
/** The data directory. */
private static final File DATA_DIR = getXDGBaseDir ( " XDG_DATA_HOME " , " .local/share " ) ;
2015-01-22 06:44:45 +01:00
/** File for logging errors. */
2015-02-13 21:03:17 +01:00
public static final File LOG_FILE = new File ( CONFIG_DIR , " .opsu.log " ) ;
2014-06-30 04:17:04 +02:00
2015-01-22 06:44:45 +01:00
/** File for storing user options. */
2015-02-13 21:03:17 +01:00
private static final File OPTIONS_FILE = new File ( CONFIG_DIR , " .opsu.cfg " ) ;
2014-07-02 07:53:42 +02:00
2015-05-24 05:48:28 +02:00
/** Beatmap directories (where to search for files). */
2014-06-30 04:17:04 +02:00
private static final String [ ] BEATMAP_DIRS = {
" C:/Program Files (x86)/osu!/Songs/ " ,
" C:/Program Files/osu!/Songs/ " ,
2015-02-13 21:03:17 +01:00
new File ( DATA_DIR , " Songs/ " ) . getPath ( )
2014-06-30 04:17:04 +02:00
} ;
2015-05-24 05:48:28 +02:00
/** Skin directories (where to search for skins). */
private static final String [ ] SKIN_ROOT_DIRS = {
" C:/Program Files (x86)/osu!/Skins/ " ,
" C:/Program Files/osu!/Skins/ " ,
new File ( DATA_DIR , " Skins/ " ) . getPath ( )
} ;
2015-03-05 03:03:06 +01:00
/** Cached beatmap database name. */
2015-05-17 03:25:19 +02:00
public static final File BEATMAP_DB = new File ( DATA_DIR , " .opsu.db " ) ;
2015-03-05 03:03:06 +01:00
2015-01-28 09:47:24 +01:00
/** Score database name. */
2015-02-13 21:03:17 +01:00
public static final File SCORE_DB = new File ( DATA_DIR , " .opsu_scores.db " ) ;
2015-01-28 09:47:24 +01:00
2015-01-22 06:44:45 +01:00
/** Font file name. */
2015-05-15 07:33:53 +02:00
public static final String FONT_NAME = " DroidSansFallback.ttf " ;
2014-08-25 18:47:10 +02:00
2015-03-07 10:17:19 +01:00
/** Version file name. */
public static final String VERSION_FILE = " version " ;
2015-01-22 06:44:45 +01:00
/** Repository address. */
2015-03-07 10:17:19 +01:00
public static final URI REPOSITORY_URI = URI . create ( " https://github.com/itdelatrisu/opsu " ) ;
2015-01-16 19:42:54 +01:00
2015-01-22 06:44:45 +01:00
/** Issue reporting address. */
2015-03-07 10:17:19 +01:00
public static final String ISSUES_URL = " https://github.com/itdelatrisu/opsu/issues/new?title=%s&body=%s " ;
/** Address containing the latest version file. */
public static final String VERSION_REMOTE = " https://raw.githubusercontent.com/itdelatrisu/opsu/gh-pages/version " ;
2015-01-16 19:42:54 +01:00
2015-01-22 06:44:45 +01:00
/** The beatmap directory. */
2014-06-30 04:17:04 +02:00
private static File beatmapDir ;
2015-01-22 06:44:45 +01:00
/** The OSZ archive directory. */
2014-07-06 07:58:44 +02:00
private static File oszDir ;
2015-01-22 06:44:45 +01:00
/** The screenshot directory (created when needed). */
2014-07-18 06:56:37 +02:00
private static File screenshotDir ;
2015-03-12 01:52:51 +01:00
/** The replay directory (created when needed). */
private static File replayDir ;
2015-05-24 05:48:28 +02:00
/** The root skin directory. */
private static File skinRootDir ;
2014-06-30 04:17:04 +02:00
2015-03-03 06:40:51 +01:00
/** Port binding. */
private static int port = 49250 ;
2015-02-13 21:03:17 +01:00
/ * *
* Returns the directory based on the XDG base directory specification for
* Unix - like operating systems , only if the system property " XDG " has been defined .
* @param env the environment variable to check ( XDG_ * _ * )
* @param fallback the fallback directory relative to ~ home
* @return the XDG base directory , or the working directory if unavailable
* /
private static File getXDGBaseDir ( String env , String fallback ) {
if ( System . getProperty ( " XDG " ) = = null )
return new File ( " ./ " ) ;
String OS = System . getProperty ( " os.name " ) . toLowerCase ( ) ;
if ( OS . indexOf ( " nix " ) > = 0 | | OS . indexOf ( " nux " ) > = 0 | | OS . indexOf ( " aix " ) > 0 ) {
String rootPath = System . getenv ( env ) ;
if ( rootPath = = null ) {
String home = System . getProperty ( " user.home " ) ;
if ( home = = null )
return new File ( " ./ " ) ;
rootPath = String . format ( " %s/%s " , home , fallback ) ;
}
File dir = new File ( rootPath , " opsu " ) ;
if ( ! dir . isDirectory ( ) )
dir . mkdir ( ) ;
return dir ;
} else
return new File ( " ./ " ) ;
}
2014-12-21 03:35:18 +01:00
/ * *
* The theme song string :
2015-01-22 06:44:45 +01:00
* { @code filename , title , artist , length ( ms ) }
2014-12-21 03:35:18 +01:00
* /
2015-02-04 09:43:23 +01:00
private static String themeString = " theme.ogg,On the Bach,Jingle Punks,66000 " ;
2014-12-21 03:35:18 +01:00
2015-01-22 06:44:45 +01:00
/** Game options. */
public enum GameOption {
2015-01-11 19:05:32 +01:00
NULL ( null , null ) ,
2015-01-21 01:01:18 +01:00
SCREEN_RESOLUTION ( " Screen Resolution " , " Restart (Ctrl+Shift+F5) to apply resolution changes. " ) {
2015-01-11 19:05:32 +01:00
@Override
2015-01-15 07:52:16 +01:00
public String getValueString ( ) { return resolution . toString ( ) ; }
2015-01-11 19:05:32 +01:00
@Override
public void click ( GameContainer container ) {
do {
2015-01-15 07:52:16 +01:00
resolution = resolution . next ( ) ;
} while ( resolution ! = Resolution . RES_800_600 & &
( container . getScreenWidth ( ) < resolution . getWidth ( ) | |
container . getScreenHeight ( ) < resolution . getHeight ( ) ) ) ;
2015-01-11 19:05:32 +01:00
}
} ,
2015-03-03 06:40:51 +01:00
// FULLSCREEN ("Fullscreen Mode", "Restart to apply changes.", false),
2015-05-24 05:48:28 +02:00
SKIN ( " Skin " , " Restart (Ctrl+Shift+F5) to apply skin changes. " ) {
@Override
public String getValueString ( ) { return skinName ; }
@Override
public void click ( GameContainer container ) {
skinDirIndex = ( skinDirIndex + 1 ) % skinDirs . length ;
skinName = skinDirs [ skinDirIndex ] ;
}
} ,
2015-01-11 19:05:32 +01:00
TARGET_FPS ( " Frame Limiter " , " Higher values may cause high CPU usage. " ) {
@Override
2015-01-15 07:52:16 +01:00
public String getValueString ( ) {
return String . format ( ( getTargetFPS ( ) = = 60 ) ? " %dfps (vsync) " : " %dfps " , getTargetFPS ( ) ) ;
}
2015-01-11 19:05:32 +01:00
@Override
public void click ( GameContainer container ) {
targetFPSindex = ( targetFPSindex + 1 ) % targetFPS . length ;
container . setTargetFrameRate ( getTargetFPS ( ) ) ;
2015-01-15 07:52:16 +01:00
container . setVSync ( getTargetFPS ( ) = = 60 ) ;
2015-01-11 19:05:32 +01:00
}
} ,
2015-03-03 06:40:51 +01:00
MASTER_VOLUME ( " Master Volume " , " Global volume level. " , 35 , 0 , 100 ) {
2015-01-20 20:52:02 +01:00
@Override
public void drag ( GameContainer container , int d ) {
2015-03-03 06:40:51 +01:00
super . drag ( container , d ) ;
2015-01-20 20:52:02 +01:00
container . setMusicVolume ( getMasterVolume ( ) * getMusicVolume ( ) ) ;
}
} ,
2015-03-03 06:40:51 +01:00
MUSIC_VOLUME ( " Music Volume " , " Volume of music. " , 80 , 0 , 100 ) {
2015-01-11 19:05:32 +01:00
@Override
public void drag ( GameContainer container , int d ) {
2015-03-03 06:40:51 +01:00
super . drag ( container , d ) ;
2015-01-20 20:52:02 +01:00
container . setMusicVolume ( getMasterVolume ( ) * getMusicVolume ( ) ) ;
2015-01-11 19:05:32 +01:00
}
} ,
2015-03-03 06:40:51 +01:00
EFFECT_VOLUME ( " Effect Volume " , " Volume of menu and game sounds. " , 70 , 0 , 100 ) ,
HITSOUND_VOLUME ( " Hit Sound Volume " , " Volume of hit sounds. " , 30 , 0 , 100 ) ,
2015-03-20 04:38:19 +01:00
MUSIC_OFFSET ( " Music Offset " , " Adjust this value if hit objects are out of sync. " , - 75 , - 500 , 500 ) {
2015-01-11 19:05:32 +01:00
@Override
2015-03-03 06:40:51 +01:00
public String getValueString ( ) { return String . format ( " %dms " , val ) ; }
2015-01-11 19:05:32 +01:00
} ,
SCREENSHOT_FORMAT ( " Screenshot Format " , " Press F12 to take a screenshot. " ) {
@Override
public String getValueString ( ) { return screenshotFormat [ screenshotFormatIndex ] . toUpperCase ( ) ; }
@Override
public void click ( GameContainer container ) { screenshotFormatIndex = ( screenshotFormatIndex + 1 ) % screenshotFormat . length ; }
} ,
2015-03-03 06:40:51 +01:00
SHOW_FPS ( " Show FPS Counter " , " Show an FPS counter in the bottom-right hand corner. " , true ) ,
SHOW_HIT_LIGHTING ( " Show Hit Lighting " , " Adds an effect behind hit explosions. " , true ) ,
SHOW_COMBO_BURSTS ( " Show Combo Bursts " , " A character image is displayed at combo milestones. " , true ) ,
SHOW_PERFECT_HIT ( " Show Perfect Hits " , " Whether to show perfect hit result bursts (300s, slider ticks). " , true ) ,
2015-03-19 04:23:34 +01:00
SHOW_FOLLOW_POINTS ( " Show Follow Points " , " Whether to show follow points between hit objects. " , true ) ,
2015-03-03 06:40:51 +01:00
NEW_CURSOR ( " Enable New Cursor " , " Use the new cursor style (may cause higher CPU usage). " , true ) {
2015-01-11 19:05:32 +01:00
@Override
public void click ( GameContainer container ) {
2015-03-03 06:40:51 +01:00
super . click ( container ) ;
2015-05-29 10:48:03 +02:00
UI . getCursor ( ) . reset ( ) ;
2015-01-11 19:05:32 +01:00
}
} ,
2015-03-03 06:40:51 +01:00
DYNAMIC_BACKGROUND ( " Enable Dynamic Backgrounds " , " The song background will be used as the main menu background. " , true ) ,
BACKGROUND_DIM ( " Background Dim " , " Percentage to dim the background image during gameplay. " , 50 , 0 , 100 ) ,
FORCE_DEFAULT_PLAYFIELD ( " Force Default Playfield " , " Override the song background with the default playfield background. " , false ) ,
IGNORE_BEATMAP_SKINS ( " Ignore All Beatmap Skins " , " Never use skin element overrides provided by beatmaps. " , false ) ,
FIXED_CS ( " Fixed Circle Size (CS) " , " Determines the size of circles and sliders. " , 0 , 0 , 100 ) {
2015-01-11 19:05:32 +01:00
@Override
2015-03-03 06:40:51 +01:00
public String getValueString ( ) { return ( val = = 0 ) ? " Disabled " : String . format ( " %.1f " , val / 10f ) ; }
2015-01-11 19:05:32 +01:00
} ,
2015-03-03 06:40:51 +01:00
FIXED_HP ( " Fixed HP Drain Rate (HP) " , " Determines the rate at which health decreases. " , 0 , 0 , 100 ) {
2015-01-11 19:05:32 +01:00
@Override
2015-03-03 06:40:51 +01:00
public String getValueString ( ) { return ( val = = 0 ) ? " Disabled " : String . format ( " %.1f " , val / 10f ) ; }
2015-01-11 19:05:32 +01:00
} ,
2015-03-03 06:40:51 +01:00
FIXED_AR ( " Fixed Approach Rate (AR) " , " Determines how long hit circles stay on the screen. " , 0 , 0 , 100 ) {
2015-01-11 19:05:32 +01:00
@Override
2015-03-03 06:40:51 +01:00
public String getValueString ( ) { return ( val = = 0 ) ? " Disabled " : String . format ( " %.1f " , val / 10f ) ; }
2015-01-11 19:05:32 +01:00
} ,
2015-03-03 06:40:51 +01:00
FIXED_OD ( " Fixed Overall Difficulty (OD) " , " Determines the time window for hit results. " , 0 , 0 , 100 ) {
2015-01-11 19:05:32 +01:00
@Override
2015-03-03 06:40:51 +01:00
public String getValueString ( ) { return ( val = = 0 ) ? " Disabled " : String . format ( " %.1f " , val / 10f ) ; }
2015-01-11 19:05:32 +01:00
} ,
2015-03-03 06:40:51 +01:00
LOAD_VERBOSE ( " Show Detailed Loading Progress " , " Display more specific loading information in the splash screen. " , false ) ,
CHECKPOINT ( " Track Checkpoint " , " Press Ctrl+L while playing to load a checkpoint, and Ctrl+S to set one. " , 0 , 0 , 3599 ) {
2015-01-11 19:05:32 +01:00
@Override
public String getValueString ( ) {
2015-03-03 06:40:51 +01:00
return ( val = = 0 ) ? " Disabled " : String . format ( " %02d:%02d " ,
TimeUnit . SECONDS . toMinutes ( val ) ,
val - TimeUnit . MINUTES . toSeconds ( TimeUnit . SECONDS . toMinutes ( val ) ) ) ;
2015-01-11 19:05:32 +01:00
}
} ,
2015-03-03 06:40:51 +01:00
DISABLE_SOUNDS ( " Disable All Sound Effects " , " May resolve Linux sound driver issues. Requires a restart. " ,
( System . getProperty ( " os.name " ) . toLowerCase ( ) . indexOf ( " linux " ) > - 1 ) ) ,
2015-01-11 19:05:32 +01:00
KEY_LEFT ( " Left Game Key " , " Select this option to input a key. " ) {
@Override
public String getValueString ( ) { return Keyboard . getKeyName ( getGameKeyLeft ( ) ) ; }
} ,
KEY_RIGHT ( " Right Game Key " , " Select this option to input a key. " ) {
@Override
public String getValueString ( ) { return Keyboard . getKeyName ( getGameKeyRight ( ) ) ; }
} ,
2015-03-03 06:40:51 +01:00
SHOW_UNICODE ( " Prefer Non-English Metadata " , " Where available, song titles will be shown in their native language. " , false ) {
2015-01-11 19:05:32 +01:00
@Override
public void click ( GameContainer container ) {
2015-03-03 06:40:51 +01:00
super . click ( container ) ;
if ( bool ) {
2015-01-11 19:05:32 +01:00
try {
Utils . FONT_LARGE . loadGlyphs ( ) ;
Utils . FONT_MEDIUM . loadGlyphs ( ) ;
Utils . FONT_DEFAULT . loadGlyphs ( ) ;
} catch ( SlickException e ) {
Log . warn ( " Failed to load glyphs. " , e ) ;
}
}
}
} ,
2015-03-03 06:40:51 +01:00
ENABLE_THEME_SONG ( " Enable Theme Song " , " Whether to play the theme song upon starting opsu! " , true ) ,
SHOW_HIT_ERROR_BAR ( " Show Hit Error Bar " , " Shows precisely how accurate you were with each hit. " , false ) ,
2015-06-11 19:42:57 +02:00
LOAD_HD_IMAGES ( " Load HD Images " , String . format ( " Loads HD (%s) images when available. Increases memory usage and loading times. " , GameImage . HD_SUFFIX ) , true ) ,
2015-03-03 06:40:51 +01:00
DISABLE_MOUSE_WHEEL ( " Disable mouse wheel in play mode " , " During play, you can use the mouse wheel to adjust the volume and pause the game. \ nThis will disable that functionality. " , false ) ,
DISABLE_MOUSE_BUTTONS ( " Disable mouse buttons in play mode " , " This option will disable all mouse buttons. \ nSpecifically for people who use their keyboard to click. " , false ) ;
2015-01-11 19:05:32 +01:00
2015-01-22 06:44:45 +01:00
/** Option name. */
2015-01-11 19:05:32 +01:00
private String name ;
2015-01-22 06:44:45 +01:00
/** Option description. */
2015-01-11 19:05:32 +01:00
private String description ;
2015-03-03 06:40:51 +01:00
/** The boolean value for the option (if applicable). */
protected boolean bool ;
/** The integer value for the option (if applicable). */
protected int val ;
/** The upper and lower bounds on the integer value (if applicable). */
private int max , min ;
/** Whether or not this is a numeric option. */
private boolean isNumeric ;
2015-01-11 19:05:32 +01:00
/ * *
* Constructor .
* @param name the option name
* @param description the option description
* /
GameOption ( String name , String description ) {
this . name = name ;
this . description = description ;
}
2015-03-03 06:40:51 +01:00
/ * *
* Constructor .
* @param name the option name
* @param description the option description
* @param value the default boolean value
* /
GameOption ( String name , String description , boolean value ) {
this ( name , description ) ;
this . bool = value ;
this . isNumeric = false ;
}
/ * *
* Constructor .
* @param name the option name
* @param description the option description
* @param value the default integer value
* /
GameOption ( String name , String description , int value , int min , int max ) {
this ( name , description ) ;
this . val = value ;
this . min = min ;
this . max = max ;
this . isNumeric = true ;
}
2015-01-11 19:05:32 +01:00
/ * *
* Returns the option name .
* @return the name string
* /
public String getName ( ) { return name ; }
/ * *
2015-03-03 06:40:51 +01:00
* Returns the option description .
2015-01-11 19:05:32 +01:00
* @return the description string
* /
public String getDescription ( ) { return description ; }
2015-03-03 06:40:51 +01:00
/ * *
* Returns the boolean value for the option , if applicable .
* @return the boolean value
* /
public boolean getBooleanValue ( ) { return bool ; }
/ * *
* Returns the integer value for the option , if applicable .
* @return the integer value
* /
public int getIntegerValue ( ) { return val ; }
/ * *
* Sets the boolean value for the option .
* @param value the new boolean value
* /
public void setValue ( boolean value ) { this . bool = value ; }
/ * *
* Sets the integer value for the option .
* @param value the new integer value
* /
public void setValue ( int value ) { this . val = value ; }
2015-01-11 19:05:32 +01:00
/ * *
* Returns the value of the option as a string ( via override ) .
2015-03-03 06:40:51 +01:00
* < p >
* By default , this returns " {@code val}% " if this is an numeric option ,
* or " Yes " or " No " based on the { @code bool } field otherwise .
2015-01-11 19:05:32 +01:00
* @return the value string
* /
2015-03-03 06:40:51 +01:00
public String getValueString ( ) {
if ( isNumeric )
return String . format ( " %d%% " , val ) ;
else
return ( bool ) ? " Yes " : " No " ;
}
2015-01-11 19:05:32 +01:00
/ * *
* Processes a mouse click action ( via override ) .
2015-03-03 06:40:51 +01:00
* < p >
* By default , this inverts the current { @code bool } field .
2015-01-11 19:05:32 +01:00
* @param container the game container
* /
2015-03-03 06:40:51 +01:00
public void click ( GameContainer container ) { bool = ! bool ; }
2015-01-11 19:05:32 +01:00
/ * *
* Processes a mouse drag action ( via override ) .
2015-03-03 06:40:51 +01:00
* < p >
* By default , if this is a numeric option , the { @code val } field will
* be shifted by { @code d } within the given bounds .
2015-01-11 19:05:32 +01:00
* @param container the game container
* @param d the dragged distance ( modified by multiplier )
* /
2015-03-03 06:40:51 +01:00
public void drag ( GameContainer container , int d ) {
if ( isNumeric )
val = Utils . getBoundedValue ( val , d , min , max ) ;
}
2014-07-03 00:24:19 +02:00
} ;
2015-01-22 06:44:45 +01:00
/** Screen resolutions. */
2015-01-15 07:52:16 +01:00
private enum Resolution {
RES_800_600 ( 800 , 600 ) ,
RES_1024_600 ( 1024 , 600 ) ,
RES_1024_768 ( 1024 , 768 ) ,
2015-02-14 20:10:47 +01:00
RES_1280_720 ( 1280 , 720 ) ,
2015-01-15 07:52:16 +01:00
RES_1280_800 ( 1280 , 800 ) ,
RES_1280_960 ( 1280 , 960 ) ,
2015-02-14 20:10:47 +01:00
RES_1280_1024 ( 1280 , 1024 ) ,
2015-01-15 07:52:16 +01:00
RES_1366_768 ( 1366 , 768 ) ,
RES_1440_900 ( 1440 , 900 ) ,
RES_1600_900 ( 1600 , 900 ) ,
2015-02-10 03:40:38 +01:00
RES_1600_1200 ( 1600 , 1200 ) ,
2015-02-10 05:22:58 +01:00
RES_1680_1050 ( 1680 , 1050 ) ,
2015-01-15 07:52:16 +01:00
RES_1920_1080 ( 1920 , 1080 ) ,
RES_1920_1200 ( 1920 , 1200 ) ,
RES_2560_1440 ( 2560 , 1440 ) ,
2015-02-14 20:10:47 +01:00
RES_2560_1600 ( 2560 , 1600 ) ,
RES_3840_2160 ( 3840 , 2160 ) ;
2015-01-15 07:52:16 +01:00
2015-01-22 06:44:45 +01:00
/** Screen dimensions. */
2015-01-15 07:52:16 +01:00
private int width , height ;
2015-01-22 06:44:45 +01:00
/** Enum values. */
2015-01-15 07:52:16 +01:00
private static Resolution [ ] values = Resolution . values ( ) ;
/ * *
* Constructor .
* @param width the screen width
* @param height the screen height
* /
Resolution ( int width , int height ) {
this . width = width ;
this . height = height ;
}
/ * *
* Returns the screen width .
* /
public int getWidth ( ) { return width ; }
/ * *
* Returns the screen height .
* /
public int getHeight ( ) { return height ; }
/ * *
* Returns the next ( larger ) Resolution .
* /
public Resolution next ( ) { return values [ ( this . ordinal ( ) + 1 ) % values . length ] ; }
@Override
public String toString ( ) { return String . format ( " %sx%s " , width , height ) ; }
}
2014-06-30 04:17:04 +02:00
2015-01-22 06:44:45 +01:00
/** Current screen resolution. */
2015-01-16 19:42:54 +01:00
private static Resolution resolution = Resolution . RES_1024_768 ;
2014-06-30 04:17:04 +02:00
2015-05-24 05:48:28 +02:00
/** The available skin directories. */
private static String [ ] skinDirs ;
/** The index in the skinDirs array. */
private static int skinDirIndex = 0 ;
/** The name of the skin. */
private static String skinName = " Default " ;
/** The current skin. */
private static Skin skin ;
2015-01-22 06:44:45 +01:00
/** Frame limiters. */
2014-06-30 04:17:04 +02:00
private static final int [ ] targetFPS = { 60 , 120 , 240 } ;
2015-01-16 21:44:13 +01:00
2015-01-22 06:44:45 +01:00
/** Index in targetFPS[] array. */
2014-06-30 04:17:04 +02:00
private static int targetFPSindex = 0 ;
2015-01-22 06:44:45 +01:00
/** Screenshot file formats. */
2014-06-30 04:17:04 +02:00
private static String [ ] screenshotFormat = { " png " , " jpg " , " bmp " } ;
2015-01-22 06:44:45 +01:00
/** Index in screenshotFormat[] array. */
2014-06-30 04:17:04 +02:00
private static int screenshotFormatIndex = 0 ;
2015-01-22 06:44:45 +01:00
/** Left and right game keys. */
2014-07-18 05:58:37 +02:00
private static int
keyLeft = Keyboard . KEY_NONE ,
keyRight = Keyboard . KEY_NONE ;
2015-01-21 05:56:10 +01:00
// This class should not be instantiated.
private Options ( ) { }
2014-06-30 04:17:04 +02:00
/ * *
2014-07-02 01:32:03 +02:00
* Returns the target frame rate .
* @return the target FPS
2014-06-30 04:17:04 +02:00
* /
2014-07-02 01:32:03 +02:00
public static int getTargetFPS ( ) { return targetFPS [ targetFPSindex ] ; }
2014-06-30 04:17:04 +02:00
2015-03-05 20:40:57 +01:00
/ * *
* Sets the target frame rate to the next available option , and sends a
* bar notification about the action .
* @param container the game container
* /
public static void setNextFPS ( GameContainer container ) {
GameOption . TARGET_FPS . click ( container ) ;
UI . sendBarNotification ( String . format ( " Frame limiter: %s " , GameOption . TARGET_FPS . getValueString ( ) ) ) ;
}
2015-01-20 20:52:02 +01:00
/ * *
* Returns the master volume level .
* @return the volume [ 0 , 1 ]
* /
2015-03-03 06:40:51 +01:00
public static float getMasterVolume ( ) { return GameOption . MASTER_VOLUME . getIntegerValue ( ) / 100f ; }
2015-01-20 20:52:02 +01:00
/ * *
* Sets the master volume level ( if within valid range ) .
* @param container the game container
* @param volume the volume [ 0 , 1 ]
* /
public static void setMasterVolume ( GameContainer container , float volume ) {
if ( volume > = 0f & & volume < = 1f ) {
2015-03-03 06:40:51 +01:00
GameOption . MASTER_VOLUME . setValue ( ( int ) ( volume * 100f ) ) ;
2015-03-27 01:45:33 +01:00
MusicController . setVolume ( getMasterVolume ( ) * getMusicVolume ( ) ) ;
2015-01-20 20:52:02 +01:00
}
}
2014-06-30 04:17:04 +02:00
/ * *
* Returns the default music volume .
* @return the volume [ 0 , 1 ]
* /
2015-03-03 06:40:51 +01:00
public static float getMusicVolume ( ) { return GameOption . MUSIC_VOLUME . getIntegerValue ( ) / 100f ; }
2014-06-30 04:17:04 +02:00
2014-07-01 07:14:03 +02:00
/ * *
* Returns the default sound effect volume .
* @return the sound volume [ 0 , 1 ]
* /
2015-03-03 06:40:51 +01:00
public static float getEffectVolume ( ) { return GameOption . EFFECT_VOLUME . getIntegerValue ( ) / 100f ; }
2014-07-01 07:14:03 +02:00
2014-07-03 00:24:19 +02:00
/ * *
2014-07-09 19:36:42 +02:00
* Returns the default hit sound volume .
* @return the hit sound volume [ 0 , 1 ]
2014-07-03 00:24:19 +02:00
* /
2015-03-03 06:40:51 +01:00
public static float getHitSoundVolume ( ) { return GameOption . HITSOUND_VOLUME . getIntegerValue ( ) / 100f ; }
2014-07-03 00:24:19 +02:00
2014-06-30 04:17:04 +02:00
/ * *
* Returns the music offset time .
* @return the offset ( in milliseconds )
* /
2015-03-03 06:40:51 +01:00
public static int getMusicOffset ( ) { return GameOption . MUSIC_OFFSET . getIntegerValue ( ) ; }
2014-06-30 04:17:04 +02:00
/ * *
2014-07-02 01:32:03 +02:00
* Returns the screenshot file format .
* @return the file extension ( " png " , " jpg " , " bmp " )
2014-06-30 04:17:04 +02:00
* /
2014-07-02 01:32:03 +02:00
public static String getScreenshotFormat ( ) { return screenshotFormat [ screenshotFormatIndex ] ; }
2014-06-30 04:17:04 +02:00
/ * *
2014-07-11 02:35:07 +02:00
* Sets the container size and makes the window borderless if the container
* size is identical to the screen resolution .
* < p >
* If the configured resolution is larger than the screen size , the smallest
* available resolution will be used .
* @param app the game container
* /
2015-01-22 00:56:53 +01:00
public static void setDisplayMode ( Container app ) {
2014-07-11 02:35:07 +02:00
int screenWidth = app . getScreenWidth ( ) ;
int screenHeight = app . getScreenHeight ( ) ;
2015-01-18 21:26:00 +01:00
2015-01-15 07:52:16 +01:00
// check for larger-than-screen dimensions
if ( screenWidth < resolution . getWidth ( ) | | screenHeight < resolution . getHeight ( ) )
resolution = Resolution . RES_800_600 ;
2015-01-22 00:56:53 +01:00
try {
app . setDisplayMode ( resolution . getWidth ( ) , resolution . getHeight ( ) , false ) ;
} catch ( SlickException e ) {
ErrorHandler . error ( " Failed to set display mode. " , e , true ) ;
}
2015-01-15 07:52:16 +01:00
// set borderless window if dimensions match screen size
2015-01-21 01:01:18 +01:00
boolean borderless = ( screenWidth = = resolution . getWidth ( ) & & screenHeight = = resolution . getHeight ( ) ) ;
System . setProperty ( " org.lwjgl.opengl.Window.undecorated " , Boolean . toString ( borderless ) ) ;
2014-07-11 02:35:07 +02:00
}
2014-06-30 04:17:04 +02:00
// /**
// * Returns whether or not fullscreen mode is enabled.
// * @return true if enabled
// */
// public static boolean isFullscreen() { return fullscreen; }
2014-07-02 01:32:03 +02:00
/ * *
* Returns whether or not the FPS counter display is enabled .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isFPSCounterEnabled ( ) { return GameOption . SHOW_FPS . getBooleanValue ( ) ; }
2014-07-02 01:32:03 +02:00
2014-06-30 04:17:04 +02:00
/ * *
* Returns whether or not hit lighting effects are enabled .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isHitLightingEnabled ( ) { return GameOption . SHOW_HIT_LIGHTING . getBooleanValue ( ) ; }
2014-06-30 04:17:04 +02:00
/ * *
* Returns whether or not combo burst effects are enabled .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isComboBurstEnabled ( ) { return GameOption . SHOW_COMBO_BURSTS . getBooleanValue ( ) ; }
2014-06-30 04:17:04 +02:00
2014-06-30 18:37:37 +02:00
/ * *
* Returns the port number to bind to .
* @return the port
* /
2014-07-02 01:32:03 +02:00
public static int getPort ( ) { return port ; }
/ * *
* Returns whether or not the new cursor type is enabled .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isNewCursorEnabled ( ) { return GameOption . NEW_CURSOR . getBooleanValue ( ) ; }
2014-06-30 18:37:37 +02:00
2014-07-02 09:02:11 +02:00
/ * *
* Returns whether or not the main menu background should be the current track image .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isDynamicBackgroundEnabled ( ) { return GameOption . DYNAMIC_BACKGROUND . getBooleanValue ( ) ; }
2014-07-02 09:02:11 +02:00
2014-07-03 00:24:19 +02:00
/ * *
* Returns whether or not to show perfect hit result bursts .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isPerfectHitBurstEnabled ( ) { return GameOption . SHOW_PERFECT_HIT . getBooleanValue ( ) ; }
2014-07-03 00:24:19 +02:00
2015-03-19 04:23:34 +01:00
/ * *
* Returns whether or not to show follow points .
* @return true if enabled
* /
public static boolean isFollowPointEnabled ( ) { return GameOption . SHOW_FOLLOW_POINTS . getBooleanValue ( ) ; }
2014-07-03 00:24:19 +02:00
/ * *
* Returns the background dim level .
* @return the alpha level [ 0 , 1 ]
* /
2015-03-03 06:40:51 +01:00
public static float getBackgroundDim ( ) { return ( 100 - GameOption . BACKGROUND_DIM . getIntegerValue ( ) ) / 100f ; }
2014-07-03 00:24:19 +02:00
2014-07-03 07:05:23 +02:00
/ * *
* Returns whether or not to override the song background with the default playfield background .
* @return true if forced
* /
2015-03-03 06:40:51 +01:00
public static boolean isDefaultPlayfieldForced ( ) { return GameOption . FORCE_DEFAULT_PLAYFIELD . getBooleanValue ( ) ; }
2014-07-03 07:05:23 +02:00
2014-07-04 22:41:52 +02:00
/ * *
* Returns whether or not beatmap skins are ignored .
* @return true if ignored
* /
2015-03-03 06:40:51 +01:00
public static boolean isBeatmapSkinIgnored ( ) { return GameOption . IGNORE_BEATMAP_SKINS . getBooleanValue ( ) ; }
2014-07-04 22:41:52 +02:00
2014-07-05 07:24:01 +02:00
/ * *
* Returns the fixed circle size override , if any .
2015-03-03 06:40:51 +01:00
* @return the CS value ( 0 , 10 ] , 0f if disabled
2014-07-05 07:24:01 +02:00
* /
2015-03-03 06:40:51 +01:00
public static float getFixedCS ( ) { return GameOption . FIXED_CS . getIntegerValue ( ) / 10f ; }
2014-07-05 07:24:01 +02:00
/ * *
* Returns the fixed HP drain rate override , if any .
2015-03-03 06:40:51 +01:00
* @return the HP value ( 0 , 10 ] , 0f if disabled
2014-07-05 07:24:01 +02:00
* /
2015-03-03 06:40:51 +01:00
public static float getFixedHP ( ) { return GameOption . FIXED_HP . getIntegerValue ( ) / 10f ; }
2014-07-05 07:24:01 +02:00
/ * *
* Returns the fixed approach rate override , if any .
2015-03-03 06:40:51 +01:00
* @return the AR value ( 0 , 10 ] , 0f if disabled
2014-07-05 07:24:01 +02:00
* /
2015-03-03 06:40:51 +01:00
public static float getFixedAR ( ) { return GameOption . FIXED_AR . getIntegerValue ( ) / 10f ; }
2014-07-05 07:24:01 +02:00
/ * *
* Returns the fixed overall difficulty override , if any .
2015-03-03 06:40:51 +01:00
* @return the OD value ( 0 , 10 ] , 0f if disabled
2014-07-05 07:24:01 +02:00
* /
2015-03-03 06:40:51 +01:00
public static float getFixedOD ( ) { return GameOption . FIXED_OD . getIntegerValue ( ) / 10f ; }
2014-07-05 07:24:01 +02:00
2014-07-06 03:00:52 +02:00
/ * *
* Returns whether or not to render loading text in the splash screen .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isLoadVerbose ( ) { return GameOption . LOAD_VERBOSE . getBooleanValue ( ) ; }
2014-07-06 03:00:52 +02:00
2014-07-09 04:17:48 +02:00
/ * *
* Returns the track checkpoint time .
* @return the checkpoint time ( in ms )
* /
2015-03-03 06:40:51 +01:00
public static int getCheckpoint ( ) { return GameOption . CHECKPOINT . getIntegerValue ( ) * 1000 ; }
2014-07-09 04:17:48 +02:00
2014-07-11 04:01:39 +02:00
/ * *
* Returns whether or not all sound effects are disabled .
* @return true if disabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isSoundDisabled ( ) { return GameOption . DISABLE_SOUNDS . getBooleanValue ( ) ; }
2014-07-11 04:01:39 +02:00
2014-08-25 05:48:52 +02:00
/ * *
* Returns whether or not to use non - English metadata where available .
* @return true if Unicode preferred
* /
2015-03-03 06:40:51 +01:00
public static boolean useUnicodeMetadata ( ) { return GameOption . SHOW_UNICODE . getBooleanValue ( ) ; }
2014-08-25 05:48:52 +02:00
2014-12-21 00:17:04 +01:00
/ * *
* Returns whether or not to play the theme song .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isThemeSongEnabled ( ) { return GameOption . ENABLE_THEME_SONG . getBooleanValue ( ) ; }
2014-12-21 00:17:04 +01:00
2014-07-09 04:17:48 +02:00
/ * *
* Sets the track checkpoint time , if within bounds .
* @param time the track position ( in ms )
* @return true if within bounds
* /
public static boolean setCheckpoint ( int time ) {
if ( time > = 0 & & time < 3600 ) {
2015-03-03 06:40:51 +01:00
GameOption . CHECKPOINT . setValue ( time ) ;
2014-07-09 04:17:48 +02:00
return true ;
}
return false ;
}
2015-02-15 07:40:01 +01:00
/ * *
* Returns whether or not to show the hit error bar .
* @return true if enabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isHitErrorBarEnabled ( ) { return GameOption . SHOW_HIT_ERROR_BAR . getBooleanValue ( ) ; }
2015-03-14 13:11:33 +01:00
/ * *
2015-03-15 04:28:50 +01:00
* Returns whether or not to load HD ( @2x ) images .
* @return true if HD images are enabled , false if only SD images should be loaded
2015-03-14 13:11:33 +01:00
* /
2015-03-15 04:28:50 +01:00
public static boolean loadHDImages ( ) { return GameOption . LOAD_HD_IMAGES . getBooleanValue ( ) ; }
2015-02-15 07:40:01 +01:00
2015-03-03 04:12:57 +01:00
/ * *
* Returns whether or not the mouse wheel is disabled during gameplay .
* @return true if disabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isMouseWheelDisabled ( ) { return GameOption . DISABLE_MOUSE_WHEEL . getBooleanValue ( ) ; }
2015-03-03 04:12:57 +01:00
/ * *
* Returns whether or not the mouse buttons are disabled during gameplay .
* @return true if disabled
* /
2015-03-03 06:40:51 +01:00
public static boolean isMouseDisabled ( ) { return GameOption . DISABLE_MOUSE_BUTTONS . getBooleanValue ( ) ; }
2015-03-03 04:12:57 +01:00
2015-03-05 20:40:57 +01:00
/ * *
* Toggles the mouse button enabled / disabled state during gameplay and
* sends a bar notification about the action .
* /
public static void toggleMouseDisabled ( ) {
GameOption . DISABLE_MOUSE_BUTTONS . click ( null ) ;
UI . sendBarNotification ( ( GameOption . DISABLE_MOUSE_BUTTONS . getBooleanValue ( ) ) ?
" Mouse buttons are disabled. " : " Mouse buttons are enabled. " ) ;
}
2014-07-18 05:58:37 +02:00
/ * *
* Returns the left game key .
* @return the left key code
* /
public static int getGameKeyLeft ( ) {
if ( keyLeft = = Keyboard . KEY_NONE )
2015-03-07 05:49:59 +01:00
setGameKeyLeft ( Input . KEY_Z ) ;
2014-07-18 05:58:37 +02:00
return keyLeft ;
}
/ * *
* Returns the right game key .
* @return the right key code
* /
public static int getGameKeyRight ( ) {
if ( keyRight = = Keyboard . KEY_NONE )
2015-03-07 05:49:59 +01:00
setGameKeyRight ( Input . KEY_X ) ;
2014-07-18 05:58:37 +02:00
return keyRight ;
}
2015-01-21 05:56:10 +01:00
/ * *
* Sets the left game key .
2015-03-07 20:24:26 +01:00
* This will not be set to the same key as the right game key , nor to any
* reserved keys ( see { @link # isValidGameKey ( int ) } ) .
2015-01-21 05:56:10 +01:00
* @param key the keyboard key
2015-03-07 05:49:59 +01:00
* @return { @code true } if the key was set , { @code false } if it was rejected
* /
public static boolean setGameKeyLeft ( int key ) {
2015-03-07 20:24:26 +01:00
if ( ( key = = keyRight & & key ! = Keyboard . KEY_NONE ) | | ! isValidGameKey ( key ) )
2015-03-07 05:49:59 +01:00
return false ;
keyLeft = key ;
return true ;
}
2015-01-21 05:56:10 +01:00
/ * *
* Sets the right game key .
2015-03-07 20:24:26 +01:00
* This will not be set to the same key as the left game key , nor to any
* reserved keys ( see { @link # isValidGameKey ( int ) } ) .
2015-01-21 05:56:10 +01:00
* @param key the keyboard key
2015-03-07 05:49:59 +01:00
* @return { @code true } if the key was set , { @code false } if it was rejected
* /
public static boolean setGameKeyRight ( int key ) {
2015-03-07 20:24:26 +01:00
if ( ( key = = keyLeft & & key ! = Keyboard . KEY_NONE ) | | ! isValidGameKey ( key ) )
2015-03-07 05:49:59 +01:00
return false ;
keyRight = key ;
return true ;
}
2015-01-21 05:56:10 +01:00
2015-03-07 20:24:26 +01:00
/ * *
* Checks if the given key is a valid game key .
* @param key the keyboard key
* @return { @code true } if valid , { @code false } otherwise
* /
private 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 ) ;
}
2014-06-30 04:17:04 +02:00
/ * *
2014-07-06 07:58:44 +02:00
* Returns the beatmap directory .
2014-06-30 04:17:04 +02:00
* If invalid , this will attempt to search for the directory ,
* and if nothing found , will create one .
2014-07-02 07:53:42 +02:00
* @return the beatmap directory
2014-06-30 04:17:04 +02:00
* /
public static File getBeatmapDir ( ) {
if ( beatmapDir ! = null & & beatmapDir . isDirectory ( ) )
return beatmapDir ;
// search for directory
for ( int i = 0 ; i < BEATMAP_DIRS . length ; i + + ) {
beatmapDir = new File ( BEATMAP_DIRS [ i ] ) ;
2014-07-02 01:32:03 +02:00
if ( beatmapDir . isDirectory ( ) )
2014-06-30 04:17:04 +02:00
return beatmapDir ;
}
beatmapDir . mkdir ( ) ; // none found, create new directory
return beatmapDir ;
}
2014-07-06 07:58:44 +02:00
/ * *
* Returns the OSZ archive directory .
2014-07-18 06:56:37 +02:00
* If invalid , this will create and return a " SongPacks " directory .
2014-07-06 07:58:44 +02:00
* @return the OSZ archive directory
* /
public static File getOSZDir ( ) {
if ( oszDir ! = null & & oszDir . isDirectory ( ) )
return oszDir ;
2015-02-13 21:03:17 +01:00
oszDir = new File ( DATA_DIR , " SongPacks/ " ) ;
2014-07-15 06:20:36 +02:00
oszDir . mkdir ( ) ;
2014-07-06 07:58:44 +02:00
return oszDir ;
}
2014-07-18 06:56:37 +02:00
/ * *
* Returns the screenshot directory .
* If invalid , this will return a " Screenshot " directory .
* @return the screenshot directory
* /
public static File getScreenshotDir ( ) {
if ( screenshotDir ! = null & & screenshotDir . isDirectory ( ) )
return screenshotDir ;
2015-02-13 21:03:17 +01:00
screenshotDir = new File ( DATA_DIR , " Screenshots/ " ) ;
2014-07-18 06:56:37 +02:00
return screenshotDir ;
}
2015-03-12 01:52:51 +01:00
/ * *
* Returns the replay directory .
* If invalid , this will return a " Replay " directory .
* @return the replay directory
* /
public static File getReplayDir ( ) {
if ( replayDir ! = null & & replayDir . isDirectory ( ) )
return replayDir ;
replayDir = new File ( DATA_DIR , " Replays/ " ) ;
return replayDir ;
}
2014-07-02 07:53:42 +02:00
/ * *
* Returns the current skin directory .
* If invalid , this will create a " Skins " folder in the root directory .
* @return the skin directory
* /
2015-05-24 05:48:28 +02:00
public static File getSkinRootDir ( ) {
if ( skinRootDir ! = null & & skinRootDir . isDirectory ( ) )
return skinRootDir ;
2014-07-02 07:53:42 +02:00
2015-05-24 05:48:28 +02:00
// search for directory
for ( int i = 0 ; i < SKIN_ROOT_DIRS . length ; i + + ) {
skinRootDir = new File ( SKIN_ROOT_DIRS [ i ] ) ;
if ( skinRootDir . isDirectory ( ) )
return skinRootDir ;
}
skinRootDir . mkdir ( ) ; // none found, create new directory
return skinRootDir ;
2014-07-02 07:53:42 +02:00
}
2014-07-02 01:32:03 +02:00
2015-05-24 05:48:28 +02:00
/ * *
* Loads the skin given by the current skin directory .
* If the directory is invalid , the default skin will be loaded .
* /
public static void loadSkin ( ) {
2015-06-03 12:23:23 +02:00
File skinDir = getSkinDir ( ) ;
if ( skinDir = = null ) // invalid skin name
2015-05-24 05:48:28 +02:00
skinName = Skin . DEFAULT_SKIN_NAME ;
// create available skins list
2015-06-03 12:23:23 +02:00
File [ ] dirs = SkinLoader . getSkinDirectories ( getSkinRootDir ( ) ) ;
2015-05-24 05:48:28 +02:00
skinDirs = new String [ dirs . length + 1 ] ;
skinDirs [ 0 ] = Skin . DEFAULT_SKIN_NAME ;
for ( int i = 0 ; i < dirs . length ; i + + )
skinDirs [ i + 1 ] = dirs [ i ] . getName ( ) ;
// set skin and modify resource locations
ResourceLoader . removeAllResourceLocations ( ) ;
if ( skinDir = = null )
skin = new Skin ( null ) ;
else {
// set skin index
for ( int i = 1 ; i < skinDirs . length ; i + + ) {
if ( skinDirs [ i ] . equals ( skinName ) ) {
skinDirIndex = i ;
break ;
}
}
// load the skin
skin = SkinLoader . loadSkin ( skinDir ) ;
ResourceLoader . addResourceLocation ( new FileSystemLocation ( skinDir ) ) ;
}
ResourceLoader . addResourceLocation ( new ClasspathLocation ( ) ) ;
ResourceLoader . addResourceLocation ( new FileSystemLocation ( new File ( " . " ) ) ) ;
ResourceLoader . addResourceLocation ( new FileSystemLocation ( new File ( " ./res/ " ) ) ) ;
}
/ * *
* Returns the current skin .
* @return the skin , or null if no skin is loaded ( see { @link # loadSkin ( ) } )
* /
public static Skin getSkin ( ) { return skin ; }
2015-06-03 12:23:23 +02:00
/ * *
* Returns the current skin directory .
* < p >
* NOTE : This directory will differ from that of the currently loaded skin
* if { @link # loadSkin ( ) } has not been called after a directory change .
* Use { @link Skin # getDirectory ( ) } to get the directory of the currently
* loaded skin .
* @return the skin directory , or null for the default skin
* /
public static File getSkinDir ( ) {
File root = getSkinRootDir ( ) ;
File dir = new File ( root , skinName ) ;
return ( dir . isDirectory ( ) ) ? dir : null ;
}
2014-12-21 03:35:18 +01:00
/ * *
2015-05-17 03:25:19 +02:00
* Returns a dummy Beatmap containing the theme song .
* @return the theme song beatmap
2014-12-21 03:35:18 +01:00
* /
2015-05-17 03:25:19 +02:00
public static Beatmap getThemeBeatmap ( ) {
2014-12-21 03:35:18 +01:00
String [ ] tokens = themeString . split ( " , " ) ;
if ( tokens . length ! = 4 ) {
2015-01-16 03:55:26 +01:00
ErrorHandler . error ( " Theme song string is malformed. " , null , false ) ;
2014-12-21 03:35:18 +01:00
return null ;
}
2015-05-17 03:25:19 +02:00
Beatmap beatmap = new Beatmap ( null ) ;
beatmap . audioFilename = new File ( tokens [ 0 ] ) ;
beatmap . title = tokens [ 1 ] ;
beatmap . artist = tokens [ 2 ] ;
2014-12-21 03:35:18 +01:00
try {
2015-05-17 03:25:19 +02:00
beatmap . endTime = Integer . parseInt ( tokens [ 3 ] ) ;
2014-12-21 03:35:18 +01:00
} catch ( NumberFormatException e ) {
2015-01-16 03:55:26 +01:00
ErrorHandler . error ( " Theme song length is not a valid integer " , e , false ) ;
2014-12-21 03:35:18 +01:00
return null ;
}
2015-05-17 03:25:19 +02:00
return beatmap ;
2014-12-21 03:35:18 +01:00
}
2014-06-30 04:17:04 +02:00
/ * *
* Reads user options from the options file , if it exists .
* /
public static void parseOptions ( ) {
// if no config file, use default settings
2014-07-02 07:53:42 +02:00
if ( ! OPTIONS_FILE . isFile ( ) ) {
2014-06-30 04:17:04 +02:00
saveOptions ( ) ;
return ;
}
2014-07-02 07:53:42 +02:00
try ( BufferedReader in = new BufferedReader ( new FileReader ( OPTIONS_FILE ) ) ) {
2014-06-30 04:17:04 +02:00
String line ;
String name , value ;
int i ;
while ( ( line = in . readLine ( ) ) ! = null ) {
line = line . trim ( ) ;
if ( line . length ( ) < 2 | | line . charAt ( 0 ) = = '#' )
continue ;
int index = line . indexOf ( '=' ) ;
if ( index = = - 1 )
continue ;
name = line . substring ( 0 , index ) . trim ( ) ;
value = line . substring ( index + 1 ) . trim ( ) ;
2015-03-03 06:40:51 +01:00
try {
switch ( name ) {
case " BeatmapDirectory " :
beatmapDir = new File ( value ) ;
break ;
case " OSZDirectory " :
oszDir = new File ( value ) ;
break ;
case " ScreenshotDirectory " :
screenshotDir = new File ( value ) ;
break ;
2015-03-12 01:52:51 +01:00
case " ReplayDirectory " :
replayDir = new File ( value ) ;
break ;
2015-05-24 05:48:28 +02:00
case " SkinDirectory " :
skinRootDir = new File ( value ) ;
2015-03-03 06:40:51 +01:00
break ;
case " ThemeSong " :
themeString = value ;
break ;
case " Port " :
i = Integer . parseInt ( value ) ;
if ( i > 0 & & i < = 65535 )
port = i ;
break ;
case " ScreenResolution " :
try {
Resolution res = Resolution . valueOf ( String . format ( " RES_%s " , value . replace ( 'x' , '_' ) ) ) ;
resolution = res ;
} catch ( IllegalArgumentException e ) { }
break ;
// case "Fullscreen":
// GameOption.FULLSCREEN.setValue(Boolean.parseBoolean(value));
// break;
2015-05-24 05:48:28 +02:00
case " Skin " :
skinName = value ;
break ;
2015-03-03 06:40:51 +01:00
case " FrameSync " :
i = Integer . parseInt ( value ) ;
for ( int j = 0 ; j < targetFPS . length ; j + + ) {
if ( i = = targetFPS [ j ] )
targetFPSindex = j ;
}
break ;
case " ScreenshotFormat " :
i = Integer . parseInt ( value ) ;
if ( i > = 0 & & i < screenshotFormat . length )
screenshotFormatIndex = i ;
break ;
case " FpsCounter " :
GameOption . SHOW_FPS . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " ShowUnicode " :
GameOption . SHOW_UNICODE . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " NewCursor " :
GameOption . NEW_CURSOR . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " DynamicBackground " :
GameOption . DYNAMIC_BACKGROUND . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " LoadVerbose " :
GameOption . LOAD_VERBOSE . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " VolumeUniversal " :
i = Integer . parseInt ( value ) ;
if ( i > = 0 & & i < = 100 )
GameOption . MASTER_VOLUME . setValue ( i ) ;
break ;
case " VolumeMusic " :
i = Integer . parseInt ( value ) ;
if ( i > = 0 & & i < = 100 )
GameOption . MUSIC_VOLUME . setValue ( i ) ;
break ;
case " VolumeEffect " :
i = Integer . parseInt ( value ) ;
if ( i > = 0 & & i < = 100 )
GameOption . EFFECT_VOLUME . setValue ( i ) ;
break ;
case " VolumeHitSound " :
i = Integer . parseInt ( value ) ;
if ( i > = 0 & & i < = 100 )
GameOption . HITSOUND_VOLUME . setValue ( i ) ;
break ;
case " Offset " :
i = Integer . parseInt ( value ) ;
if ( i > = - 500 & & i < = 500 )
GameOption . MUSIC_OFFSET . setValue ( i ) ;
break ;
case " DisableSound " :
GameOption . DISABLE_SOUNDS . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " keyOsuLeft " :
2015-03-07 05:49:59 +01:00
setGameKeyLeft ( Keyboard . getKeyIndex ( value ) ) ;
2015-03-03 06:40:51 +01:00
break ;
case " keyOsuRight " :
2015-03-07 05:49:59 +01:00
setGameKeyRight ( Keyboard . getKeyIndex ( value ) ) ;
2015-03-03 06:40:51 +01:00
break ;
case " MouseDisableWheel " :
GameOption . DISABLE_MOUSE_WHEEL . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " MouseDisableButtons " :
GameOption . DISABLE_MOUSE_BUTTONS . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " DimLevel " :
i = Integer . parseInt ( value ) ;
if ( i > = 0 & & i < = 100 )
GameOption . BACKGROUND_DIM . setValue ( i ) ;
break ;
case " ForceDefaultPlayfield " :
GameOption . FORCE_DEFAULT_PLAYFIELD . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " IgnoreBeatmapSkins " :
GameOption . IGNORE_BEATMAP_SKINS . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " HitLighting " :
GameOption . SHOW_HIT_LIGHTING . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " ComboBurst " :
GameOption . SHOW_COMBO_BURSTS . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
case " PerfectHit " :
GameOption . SHOW_PERFECT_HIT . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
2015-03-19 04:23:34 +01:00
case " FollowPoints " :
GameOption . SHOW_FOLLOW_POINTS . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
2015-03-03 06:40:51 +01:00
case " ScoreMeter " :
GameOption . SHOW_HIT_ERROR_BAR . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
2015-03-15 04:28:50 +01:00
case " LoadHDImages " :
GameOption . LOAD_HD_IMAGES . setValue ( Boolean . parseBoolean ( value ) ) ;
2015-03-14 13:11:33 +01:00
break ;
2015-03-03 06:40:51 +01:00
case " FixedCS " :
GameOption . FIXED_CS . setValue ( ( int ) ( Float . parseFloat ( value ) * 10f ) ) ;
break ;
case " FixedHP " :
GameOption . FIXED_HP . setValue ( ( int ) ( Float . parseFloat ( value ) * 10f ) ) ;
break ;
case " FixedAR " :
GameOption . FIXED_AR . setValue ( ( int ) ( Float . parseFloat ( value ) * 10f ) ) ;
break ;
case " FixedOD " :
GameOption . FIXED_OD . setValue ( ( int ) ( Float . parseFloat ( value ) * 10f ) ) ;
break ;
case " Checkpoint " :
setCheckpoint ( Integer . parseInt ( value ) ) ;
break ;
case " MenuMusic " :
GameOption . ENABLE_THEME_SONG . setValue ( Boolean . parseBoolean ( value ) ) ;
break ;
2014-07-18 05:58:37 +02:00
}
2015-03-03 06:40:51 +01:00
} catch ( NumberFormatException e ) {
Log . warn ( String . format ( " Format error in options file for line: '%s'. " , line ) , e ) ;
continue ;
2014-06-30 04:17:04 +02:00
}
}
} catch ( IOException e ) {
2015-01-16 03:55:26 +01:00
ErrorHandler . error ( String . format ( " Failed to read file '%s'. " , OPTIONS_FILE . getAbsolutePath ( ) ) , e , false ) ;
2014-06-30 04:17:04 +02:00
}
}
/ * *
* ( Over ) writes user options to a file .
* /
public static void saveOptions ( ) {
try ( BufferedWriter writer = new BufferedWriter ( new OutputStreamWriter (
new FileOutputStream ( OPTIONS_FILE ) , " utf-8 " ) ) ) {
// header
SimpleDateFormat dateFormat = new SimpleDateFormat ( " EEEE, MMMM dd, yyyy " ) ;
String date = dateFormat . format ( new Date ( ) ) ;
writer . write ( " # opsu! configuration " ) ;
writer . newLine ( ) ;
writer . write ( " # last updated on " ) ;
writer . write ( date ) ;
writer . newLine ( ) ;
writer . newLine ( ) ;
// options
2014-07-02 07:53:42 +02:00
writer . write ( String . format ( " BeatmapDirectory = %s " , getBeatmapDir ( ) . getAbsolutePath ( ) ) ) ;
writer . newLine ( ) ;
2014-07-06 07:58:44 +02:00
writer . write ( String . format ( " OSZDirectory = %s " , getOSZDir ( ) . getAbsolutePath ( ) ) ) ;
writer . newLine ( ) ;
2014-07-18 06:56:37 +02:00
writer . write ( String . format ( " ScreenshotDirectory = %s " , getScreenshotDir ( ) . getAbsolutePath ( ) ) ) ;
writer . newLine ( ) ;
2015-03-12 01:52:51 +01:00
writer . write ( String . format ( " ReplayDirectory = %s " , getReplayDir ( ) . getAbsolutePath ( ) ) ) ;
writer . newLine ( ) ;
2015-05-24 05:48:28 +02:00
writer . write ( String . format ( " SkinDirectory = %s " , getSkinRootDir ( ) . getAbsolutePath ( ) ) ) ;
2014-07-02 07:53:42 +02:00
writer . newLine ( ) ;
2014-12-21 03:35:18 +01:00
writer . write ( String . format ( " ThemeSong = %s " , themeString ) ) ;
writer . newLine ( ) ;
2014-07-03 00:24:19 +02:00
writer . write ( String . format ( " Port = %d " , port ) ) ;
writer . newLine ( ) ;
2015-01-15 07:52:16 +01:00
writer . write ( String . format ( " ScreenResolution = %s " , resolution . toString ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
// writer.write(String.format("Fullscreen = %b", isFullscreen()));
2014-06-30 04:17:04 +02:00
// writer.newLine();
2015-05-24 05:48:28 +02:00
writer . write ( String . format ( " Skin = %s " , skinName ) ) ;
writer . newLine ( ) ;
2015-01-15 07:52:16 +01:00
writer . write ( String . format ( " FrameSync = %d " , targetFPS [ targetFPSindex ] ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " FpsCounter = %b " , isFPSCounterEnabled ( ) ) ) ;
2014-07-03 00:24:19 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " ShowUnicode = %b " , useUnicodeMetadata ( ) ) ) ;
2014-08-25 05:48:52 +02:00
writer . newLine ( ) ;
2014-07-03 00:24:19 +02:00
writer . write ( String . format ( " ScreenshotFormat = %d " , screenshotFormatIndex ) ) ;
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " NewCursor = %b " , isNewCursorEnabled ( ) ) ) ;
2014-07-03 00:24:19 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " DynamicBackground = %b " , isDynamicBackgroundEnabled ( ) ) ) ;
2014-07-03 00:24:19 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " LoadVerbose = %b " , isLoadVerbose ( ) ) ) ;
2014-07-06 03:00:52 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " VolumeUniversal = %d " , GameOption . MASTER_VOLUME . getIntegerValue ( ) ) ) ;
2015-01-20 20:52:02 +01:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " VolumeMusic = %d " , GameOption . MUSIC_VOLUME . getIntegerValue ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " VolumeEffect = %d " , GameOption . EFFECT_VOLUME . getIntegerValue ( ) ) ) ;
2014-07-01 07:14:03 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " VolumeHitSound = %d " , GameOption . HITSOUND_VOLUME . getIntegerValue ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " Offset = %d " , getMusicOffset ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " DisableSound = %b " , isSoundDisabled ( ) ) ) ;
2014-07-11 04:01:39 +02:00
writer . newLine ( ) ;
2014-07-19 03:33:07 +02:00
writer . write ( String . format ( " keyOsuLeft = %s " , Keyboard . getKeyName ( getGameKeyLeft ( ) ) ) ) ;
2014-07-18 05:58:37 +02:00
writer . newLine ( ) ;
2014-07-19 03:33:07 +02:00
writer . write ( String . format ( " keyOsuRight = %s " , Keyboard . getKeyName ( getGameKeyRight ( ) ) ) ) ;
2014-07-18 05:58:37 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " MouseDisableWheel = %b " , isMouseWheelDisabled ( ) ) ) ;
2015-03-03 04:12:57 +01:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " MouseDisableButtons = %b " , isMouseDisabled ( ) ) ) ;
2015-03-03 04:12:57 +01:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " DimLevel = %d " , GameOption . BACKGROUND_DIM . getIntegerValue ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " ForceDefaultPlayfield = %b " , isDefaultPlayfieldForced ( ) ) ) ;
2014-07-03 07:05:23 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " IgnoreBeatmapSkins = %b " , isBeatmapSkinIgnored ( ) ) ) ;
2014-07-04 22:41:52 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " HitLighting = %b " , isHitLightingEnabled ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " ComboBurst = %b " , isComboBurstEnabled ( ) ) ) ;
2014-06-30 04:17:04 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " PerfectHit = %b " , isPerfectHitBurstEnabled ( ) ) ) ;
2014-07-02 01:32:03 +02:00
writer . newLine ( ) ;
2015-03-19 04:23:34 +01:00
writer . write ( String . format ( " FollowPoints = %b " , isFollowPointEnabled ( ) ) ) ;
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " ScoreMeter = %b " , isHitErrorBarEnabled ( ) ) ) ;
2015-02-15 07:40:01 +01:00
writer . newLine ( ) ;
2015-03-15 04:28:50 +01:00
writer . write ( String . format ( " LoadHDImages = %b " , loadHDImages ( ) ) ) ;
2015-03-14 13:11:33 +01:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( Locale . US , " FixedCS = %.1f " , getFixedCS ( ) ) ) ;
2014-07-05 07:24:01 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( Locale . US , " FixedHP = %.1f " , getFixedHP ( ) ) ) ;
2014-07-05 07:24:01 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( Locale . US , " FixedAR = %.1f " , getFixedAR ( ) ) ) ;
2014-07-05 07:24:01 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( Locale . US , " FixedOD = %.1f " , getFixedOD ( ) ) ) ;
2014-07-05 07:24:01 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " Checkpoint = %d " , GameOption . CHECKPOINT . getIntegerValue ( ) ) ) ;
2014-07-09 04:17:48 +02:00
writer . newLine ( ) ;
2015-03-03 06:40:51 +01:00
writer . write ( String . format ( " MenuMusic = %b " , isThemeSongEnabled ( ) ) ) ;
2014-12-21 00:17:04 +01:00
writer . newLine ( ) ;
2014-06-30 04:17:04 +02:00
writer . close ( ) ;
} catch ( IOException e ) {
2015-01-16 03:55:26 +01:00
ErrorHandler . error ( String . format ( " Failed to write to file '%s'. " , OPTIONS_FILE . getAbsolutePath ( ) ) , e , false ) ;
2014-06-30 04:17:04 +02:00
}
}
}