Merge branch 'master' into replaystuff
# Conflicts: # src/itdelatrisu/opsu/states/Game.java
6
.gitignore
vendored
|
@ -29,4 +29,8 @@
|
|||
build/
|
||||
|
||||
Thumbs.db
|
||||
/target
|
||||
.DS_STORE
|
||||
/target
|
||||
/out/
|
||||
/lib/
|
||||
/mvnlibs/
|
||||
|
|
|
@ -20,6 +20,7 @@ The images included in opsu! belong to their respective authors.
|
|||
* sherrie__fay
|
||||
* kouyang
|
||||
* teinecthel
|
||||
* Font Awesome by Dave Gandy - http://fontawesome.io
|
||||
|
||||
Projects
|
||||
--------
|
||||
|
@ -31,6 +32,5 @@ The following projects were referenced in creating opsu!:
|
|||
|
||||
Theme Song
|
||||
----------
|
||||
Rainbows - Kevin MacLeod (incompetech.com)
|
||||
Licensed under Creative Commons: By Attribution 3.0 License
|
||||
http://creativecommons.org/licenses/by/3.0/
|
||||
The theme song is "On the Bach" by Jingle Punks, from the [YouTube Audio Library]
|
||||
(https://www.youtube.com/audiolibrary/music).
|
||||
|
|
76
README.md
|
@ -1,23 +1,69 @@
|
|||
# opsu!dance
|
||||
[example video](https://www.youtube.com/watch?v=tqZqn7nx8N0)
|
||||
|
||||
Originally started as a fork of [opsu!](https://github.com/itdelatrisu/opsu) with cursordance stuff. I made a cursordancing bot in C# for osu!, and by adding it into this clone, it allows me to do even more stuff with it. This way I can also provide this client to other players so they can play with it too, as I will not give my bot to people because I don't want to endorse cheating in any way.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
* [What](#What) - [Why](#why) - [Downloads](#downloads) - [Running](#running) - [Building a JAR](#building-a-jar) - [Credits](#credits) - [License](#license)
|
||||
|
||||
What
|
||||
----
|
||||
Fork of [opsu!](https://github.com/itdelatrisu/opsu), which is a clone of the [osu!](https://osu.ppy.sh/) rythm game.
|
||||
|
||||
* [example video: Cursor Dance | MOMOIRO CLOVER Z - SANTA SAN](https://youtu.be/tqZqn7nx8N0)
|
||||
* [example video: osu! 50 top replays | Getty vs. DJ DiA - Fox4-Raize- [Extreme]](https://youtu.be/T2AiGn2xOQo)
|
||||
|
||||
As of 2017 some major changes were made in this fork which changed the inner workings of opsu. This was done in an attempt to get more control over the base system and allowed a.o. changing resolution and skin at runtime without the need to restart the whole system. This fork was pretty even to opsu! before this change, but now there are way more differences.
|
||||
|
||||
My goal is to to add cool cursordancing things to this fork, but also make it possible to play the normal way.
|
||||
|
||||
### Downloads
|
||||
Click on the releases link (scroll up) to go to the downloadpage with prebuilt jars.
|
||||
Why
|
||||
---
|
||||
I made a cursordancing bot in C# for osu!, and by adding it into this clone, it allows me to do even more stuff with it. This way I can also provide this client to other players so they can play with it too, as I will not give my bot to people because I don't want to endorse cheating in any way.
|
||||
|
||||
### Building
|
||||
You can find general (run/build) instructions in the original [opsu! README](README-OPSU.md).
|
||||
Please note that I am only using maven, gradle scripts are not being updated.
|
||||
My goal is to to add cool cursordancing things to this fork, but also make it possible to play the normal way. In the meantime I'm also adding various improvements to opsu! while I make a mess here, like the option menu, default back button, slider stuff, ...
|
||||
|
||||
### Credits
|
||||
opsu! was made by Jeffrey Han ([@itdelatrisu](https://github.com/itdelatrisu)). All game concepts and designs are based on work by osu! developer Dean Herbert. Other opsu! credits can be found [here](CREDITS.md).
|
||||
opsu!dance (everything in the src package yugecin.opsudance) was made by me ([@yugecin](https://github.com/yugecin)). Edits were made in the opsu! sources, too.
|
||||
Downloads
|
||||
---------
|
||||
You can find prebuilt jars on [the releases page](https://github.com/yugecin/opsu-dance/releases).
|
||||
|
||||
### License
|
||||
Running
|
||||
-------
|
||||
|
||||
If you don't need to edit the source, just download a jar from [the releases page](https://github.com/yugecin/opsu-dance/releases).
|
||||
|
||||
Using an IDE is recommended because it is usually faster than the other options and provides debugging.
|
||||
|
||||
### Using your favorite IDE
|
||||
You should know how to do this. It's recommended to use a working directory like `out` to not pollute the project directory with config/db files.
|
||||
|
||||
### Using apache maven
|
||||
`mvn compile`
|
||||
|
||||
### Using apache ant
|
||||
|
||||
Resolve dependencies first, use either:
|
||||
|
||||
* `ant ivyresolve` to download dependencies using apache ivy
|
||||
* `ant mvnresolve` to download dependencies using apache mvn
|
||||
|
||||
Then do `ant run`
|
||||
|
||||
Building a JAR
|
||||
--------------
|
||||
|
||||
Using ant is recommended. Ant is used since release 0.5.0
|
||||
|
||||
### Using apache maven
|
||||
`mvn package -Djar`, find it in the `target` folder.
|
||||
|
||||
### Using apache ant
|
||||
`ant jar`, find it in the `bin` folder
|
||||
|
||||
|
||||
Credits
|
||||
-------
|
||||
opsu! was made by Jeffrey Han ([@itdelatrisu](https://github.com/itdelatrisu)). All game concepts and designs are based on work by osu! developer Dean Herbert. Other opsu! credits can be found [here](CREDITS.md).
|
||||
|
||||
opsu!dance (everything in the src package yugecin.opsudance) was made by me ([@yugecin](https://github.com/yugecin)). Lots of edits were made in the opsu! sources, too.
|
||||
|
||||
License
|
||||
-------
|
||||
**This software is licensed under GNU GPL version 3.**
|
||||
You can find the full text of the license [here](LICENSE).
|
||||
You can find the full text of the license in [the LICENSE file](LICENSE).
|
||||
|
|
159
build.xml
Normal file
|
@ -0,0 +1,159 @@
|
|||
<project name="opsu!dance" default="hi" xmlns:ivy="antlib:org.apache.ivy.ant">
|
||||
|
||||
<property name="dir.src" value="${basedir}/src" />
|
||||
<property name="dir.lib" value="${basedir}/lib" />
|
||||
<property name="dir.mvnlibs" value="${basedir}/mvnlibs" />
|
||||
<property name="dir.ivylibs" value="${basedir}/ivylibs" />
|
||||
<property name="dir.res" value="${basedir}/res" />
|
||||
<property name="dir.out" value="${basedir}/bin" />
|
||||
|
||||
<property name="lang.src" value="1.8" />
|
||||
<property name="lang.target" value="1.8" />
|
||||
<property name="version" value="0.5.0-SNAPSHOT" />
|
||||
|
||||
<property name="main" value="yugecin.opsudance.core.Entrypoint" />
|
||||
|
||||
<tstamp>
|
||||
<format property="timestamp" pattern="yyyy-MM-dd HH:mm" />
|
||||
</tstamp>
|
||||
|
||||
<target name="hi">
|
||||
<echo>
|
||||
ant clean --> clean the ant working dir
|
||||
ant cleanlib --> clean the lib folder
|
||||
ant ivyresolve --> resolve dependencies using ivy
|
||||
ant mvnresolve --> resolve dependencies using mvn
|
||||
ant compile --> compile the code
|
||||
ant run --> prepare to run and run
|
||||
ant jar --> package a jar
|
||||
|
||||
resolve dependencies first
|
||||
(using either mvnresolve or ivyresolve),
|
||||
then run (code is compiled automatically when you run)
|
||||
</echo>
|
||||
</target>
|
||||
|
||||
<target name="clean" description="--> clean the ant working dir">
|
||||
<delete dir="${dir.out}" />
|
||||
</target>
|
||||
|
||||
<target name="cleanlib" description="--> clean the lib folder">
|
||||
<delete dir="${dir.lib}" />
|
||||
<delete dir="${dir.mvnlibs}" />
|
||||
<delete dir="${dir.ivylibs}" />
|
||||
</target>
|
||||
|
||||
<target name="ivyresolve" depends="cleanlib" description="--> resolve dependencies using ivy">
|
||||
<ivy:retrieve pattern="${dir.ivylibs}/[artifact]-[revision](-[classifier]).[ext]" />
|
||||
<move file="${dir.ivylibs}" tofile="${dir.lib}" />
|
||||
</target>
|
||||
|
||||
<target name="mvnresolve" depends="cleanlib" description="--> resolve dependencies using mvn">
|
||||
<condition property="shellexecutable" value="cmd">
|
||||
<os family="windows" />
|
||||
</condition>
|
||||
<condition property="shellcmdarg" value="/c">
|
||||
<os family="windows" />
|
||||
</condition>
|
||||
<!-- properties are immutable, the following 2 lines won't do anything if os is windows -->
|
||||
<property name="shellexecutable" value="sh" />
|
||||
<property name="shellcmdarg" value="-c" />
|
||||
|
||||
<exec executable="${shellexecutable}">
|
||||
<arg value="${shellcmdarg}" />
|
||||
<arg value="mvn initialize" />
|
||||
</exec>
|
||||
|
||||
<move file="${dir.mvnlibs}" tofile="${dir.lib}" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="--> compile sources">
|
||||
<mkdir dir="${dir.out}/classes" />
|
||||
|
||||
<javac
|
||||
srcdir="${dir.src}"
|
||||
destdir="${dir.out}/classes"
|
||||
includes="**/*.java"
|
||||
source="${lang.src}"
|
||||
target="${lang.target}"
|
||||
includeantruntime="false"
|
||||
classpathref="classpath.base" />
|
||||
|
||||
<copy todir="${dir.out}/classes">
|
||||
<fileset dir="${dir.res}" excludes="version,*.pdn" />
|
||||
</copy>
|
||||
|
||||
<copy todir="${dir.out}/classes">
|
||||
<filterchain>
|
||||
<expandproperties />
|
||||
</filterchain>
|
||||
<fileset dir="${dir.res}" includes="version" />
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="run" depends="compile" description="--> run opsu!dance">
|
||||
<mkdir dir="${dir.out}/Natives" />
|
||||
|
||||
<unzip dest="${dir.out}/Natives">
|
||||
<fileset dir="${dir.lib}" includes="**/lwjgl-*-natives-*.jar" />
|
||||
</unzip>
|
||||
|
||||
<java
|
||||
fork="true"
|
||||
dir="${dir.out}"
|
||||
failonerror="false"
|
||||
classpathref="classpath.run"
|
||||
classname="${main}" />
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile" description="--> package a jar">
|
||||
<property name="jarfile" value="${dir.out}/opsu-dance-${version}.jar" />
|
||||
<delete file="${jarfile}" />
|
||||
|
||||
<jar jarfile="${dir.out}/lib.jar" roundup="false">
|
||||
<zipgroupfileset dir="${dir.lib}" />
|
||||
</jar>
|
||||
|
||||
<jar destfile="${jarfile}" duplicate="fail">
|
||||
<manifest>
|
||||
<attribute name="Manifest-Version" value="1.0" />
|
||||
<attribute name="Built-By" value="${user.name}" />
|
||||
<attribute name="Main-Class" value="${main}" />
|
||||
<attribute name="WinNatives" value="OpenAL32.dll,OpenAL64.dll,lwjgl.dll,lwjgl64.dll" />
|
||||
<attribute name="NixNatives" value="liblwjgl.so,liblwjgl64.so,libopenal.so,libopenal64.so" />
|
||||
<attribute name="MacNatives" value="liblwjgl.dylib,openal.dylib" />
|
||||
</manifest>
|
||||
<fileset dir="${dir.out}/classes" />
|
||||
<zipfileset src="${dir.out}/lib.jar">
|
||||
<exclude name="META-INF/**" />
|
||||
<exclude name="org/newdawn/slick/GameContainer.*" />
|
||||
<exclude name="org/newdawn/slick/Image.*" />
|
||||
<exclude name="org/newdawn/slick/Music.*" />
|
||||
<exclude name="org/newdawn/slick/Input.*" />
|
||||
<exclude name="org/newdawn/slick/Input$NullOutputStream.*" />
|
||||
<exclude name="org/newdawn/slick/MouseListener.*" />
|
||||
<exclude name="org/newdawn/slick/KeyListener.*" />
|
||||
<exclude name="org/newdawn/slick/InputListener.*" />
|
||||
<exclude name="org/newdawn/slick/gui/TextField.*" />
|
||||
<exclude name="org/newdawn/slick/openal/AudioInputStream*" />
|
||||
<exclude name="org/newdawn/slick/openal/OpenALStreamPlayer*" />
|
||||
<exclude name="org/newdawn/slick/openal/SoundStore*" />
|
||||
<!-- sqlite contains sources for some reason -->
|
||||
<exclude name="**/*.java" />
|
||||
<exclude name="**/*.c" />
|
||||
</zipfileset>
|
||||
</jar>
|
||||
|
||||
<delete file="${dir.out}/lib.jar" />
|
||||
</target>
|
||||
|
||||
<path id="classpath.base">
|
||||
<fileset dir="${dir.lib}" includes="**/*.jar" />
|
||||
</path>
|
||||
|
||||
<path id="classpath.run">
|
||||
<pathelement path="${dir.out}/classes" />
|
||||
<fileset dir="${dir.lib}" includes="**/*.jar" />
|
||||
</path>
|
||||
|
||||
</project>
|
38
ivy.xml
Normal file
|
@ -0,0 +1,38 @@
|
|||
<ivy-module
|
||||
version="2.0"
|
||||
xmlns:extra="http://ant.apache.org/ivy/extra"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
|
||||
|
||||
<info organisation="yugecin.opsudance" module="opsu!dance" />
|
||||
|
||||
<dependencies defaultconfmapping="default">
|
||||
<dependency org="org.lwjgl.lwjgl" name="lwjgl" rev="2.9.3">
|
||||
<exclude module="jinput" />
|
||||
</dependency>
|
||||
<dependency org="org.lwjgl.lwjgl" name="lwjgl-platform" rev="2.9.3">
|
||||
<artifact name="lwjgl-platform" type="jar" extra:classifier="natives-linux" />
|
||||
<artifact name="lwjgl-platform" type="jar" extra:classifier="natives-osx" />
|
||||
<artifact name="lwjgl-platform" type="jar" extra:classifier="natives-windows" />
|
||||
</dependency>
|
||||
<dependency org="org.slick2d" name="slick2d-core" rev="1.0.1">
|
||||
<exclude module="jnlp" />
|
||||
<exclude module="lwjgl" />
|
||||
</dependency>
|
||||
<dependency org="org.jcraft" name="jorbis" rev="0.0.17" />
|
||||
<dependency org="net.lingala.zip4j" name="zip4j" rev="1.3.2" />
|
||||
<dependency org="com.googlecode.soundlibs" name="mp3spi" rev="1.9.5.4">
|
||||
<exclude module="junit" />
|
||||
</dependency>
|
||||
<dependency org="org.xerial" name="sqlite-jdbc" rev="3.8.10.2" />
|
||||
<dependency org="org.json" name="json" rev="20140107" />
|
||||
<dependency org="net.java.dev.jna" name="jna" rev="4.1.0" />
|
||||
<dependency org="net.java.dev.jna" name="jna-platform" rev="4.1.0" />
|
||||
<dependency org="org.apache.maven" name="maven-artifact" rev="3.3.3" />
|
||||
<dependency org="org.apache.commons" name="commons-compress" rev="1.9" />
|
||||
<dependency org="org.tukaani" name="xz" rev="1.5" />
|
||||
<dependency org="com.github.jponge" name="lzma-java" rev="1.3" />
|
||||
<dependency org="gov.nist.math" name="jama" rev="1.0.3" />
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
88
pom.xml
|
@ -1,10 +1,14 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>yugecin</groupId>
|
||||
<artifactId>opsu-dance</artifactId>
|
||||
<version>0.5.0-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<version>${project.version}</version>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||
|
@ -20,6 +24,7 @@
|
|||
<excludes>
|
||||
<exclude>**/Thumbs.db</exclude>
|
||||
<exclude>**/version</exclude>
|
||||
<exclude>**.pdn</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
|
@ -31,13 +36,40 @@
|
|||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>2.4.1</version>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>${project.basedir}/mvnlibs</directory>
|
||||
<followSymlinks>true</followSymlinks>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.basedir}/mvnlibs</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
@ -74,6 +106,7 @@
|
|||
<classpath />
|
||||
<argument>${mainClassName}</argument>
|
||||
</arguments>
|
||||
<workingDirectory>${project.build.outputDirectory}/../</workingDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
@ -92,18 +125,32 @@
|
|||
<exclude>org/newdawn/slick/Music.*</exclude>
|
||||
<exclude>org/newdawn/slick/Input.*</exclude>
|
||||
<exclude>org/newdawn/slick/Input$NullOutputStream.*</exclude>
|
||||
<exclude>org/newdawn/slick/MouseListener.*</exclude>
|
||||
<exclude>org/newdawn/slick/KeyListener.*</exclude>
|
||||
<exclude>org/newdawn/slick/InputListener.*</exclude>
|
||||
<exclude>org/newdawn/slick/gui/TextField.*</exclude>
|
||||
<exclude>org/newdawn/slick/openal/AudioInputStream*</exclude>
|
||||
<exclude>org/newdawn/slick/openal/OpenALStreamPlayer*</exclude>
|
||||
<exclude>org/newdawn/slick/openal/SoundStore*</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<!-- sqlite contains sources for some reason -->
|
||||
<artifact>*:sqlite-jdbc</artifact>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
<exclude>**/*.c</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<manifestEntries>
|
||||
<Main-Class>${mainClassName}</Main-Class>
|
||||
<Use-XDG>${XDG}</Use-XDG>
|
||||
<WinNatives>OpenAL32.dll,OpenAL64.dll,lwjgl.dll,lwjgl64.dll</WinNatives>
|
||||
<NixNatives>liblwjgl.so,liblwjgl64.so,libopenal.so,libopenal64.so</NixNatives>
|
||||
<MacNatives>liblwjgl.dylib,openal.dylib</MacNatives>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
|
@ -142,6 +189,10 @@
|
|||
<groupId>org.lwjgl.lwjgl</groupId>
|
||||
<artifactId>lwjgl</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.jnlp</groupId>
|
||||
<artifactId>jnlp-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -154,20 +205,16 @@
|
|||
<artifactId>zip4j</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.soundlibs</groupId>
|
||||
<artifactId>jlayer</artifactId>
|
||||
<version>1.0.1-1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.soundlibs</groupId>
|
||||
<artifactId>mp3spi</artifactId>
|
||||
<version>1.9.5-1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.googlecode.soundlibs</groupId>
|
||||
<artifactId>tritonus-share</artifactId>
|
||||
<version>0.3.7-2</version>
|
||||
<version>1.9.5.4</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
|
@ -209,10 +256,11 @@
|
|||
<artifactId>lzma-java</artifactId>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nist.math</groupId>
|
||||
<artifactId>jama</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nist.math</groupId>
|
||||
<artifactId>jama</artifactId>
|
||||
<version>1.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
BIN
res/menu-nav-advanced.png
Normal file
After Width: | Height: | Size: 923 B |
BIN
res/menu-nav-audio.png
Normal file
After Width: | Height: | Size: 719 B |
BIN
res/menu-nav-custom.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/menu-nav-dance.png
Normal file
After Width: | Height: | Size: 935 B |
BIN
res/menu-nav-gameplay.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
res/menu-nav-general.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
res/menu-nav-graphics.png
Normal file
After Width: | Height: | Size: 647 B |
BIN
res/menu-nav-input.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
res/menu-nav-pippi.png
Normal file
After Width: | Height: | Size: 841 B |
BIN
res/menu-nav-skin.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
res/theme.mp3
BIN
res/theme.ogg
Normal file
|
@ -8,7 +8,8 @@ import itdelatrisu.opsu.objects.GameObject;
|
|||
import itdelatrisu.opsu.objects.curves.Vec2f;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
/**
|
||||
* This class is just a dummy {@link GameObject} to place in the middle of 2 GameObjects.
|
||||
|
@ -22,8 +23,8 @@ public class FakeGameObject extends GameObject {
|
|||
public FakeGameObject() {
|
||||
this.start = new Vec2f();
|
||||
this.end = new Vec2f();
|
||||
this.start.x = this.end.x = Options.width / 2;
|
||||
this.start.y = this.end.y = Options.height / 2;
|
||||
this.start.x = this.end.x = displayContainer.width / 2;
|
||||
this.start.y = this.end.y = displayContainer.height / 2;
|
||||
}
|
||||
|
||||
public FakeGameObject(GameObject start, GameObject end) {
|
||||
|
|
|
@ -5,7 +5,8 @@ import itdelatrisu.opsu.Utils;
|
|||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import yugecin.opsudance.movers.Mover;
|
||||
import yugecin.opsudance.movers.factories.AutoMoverFactory;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Created by Alex Wieser on 09.10.2016.
|
||||
|
@ -130,6 +131,6 @@ public class CombinedSpiralMover extends Mover {
|
|||
}
|
||||
|
||||
private boolean checkBounds(double[] pos) {
|
||||
return 0 < pos[0] && pos[0] < Options.width && 0 < pos[1] && pos[1] < Options.height;
|
||||
return 0 < pos[0] && pos[0] < displayContainer.width && 0 < pos[1] && pos[1] < displayContainer.height;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ import awlex.ospu.movers.CombinedSpiralMover;
|
|||
import yugecin.opsudance.movers.Mover;
|
||||
import awlex.ospu.movers.SpiralToMover;
|
||||
import yugecin.opsudance.movers.factories.MoverFactory;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
/**
|
||||
* Created by Alex Wieser on 09.10.2016.
|
||||
|
@ -87,7 +88,7 @@ public class SpiralMoverFactory implements MoverFactory {
|
|||
* @return
|
||||
*/
|
||||
private boolean checkBounds(double[] pos) {
|
||||
return 0 < pos[0] && pos[0] < Options.width && 0 < pos[1] && pos[1] < Options.height;
|
||||
return 0 < pos[0] && pos[0] < displayContainer.width && 0 < pos[1] && pos[1] < displayContainer.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package awlex.ospu.spinners;
|
||||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import yugecin.opsudance.options.Options;
|
||||
import yugecin.opsudance.spinners.Spinner;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Created by Alex Wieser on 09.10.2016.
|
||||
* WHO DO YOU THINK I AM?
|
||||
|
@ -42,11 +43,11 @@ public class SpiralSpinner extends Spinner {
|
|||
double ang;
|
||||
double rad;
|
||||
for (int i = 0; i < SIZE / 2; i++) {
|
||||
MAX_RAD = (int) (Options.height * .35);
|
||||
MAX_RAD = (int) (displayContainer.height * .35);
|
||||
ang = (DENSITY * (Math.PI / SIZE) * i);
|
||||
rad = (MAX_RAD / (SIZE / 2)) * i;
|
||||
int offsetX = Options.width / 2;
|
||||
int offsetY = Options.height / 2;
|
||||
int offsetX = displayContainer.width / 2;
|
||||
int offsetY = displayContainer.height / 2;
|
||||
points[SIZE / 2 - 1 - i] = new double[]{
|
||||
offsetX + rad * Math.cos(ang),
|
||||
offsetY + rad * Math.sin(ang)
|
||||
|
@ -83,12 +84,12 @@ public class SpiralSpinner extends Spinner {
|
|||
}
|
||||
|
||||
private void rotatePointAroundCenter(double[] point, double beta) {
|
||||
double angle = Math.atan2(point[1] - Options.height / 2, point[0] - Options.width / 2);
|
||||
double rad = Utils.distance(point[0], point[1], Options.width / 2, Options.height / 2);
|
||||
double angle = Math.atan2(point[1] - displayContainer.height / 2, point[0] - displayContainer.width / 2);
|
||||
double rad = Utils.distance(point[0], point[1], displayContainer.width / 2, displayContainer.height / 2);
|
||||
|
||||
//rotationMatrix
|
||||
point[0] = Options.width / 2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta));
|
||||
point[1] = Options.height / 2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
|
||||
point[0] = displayContainer.width / 2 + rad * (Math.cos(angle) * Math.cos(beta) - Math.sin(angle) * Math.sin(beta));
|
||||
point[1] = displayContainer.height / 2 + rad * (Math.cos(angle) * Math.sin(beta) + Math.sin(angle) * Math.cos(beta));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import itdelatrisu.opsu.audio.SoundController;
|
|||
import itdelatrisu.opsu.audio.SoundEffect;
|
||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||
import itdelatrisu.opsu.beatmap.HitObject;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.objects.curves.Curve;
|
||||
import itdelatrisu.opsu.replay.Replay;
|
||||
import itdelatrisu.opsu.replay.ReplayFrame;
|
||||
|
@ -42,25 +41,17 @@ import org.newdawn.slick.Animation;
|
|||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Image;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.utils.SlickUtil;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Holds game data and renders all related elements.
|
||||
*/
|
||||
public class GameData {
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
/** Delta multiplier for steady HP drain. */
|
||||
public static final float HP_DRAIN_MULTIPLIER = 1 / 200f;
|
||||
|
||||
|
@ -354,17 +345,10 @@ public class GameData {
|
|||
/** Whether this object is used for gameplay (true) or score viewing (false). */
|
||||
private boolean isGameplay;
|
||||
|
||||
/** Container dimensions. */
|
||||
private int width, height;
|
||||
|
||||
/**
|
||||
* Constructor for gameplay.
|
||||
* @param width container width
|
||||
* @param height container height
|
||||
*/
|
||||
public GameData(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
public GameData() {
|
||||
this.isGameplay = true;
|
||||
|
||||
clear();
|
||||
|
@ -375,12 +359,8 @@ public class GameData {
|
|||
* This will initialize all parameters and images needed for the
|
||||
* {@link #drawRankingElements(Graphics, Beatmap)} method.
|
||||
* @param s the ScoreData object
|
||||
* @param width container width
|
||||
* @param height container height
|
||||
*/
|
||||
public GameData(ScoreData s, int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
public GameData(ScoreData s) {
|
||||
this.isGameplay = false;
|
||||
|
||||
this.scoreData = s;
|
||||
|
@ -395,8 +375,9 @@ public class GameData {
|
|||
hitResultCount[HIT_300K] = 0;
|
||||
hitResultCount[HIT_100K] = s.katu;
|
||||
hitResultCount[HIT_MISS] = s.miss;
|
||||
this.replay = (s.replayString == null) ? null :
|
||||
instanceContainer.injectFields(new Replay(new File(config.replayDir, String.format("%s.osr", s.replayString))));
|
||||
if (s.replayString != null) {
|
||||
this.replay = new Replay(new File(config.replayDir, s.replayString + ".osr"));
|
||||
}
|
||||
|
||||
loadImages();
|
||||
}
|
||||
|
@ -622,6 +603,8 @@ public class GameData {
|
|||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void drawGameElements(Graphics g, boolean breakPeriod, boolean firstObject, float alpha) {
|
||||
int width = displayContainer.width;
|
||||
int height = displayContainer.height;
|
||||
boolean relaxAutoPilot = (GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
|
||||
int margin = (int) (width * 0.008f);
|
||||
float uiScale = GameImage.getUIscale();
|
||||
|
@ -813,6 +796,9 @@ public class GameData {
|
|||
* @param beatmap the beatmap
|
||||
*/
|
||||
public void drawRankingElements(Graphics g, Beatmap beatmap) {
|
||||
int width = displayContainer.width;
|
||||
int height = displayContainer.height;
|
||||
|
||||
// TODO Version 2 skins
|
||||
float rankingHeight = 75;
|
||||
float scoreTextScale = 1.0f;
|
||||
|
@ -925,7 +911,7 @@ public class GameData {
|
|||
if (hitResult.hitResultType == HitObjectType.SPINNER && hitResult.result != HIT_MISS) {
|
||||
Image spinnerOsu = GameImage.SPINNER_OSU.getImage();
|
||||
spinnerOsu.setAlpha(hitResult.alpha);
|
||||
spinnerOsu.drawCentered(width / 2, height / 4);
|
||||
spinnerOsu.drawCentered(displayContainer.width / 2, displayContainer.height / 4);
|
||||
spinnerOsu.setAlpha(1f);
|
||||
} else if (OPTION_SHOW_HIT_LIGHTING.state && !hitResult.hideResult && hitResult.result != HIT_MISS &&
|
||||
// hit lighting
|
||||
|
@ -1199,7 +1185,7 @@ public class GameData {
|
|||
// combo burst
|
||||
if (comboBurstIndex > -1 && OPTION_SHOW_COMBO_BURSTS.state) {
|
||||
int leftX = 0;
|
||||
int rightX = width - comboBurstImages[comboBurstIndex].getWidth();
|
||||
int rightX = displayContainer.width - comboBurstImages[comboBurstIndex].getWidth();
|
||||
if (comboBurstX < leftX) {
|
||||
comboBurstX += (delta / 2f) * GameImage.getUIscale();
|
||||
if (comboBurstX > leftX)
|
||||
|
@ -1260,7 +1246,7 @@ public class GameData {
|
|||
}
|
||||
comboBurstAlpha = 0.8f;
|
||||
if ((comboBurstIndex % 2) == 0) {
|
||||
comboBurstX = width;
|
||||
comboBurstX = displayContainer.width;
|
||||
} else {
|
||||
comboBurstX = comboBurstImages[0].getWidth() * -1;
|
||||
}
|
||||
|
@ -1603,7 +1589,7 @@ public class GameData {
|
|||
|
||||
replay = new Replay();
|
||||
replay.mode = Beatmap.MODE_OSU;
|
||||
replay.version = Updater.get().getBuildDate();
|
||||
replay.version = updater.getBuildDate();
|
||||
replay.beatmapHash = (beatmap == null) ? "" : beatmap.md5Hash;
|
||||
replay.playerName = ""; // TODO
|
||||
replay.replayHash = Long.toString(System.currentTimeMillis()); // TODO
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package itdelatrisu.opsu;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import itdelatrisu.opsu.ui.Fonts;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -30,8 +31,7 @@ import org.newdawn.slick.SlickException;
|
|||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.utils.SlickUtil;
|
||||
|
||||
|
@ -249,6 +249,16 @@ public enum GameImage {
|
|||
CONTROL_SLIDER_BALL ("control-sliderball", "png", false, false),
|
||||
CONTROL_CHECK_ON ("control-check-on", "png", false, false),
|
||||
CONTROL_CHECK_OFF ("control-check-off", "png", false, false),
|
||||
MENU_NAV_AUDIO ("menu-nav-audio", "png", false, false),
|
||||
MENU_NAV_CUSTOM ("menu-nav-custom", "png", false, false),
|
||||
MENU_NAV_GAMEPLAY ("menu-nav-gameplay", "png", false, false),
|
||||
MENU_NAV_GENERAL ("menu-nav-general", "png", false, false),
|
||||
MENU_NAV_GRAPHICS ("menu-nav-graphics", "png", false, false),
|
||||
MENU_NAV_INPUT ("menu-nav-input", "png", false, false),
|
||||
MENU_NAV_SKIN ("menu-nav-skin", "png", false, false),
|
||||
MENU_NAV_ADVANCED ("menu-nav-advanced", "png", false, false),
|
||||
MENU_NAV_DANCE ("menu-nav-dance", "png", false, false),
|
||||
MENU_NAV_PIPPI ("menu-nav-pippi", "png", false, false),
|
||||
VOLUME ("volume-bg", "png", false, false) {
|
||||
@Override
|
||||
protected Image process_sub(Image img, int w, int h) {
|
||||
|
@ -733,7 +743,7 @@ public enum GameImage {
|
|||
|
||||
String err = String.format("Could not find default image '%s'.", filename);
|
||||
Log.warn(err);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -776,31 +786,33 @@ public enum GameImage {
|
|||
* @return an array of the loaded images, or null if not found
|
||||
*/
|
||||
private Image[] loadImageArray(File dir) {
|
||||
if (filenameFormat != null) {
|
||||
for (String suffix : getSuffixes()) {
|
||||
List<Image> list = new ArrayList<Image>();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
// look for next image
|
||||
String filenameFormatted = String.format(filenameFormat + suffix, i++);
|
||||
String name = getImageFileName(filenameFormatted, dir, type, true);
|
||||
if (name == null)
|
||||
break;
|
||||
if (filenameFormat == null) {
|
||||
return null;
|
||||
}
|
||||
for (String suffix : getSuffixes()) {
|
||||
List<Image> list = new ArrayList<Image>();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
// look for next image
|
||||
String filenameFormatted = String.format(filenameFormat + suffix, i++);
|
||||
String name = getImageFileName(filenameFormatted, dir, type, true);
|
||||
if (name == null)
|
||||
break;
|
||||
|
||||
// add image to list
|
||||
try {
|
||||
Image img = new Image(name);
|
||||
if (suffix.equals(HD_SUFFIX))
|
||||
img = img.getScaledCopy(0.5f);
|
||||
list.add(img);
|
||||
} catch (SlickException e) {
|
||||
EventBus.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", name), BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
break;
|
||||
}
|
||||
// add image to list
|
||||
try {
|
||||
Image img = new Image(name);
|
||||
if (suffix.equals(HD_SUFFIX))
|
||||
img = img.getScaledCopy(0.5f);
|
||||
list.add(img);
|
||||
} catch (SlickException e) {
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
String.format("Failed to set image '%s'.", name), Colors.BUB_RED);
|
||||
break;
|
||||
}
|
||||
if (!list.isEmpty())
|
||||
return list.toArray(new Image[list.size()]);
|
||||
}
|
||||
if (!list.isEmpty())
|
||||
return list.toArray(new Image[list.size()]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -813,15 +825,17 @@ public enum GameImage {
|
|||
private Image loadImageSingle(File dir) {
|
||||
for (String suffix : getSuffixes()) {
|
||||
String name = getImageFileName(filename + suffix, dir, type, true);
|
||||
if (name != null) {
|
||||
try {
|
||||
Image img = new Image(name);
|
||||
if (suffix.equals(HD_SUFFIX))
|
||||
img = img.getScaledCopy(0.5f);
|
||||
return img;
|
||||
} catch (SlickException e) {
|
||||
EventBus.post(new BubbleNotificationEvent(String.format("Failed to set image '%s'.", filename), BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
}
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Image img = new Image(name);
|
||||
if (suffix.equals(HD_SUFFIX))
|
||||
img = img.getScaledCopy(0.5f);
|
||||
return img;
|
||||
} catch (SlickException e) {
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
String.format("Failed to set image '%s'.", filename), Colors.BUB_RED);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -865,7 +879,8 @@ public enum GameImage {
|
|||
skinImages = null;
|
||||
}
|
||||
} catch (SlickException e) {
|
||||
ErrorHandler.error(String.format("Failed to destroy beatmap skin images for '%s'.", this.name()), e).show();
|
||||
String msg = String.format("Failed to destroy beatmap skin images for '%s'.", this.name());
|
||||
ErrorHandler.explode(msg, e, ErrorHandler.DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,39 +27,40 @@ import java.util.Collections;
|
|||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.Input;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
|
||||
/**
|
||||
* Game mods.
|
||||
*/
|
||||
public enum GameMod {
|
||||
EASY (Category.EASY, 0, GameImage.MOD_EASY, "EZ", 2, Input.KEY_Q, 0.5f,
|
||||
EASY (Category.EASY, 0, GameImage.MOD_EASY, "EZ", 2, KEY_Q, 0.5f,
|
||||
"Easy", "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required."),
|
||||
NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, Input.KEY_W, 0.5f,
|
||||
NO_FAIL (Category.EASY, 1, GameImage.MOD_NO_FAIL, "NF", 1, KEY_W, 0.5f,
|
||||
"NoFail", "You can't fail. No matter what."),
|
||||
HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, Input.KEY_E, 0.3f,
|
||||
HALF_TIME (Category.EASY, 2, GameImage.MOD_HALF_TIME, "HT", 256, KEY_E, 0.3f,
|
||||
"HalfTime", "Less zoom."),
|
||||
HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, Input.KEY_A, 1.06f,
|
||||
HARD_ROCK (Category.HARD, 0, GameImage.MOD_HARD_ROCK, "HR", 16, KEY_A, 1.06f,
|
||||
"HardRock", "Everything just got a bit harder..."),
|
||||
SUDDEN_DEATH (Category.HARD, 1, GameImage.MOD_SUDDEN_DEATH, "SD", 32, Input.KEY_S, 1f,
|
||||
SUDDEN_DEATH (Category.HARD, 1, GameImage.MOD_SUDDEN_DEATH, "SD", 32, KEY_S, 1f,
|
||||
"SuddenDeath", "Miss a note and fail."),
|
||||
// PERFECT (Category.HARD, 1, GameImage.MOD_PERFECT, "PF", 64, Input.KEY_S, 1f,
|
||||
// "Perfect", "SS or quit."),
|
||||
DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, Input.KEY_D, 1.12f,
|
||||
DOUBLE_TIME (Category.HARD, 2, GameImage.MOD_DOUBLE_TIME, "DT", 64, KEY_D, 1.12f,
|
||||
"DoubleTime", "Zoooooooooom."),
|
||||
// NIGHTCORE (Category.HARD, 2, GameImage.MOD_NIGHTCORE, "NT", 64, Input.KEY_D, 1.12f,
|
||||
// "Nightcore", "uguuuuuuuu"),
|
||||
HIDDEN (Category.HARD, 3, GameImage.MOD_HIDDEN, "HD", 8, Input.KEY_F, 1.06f,
|
||||
HIDDEN (Category.HARD, 3, GameImage.MOD_HIDDEN, "HD", 8, KEY_F, 1.06f,
|
||||
"Hidden", "Play with no approach circles and fading notes for a slight score advantage."),
|
||||
FLASHLIGHT (Category.HARD, 4, GameImage.MOD_FLASHLIGHT, "FL", 1024, Input.KEY_G, 1.12f,
|
||||
FLASHLIGHT (Category.HARD, 4, GameImage.MOD_FLASHLIGHT, "FL", 1024, KEY_G, 1.12f,
|
||||
"Flashlight", "Restricted view area."),
|
||||
RELAX (Category.SPECIAL, 0, GameImage.MOD_RELAX, "RL", 128, Input.KEY_Z, 0f,
|
||||
RELAX (Category.SPECIAL, 0, GameImage.MOD_RELAX, "RL", 128, KEY_Z, 0f,
|
||||
"Relax", "You don't need to click.\nGive your clicking/tapping finger a break from the heat of things.\n**UNRANKED**"),
|
||||
AUTOPILOT (Category.SPECIAL, 1, GameImage.MOD_AUTOPILOT, "AP", 8192, Input.KEY_X, 0f,
|
||||
AUTOPILOT (Category.SPECIAL, 1, GameImage.MOD_AUTOPILOT, "AP", 8192, KEY_X, 0f,
|
||||
"Relax2", "Automatic cursor movement - just follow the rhythm.\n**UNRANKED**"),
|
||||
SPUN_OUT (Category.SPECIAL, 2, GameImage.MOD_SPUN_OUT, "SO", 4096, Input.KEY_C, 0.9f,
|
||||
SPUN_OUT (Category.SPECIAL, 2, GameImage.MOD_SPUN_OUT, "SO", 4096, KEY_C, 0.9f,
|
||||
"SpunOut", "Spinners will be automatically completed."),
|
||||
AUTO (Category.SPECIAL, 3, GameImage.MOD_AUTO, "", 2048, Input.KEY_V, 1f,
|
||||
AUTO (Category.SPECIAL, 3, GameImage.MOD_AUTO, "", 2048, KEY_V, 1f,
|
||||
"Autoplay", "Watch a perfect automated play through the song.");
|
||||
|
||||
/** Mod categories. */
|
||||
|
|
|
@ -18,87 +18,75 @@
|
|||
|
||||
package itdelatrisu.opsu;
|
||||
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.utils.ManifestWrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Native loader, based on the JarSplice launcher.
|
||||
*
|
||||
* @author http://ninjacave.com
|
||||
*/
|
||||
public class NativeLoader {
|
||||
/** The directory to unpack natives to. */
|
||||
private final File nativeDir;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param dir the directory to unpack natives to
|
||||
*/
|
||||
public NativeLoader(File dir) {
|
||||
nativeDir = dir;
|
||||
public class NativeLoader {
|
||||
|
||||
public static void setNativePath() {
|
||||
String nativepath = config.NATIVE_DIR.getAbsolutePath();
|
||||
System.setProperty("org.lwjgl.librarypath", nativepath);
|
||||
System.setProperty("java.library.path", nativepath);
|
||||
|
||||
try {
|
||||
// Workaround for "java.library.path" property being read-only.
|
||||
// http://stackoverflow.com/a/24988095
|
||||
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
|
||||
fieldSysPath.setAccessible(true);
|
||||
fieldSysPath.set(null, null);
|
||||
} catch (Exception e) {
|
||||
Log.warn("Failed to set 'sys_paths' field.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks natives for the current operating system to the natives directory.
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
public void loadNatives() throws IOException {
|
||||
if (!nativeDir.exists())
|
||||
nativeDir.mkdir();
|
||||
|
||||
JarFile jarFile = Utils.getJarFile();
|
||||
if (jarFile == null)
|
||||
return;
|
||||
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry e = entries.nextElement();
|
||||
if (e == null)
|
||||
break;
|
||||
|
||||
File f = new File(nativeDir, e.getName());
|
||||
if (isNativeFile(e.getName()) && !e.isDirectory() && e.getName().indexOf('/') == -1 && !f.exists()) {
|
||||
InputStream in = jarFile.getInputStream(jarFile.getEntry(e.getName()));
|
||||
OutputStream out = new FileOutputStream(f);
|
||||
|
||||
byte[] buffer = new byte[65536];
|
||||
int bufferSize;
|
||||
while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1)
|
||||
out.write(buffer, 0, bufferSize);
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
public static void loadNatives(JarFile jarfile, ManifestWrapper manifest) throws IOException {
|
||||
if (!config.NATIVE_DIR.exists() && !config.NATIVE_DIR.mkdir()) {
|
||||
String msg = String.format("Could not create folder '%s'",
|
||||
config.NATIVE_DIR.getAbsolutePath());
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given file name is a native file for the current operating system.
|
||||
* @param entryName the file name
|
||||
* @return true if the file is a native that should be loaded, false otherwise
|
||||
*/
|
||||
private boolean isNativeFile(String entryName) {
|
||||
String osName = System.getProperty("os.name");
|
||||
String name = entryName.toLowerCase();
|
||||
|
||||
String nativekey = null;
|
||||
if (osName.startsWith("Win")) {
|
||||
if (name.endsWith(".dll"))
|
||||
return true;
|
||||
nativekey = "WinNatives";
|
||||
} else if (osName.startsWith("Linux")) {
|
||||
if (name.endsWith(".so"))
|
||||
return true;
|
||||
nativekey = "NixNatives";
|
||||
} else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
|
||||
if (name.endsWith(".dylib") || name.endsWith(".jnilib"))
|
||||
return true;
|
||||
nativekey = "MacNatives";
|
||||
}
|
||||
|
||||
if (nativekey == null) {
|
||||
Log.warn("Cannot determine natives for os " + osName);
|
||||
return;
|
||||
}
|
||||
|
||||
String natives = manifest.valueOrDefault(null, nativekey, null);
|
||||
if (natives == null) {
|
||||
String msg = String.format("No entry for '%s' in manifest, jar is badly packed or damaged",
|
||||
nativekey);
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
String[] nativefiles = natives.split(",");
|
||||
for (String nativefile : nativefiles) {
|
||||
File unpackedFile = new File(config.NATIVE_DIR, nativefile);
|
||||
if (unpackedFile.exists()) {
|
||||
continue;
|
||||
}
|
||||
Utils.unpackFromJar(jarfile, unpackedFile, nativefile);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,22 +20,13 @@ package itdelatrisu.opsu;
|
|||
|
||||
import itdelatrisu.opsu.downloads.Download;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Scanner;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
|
@ -50,41 +41,21 @@ import org.json.JSONObject;
|
|||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Animation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.util.Log;
|
||||
|
||||
import com.sun.jna.platform.FileUtils;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.NotNull;
|
||||
import yugecin.opsudance.core.Nullable;
|
||||
import yugecin.opsudance.options.Options;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Contains miscellaneous utilities.
|
||||
*/
|
||||
public class Utils {
|
||||
/**
|
||||
* List of illegal filename characters.
|
||||
* @see #cleanFileName(String, char)
|
||||
*/
|
||||
private final static int[] illegalChars = {
|
||||
34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47
|
||||
};
|
||||
static {
|
||||
Arrays.sort(illegalChars);
|
||||
}
|
||||
|
||||
// This class should not be instantiated.
|
||||
private Utils() {}
|
||||
|
||||
/**
|
||||
* Initializes game settings and class data.
|
||||
*/
|
||||
public static void init(DisplayContainer displayContainer) {
|
||||
// TODO clean this up
|
||||
|
||||
// game settings
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an animation based on its center.
|
||||
|
@ -183,15 +154,12 @@ public class Utils {
|
|||
* @return true if pressed
|
||||
*/
|
||||
public static boolean isGameKeyPressed() {
|
||||
/*
|
||||
boolean mouseDown = !Options.isMouseDisabled() && (
|
||||
input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) ||
|
||||
input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON));
|
||||
return (mouseDown ||
|
||||
input.isKeyDown(Options.getGameKeyLeft()) ||
|
||||
input.isKeyDown(Options.getGameKeyRight()));
|
||||
*/
|
||||
return true;
|
||||
return
|
||||
input.isKeyPressed(Options.OPTION_KEY_LEFT.intval) ||
|
||||
input.isKeyPressed(Options.OPTION_KEY_RIGHT.intval) ||
|
||||
(!Options.OPTION_DISABLE_MOUSE_BUTTONS.state && (
|
||||
input.isMousePressed(Input.MOUSE_LEFT_BUTTON) ||
|
||||
input.isMousePressed(Input.MOUSE_RIGHT_BUTTON)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,26 +178,31 @@ public class Utils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Cleans a file name.
|
||||
* @param badFileName the original name string
|
||||
* @param replace the character to replace illegal characters with (or 0 if none)
|
||||
* @return the cleaned file name
|
||||
* @author Sarel Botha (http://stackoverflow.com/a/5626340)
|
||||
* Changes bad characters to the replacement char given.
|
||||
* Bad characters:
|
||||
* non-printable (0-31)
|
||||
* " (34) * (42) / (47) : (58)
|
||||
* < (60) > (62) ? (63) \ (92)
|
||||
* DEL (124)
|
||||
*/
|
||||
public static String cleanFileName(String badFileName, char replace) {
|
||||
if (badFileName == null)
|
||||
return null;
|
||||
|
||||
boolean doReplace = (replace > 0 && Arrays.binarySearch(illegalChars, replace) < 0);
|
||||
StringBuilder cleanName = new StringBuilder();
|
||||
for (int i = 0, n = badFileName.length(); i < n; i++) {
|
||||
int c = badFileName.charAt(i);
|
||||
if (Arrays.binarySearch(illegalChars, c) < 0)
|
||||
cleanName.append((char) c);
|
||||
else if (doReplace)
|
||||
cleanName.append(replace);
|
||||
public static String cleanFileName(@NotNull String badFileName, char replacement) {
|
||||
char[] chars = badFileName.toCharArray();
|
||||
long additionalBadChars =
|
||||
1L << (34 - 32)|
|
||||
1L << (42 - 32)|
|
||||
1L << (47 - 32)|
|
||||
1L << (58 - 32)|
|
||||
1L << (60 - 32)|
|
||||
1L << (62 - 32)|
|
||||
1L << (63 - 32)|
|
||||
1L << (92 - 32);
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (c < 32 || c == 124 || (c < 93 && 0 != (additionalBadChars & (1L << (c - 32))))) {
|
||||
chars[i] = replacement;
|
||||
}
|
||||
}
|
||||
return cleanName.toString();
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -338,7 +311,7 @@ public class Utils {
|
|||
try {
|
||||
json = new JSONObject(s);
|
||||
} catch (JSONException e) {
|
||||
ErrorHandler.error("Failed to create JSON object.", e).show();
|
||||
explode("Failed to create JSON object.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
return json;
|
||||
|
@ -357,7 +330,7 @@ public class Utils {
|
|||
try {
|
||||
json = new JSONArray(s);
|
||||
} catch (JSONException e) {
|
||||
ErrorHandler.error("Failed to create JSON array.", e).show();
|
||||
explode("Failed to create JSON array.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
return json;
|
||||
|
@ -399,7 +372,7 @@ public class Utils {
|
|||
result.append(String.format("%02x", b));
|
||||
return result.toString();
|
||||
} catch (NoSuchAlgorithmException | IOException e) {
|
||||
ErrorHandler.error("Failed to calculate MD5 hash.", e).show();
|
||||
explode("Failed to calculate MD5 hash.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -418,43 +391,6 @@ public class Utils {
|
|||
return String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the application is running within a JAR.
|
||||
* @return true if JAR, false if file
|
||||
*/
|
||||
public static boolean isJarRunning() {
|
||||
return Utils.class.getResource(String.format("%s.class", Utils.class.getSimpleName())).toString().startsWith("jar:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JarFile for the application.
|
||||
* @return the JAR file, or null if it could not be determined
|
||||
*/
|
||||
public static JarFile getJarFile() {
|
||||
if (!isJarRunning())
|
||||
return null;
|
||||
|
||||
try {
|
||||
return new JarFile(new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI()), false);
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
Log.error("Could not determine the JAR file.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory where the application is being run.
|
||||
* @return the directory, or null if it could not be determined
|
||||
*/
|
||||
public static File getRunningDirectory() {
|
||||
try {
|
||||
return new File(Utils.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
|
||||
} catch (URISyntaxException e) {
|
||||
Log.error("Could not get the running directory.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the integer string argument as a boolean:
|
||||
* {@code 1} is {@code true}, and all other values are {@code false}.
|
||||
|
@ -470,8 +406,9 @@ public class Utils {
|
|||
* most recent update to the working directory (e.g. fetch or successful push).
|
||||
* @return the 40-character SHA-1 hash, or null if it could not be determined
|
||||
*/
|
||||
@Nullable
|
||||
public static String getGitHash() {
|
||||
if (isJarRunning())
|
||||
if (env.isJarRunning)
|
||||
return null;
|
||||
File f = new File(".git/refs/remotes/origin/master");
|
||||
if (!f.isFile())
|
||||
|
@ -516,11 +453,20 @@ public class Utils {
|
|||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
public static int getQuadrant(double x, double y) {
|
||||
if (x < Options.width / 2d) {
|
||||
return y < Options.height / 2d ? 2 : 3;
|
||||
}
|
||||
return y < Options.height / 2d ? 1 : 4;
|
||||
/**
|
||||
* Gets the region where the given point is in.
|
||||
* First bit is set if x > half
|
||||
* Second bit is set if y > half
|
||||
*
|
||||
* 2 | 3
|
||||
* --+--
|
||||
* 0 | 1
|
||||
*/
|
||||
public static int getRegion(double x, double y) {
|
||||
int q = 0;
|
||||
if (y < displayContainer.height / 2d) q = 2;
|
||||
if (x < displayContainer.width / 2d) q |= 1;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -537,24 +483,24 @@ public class Utils {
|
|||
*/
|
||||
|
||||
public static float[] mirrorPoint(float x, float y) {
|
||||
double dx = x - Options.width / 2d;
|
||||
double dy = y - Options.height / 2d;
|
||||
double dx = x - displayContainer.width / 2d;
|
||||
double dy = y - displayContainer.height / 2d;
|
||||
double ang = Math.atan2(dy, dx);
|
||||
double d = -Math.sqrt(dx * dx + dy * dy);
|
||||
return new float[]{
|
||||
(float) (Options.width / 2d + Math.cos(ang) * d),
|
||||
(float) (Options.height / 2d + Math.sin(ang) * d)
|
||||
(float) (displayContainer.width / 2d + Math.cos(ang) * d),
|
||||
(float) (displayContainer.height / 2d + Math.sin(ang) * d)
|
||||
};
|
||||
}
|
||||
|
||||
public static float[] mirrorPoint(float x, float y, float degrees) {
|
||||
double dx = x - Options.width / 2d;
|
||||
double dy = y - Options.height / 2d;
|
||||
double dx = x - displayContainer.width / 2d;
|
||||
double dy = y - displayContainer.height / 2d;
|
||||
double ang = Math.atan2(dy, dx) + (degrees * Math.PI / 180d);
|
||||
double d = Math.sqrt(dx * dx + dy * dy);
|
||||
return new float[]{
|
||||
(float) (Options.width / 2d + Math.cos(ang) * d),
|
||||
(float) (Options.height / 2d + Math.sin(ang) * d)
|
||||
(float) (displayContainer.width / 2d + Math.cos(ang) * d),
|
||||
(float) (displayContainer.height / 2d + Math.sin(ang) * d)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -573,4 +519,19 @@ public class Utils {
|
|||
key != Keyboard.KEY_F7 && key != Keyboard.KEY_F10 && key != Keyboard.KEY_F12);
|
||||
}
|
||||
|
||||
public static void unpackFromJar(@NotNull JarFile jarfile, @NotNull File unpackedFile,
|
||||
@NotNull String filename) throws IOException {
|
||||
InputStream in = jarfile.getInputStream(jarfile.getEntry(filename));
|
||||
OutputStream out = new FileOutputStream(unpackedFile);
|
||||
|
||||
byte[] buffer = new byte[65536];
|
||||
int bufferSize;
|
||||
while ((bufferSize = in.read(buffer, 0, buffer.length)) != -1) {
|
||||
out.write(buffer, 0, bufferSize);
|
||||
}
|
||||
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package itdelatrisu.opsu.audio;
|
||||
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
@ -14,6 +12,8 @@ import javax.sound.sampled.FloatControl;
|
|||
import javax.sound.sampled.LineListener;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Extension of Clip that allows playing multiple copies of a Clip simultaneously.
|
||||
* http://stackoverflow.com/questions/1854616/
|
||||
|
@ -194,7 +194,8 @@ public class MultiClip {
|
|||
try {
|
||||
audioIn.close();
|
||||
} catch (IOException e) {
|
||||
ErrorHandler.error(String.format("Could not close AudioInputStream for MultiClip %s.", name), e).show();
|
||||
explode(String.format("Could not close AudioInputStream for MultiClip %s.", name), e,
|
||||
DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import javax.sound.sampled.AudioFileFormat;
|
|||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
@ -44,11 +45,10 @@ import org.newdawn.slick.openal.SoundStore;
|
|||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import org.tritonus.share.sampled.file.TAudioFileFormat;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -103,7 +103,8 @@ public class MusicController {
|
|||
if (lastBeatmap == null || !beatmap.audioFilename.equals(lastBeatmap.audioFilename)) {
|
||||
final File audioFile = beatmap.audioFilename;
|
||||
if (!audioFile.isFile() && !ResourceLoader.resourceExists(audioFile.getPath())) {
|
||||
EventBus.post(new BarNotificationEvent(String.format("Could not find track '%s'.", audioFile.getName())));
|
||||
BarNotifListener.EVENT.make().onBarNotif(String.format("Could not find track '%s'.",
|
||||
audioFile.getName()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,7 @@ public class MusicController {
|
|||
} catch (Exception e) {
|
||||
String err = String.format("Could not play track '%s'.", file.getName());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -575,7 +576,7 @@ public class MusicController {
|
|||
|
||||
player = null;
|
||||
} catch (Exception e) {
|
||||
ErrorHandler.error("Failed to destroy OpenAL.", e).show();
|
||||
explode("Failed to destroy OpenAL.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,15 +36,15 @@ import javax.sound.sampled.DataLine;
|
|||
import javax.sound.sampled.LineListener;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -104,7 +104,7 @@ public class SoundController {
|
|||
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
|
||||
return loadClip(ref, audioIn, isMP3);
|
||||
} catch (Exception e) {
|
||||
ErrorHandler.error(String.format("Failed to load file '%s'.", ref), e).show();
|
||||
explode(String.format("Failed to load file '%s'.", ref), e, DEFAULT_OPTIONS);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +220,8 @@ public class SoundController {
|
|||
// menu and game sounds
|
||||
for (SoundEffect s : SoundEffect.values()) {
|
||||
if ((currentFileName = getSoundFileName(s.getFileName())) == null) {
|
||||
EventBus.post(new BubbleNotificationEvent("Could not find sound file " + s.getFileName(), BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
"Could not find sound file " + s.getFileName(), Colors.BUB_ORANGE);
|
||||
continue;
|
||||
}
|
||||
MultiClip newClip = loadClip(currentFileName, currentFileName.endsWith(".mp3"));
|
||||
|
@ -239,7 +240,8 @@ public class SoundController {
|
|||
for (HitSound s : HitSound.values()) {
|
||||
String filename = String.format("%s-%s", ss.getName(), s.getFileName());
|
||||
if ((currentFileName = getSoundFileName(filename)) == null) {
|
||||
EventBus.post(new BubbleNotificationEvent("Could not find hit sound file " + filename, BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
"Could not find hit sound file " + filename, Colors.BUB_ORANGE);
|
||||
continue;
|
||||
}
|
||||
MultiClip newClip = loadClip(currentFileName, false);
|
||||
|
@ -283,7 +285,7 @@ public class SoundController {
|
|||
try {
|
||||
clip.start(volume, listener);
|
||||
} catch (LineUnavailableException e) {
|
||||
ErrorHandler.error(String.format("Could not start a clip '%s'.", clip.getName()), e).show();
|
||||
explode(String.format("Could not start a clip '%s'.", clip.getName()), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +398,8 @@ public class SoundController {
|
|||
|
||||
@Override
|
||||
public void error() {
|
||||
EventBus.post(new BarNotificationEvent("Failed to download track preview."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"Failed to download track preview");
|
||||
}
|
||||
});
|
||||
try {
|
||||
|
|
|
@ -31,16 +31,15 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.core.Nullable;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -48,12 +47,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class BeatmapParser {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
/** The string lookup database. */
|
||||
private static HashMap<String, String> stringdb = new HashMap<String, String>();
|
||||
|
||||
|
@ -78,14 +71,9 @@ public class BeatmapParser {
|
|||
/** If no Provider supports a MessageDigestSpi implementation for the MD5 algorithm. */
|
||||
private boolean hasNoMD5Algorithm = false;
|
||||
|
||||
@Inject
|
||||
public BeatmapParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes parser for each OSU file in a root directory and
|
||||
* adds the beatmaps to a new BeatmapSetList.
|
||||
* @param root the root directory (search has depth 1)
|
||||
*/
|
||||
public void parseAll() {
|
||||
// create a new BeatmapSetList
|
||||
|
@ -93,7 +81,7 @@ public class BeatmapParser {
|
|||
|
||||
// create a new watch service
|
||||
if (OPTION_ENABLE_WATCH_SERVICE.state) {
|
||||
BeatmapWatchService.create(instanceContainer);
|
||||
BeatmapWatchService.create();
|
||||
}
|
||||
|
||||
// parse all directories
|
||||
|
@ -106,8 +94,8 @@ public class BeatmapParser {
|
|||
* @param dirs the array of directories to parse
|
||||
* @return the last BeatmapSetNode parsed, or null if none
|
||||
*/
|
||||
public BeatmapSetNode parseDirectories(File[] dirs) {
|
||||
if (dirs == null)
|
||||
public BeatmapSetNode parseDirectories(@Nullable File[] dirs) {
|
||||
if (dirs == null || dirs.length == 0)
|
||||
return null;
|
||||
|
||||
// progress tracking
|
||||
|
@ -172,8 +160,8 @@ public class BeatmapParser {
|
|||
try {
|
||||
beatmap = parseFile(file, dir, beatmaps, false);
|
||||
} catch(Exception e) {
|
||||
Log.error("could not parse beatmap " + file.getName() + ": " + e.getMessage());
|
||||
EventBus.post(new BubbleNotificationEvent("Could not parse beatmap " + file.getName(), BubbleNotificationEvent.COLOR_ORANGE));
|
||||
logAndShowErrorNotification(e, "Could not parse beatmap %s: %s",
|
||||
file.getName(), e.getMessage());
|
||||
}
|
||||
|
||||
// add to parsed beatmap list
|
||||
|
@ -260,11 +248,9 @@ public class BeatmapParser {
|
|||
}
|
||||
map.timingPoints.trimToSize();
|
||||
} catch (IOException e) {
|
||||
String err = String.format("Failed to read file '%s'.", map.getFile().getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
logAndShowErrorNotification(e, "Failed to read file '%s'.", map.getFile().getAbsolutePath());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
ErrorHandler.error("Failed to get MD5 hash stream.", e).show();
|
||||
explode("Failed to get MD5 hash stream.", e, DEFAULT_OPTIONS);
|
||||
|
||||
// retry without MD5
|
||||
hasNoMD5Algorithm = true;
|
||||
|
@ -665,11 +651,9 @@ public class BeatmapParser {
|
|||
if (md5stream != null)
|
||||
beatmap.md5Hash = md5stream.getMD5();
|
||||
} catch (IOException e) {
|
||||
String err = String.format("Failed to read file '%s'.", file.getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
logAndShowErrorNotification(e, "Failed to read file '%s'.", file.getAbsolutePath());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
ErrorHandler.error("Failed to get MD5 hash stream.", e).show();
|
||||
explode("Failed to get MD5 hash stream.", e, DEFAULT_OPTIONS);
|
||||
|
||||
// retry without MD5
|
||||
hasNoMD5Algorithm = true;
|
||||
|
@ -748,9 +732,8 @@ public class BeatmapParser {
|
|||
}
|
||||
beatmap.timingPoints.trimToSize();
|
||||
} catch (IOException e) {
|
||||
String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
logAndShowErrorNotification(e, "Failed to read file '%s'.",
|
||||
beatmap.getFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -828,12 +811,12 @@ public class BeatmapParser {
|
|||
|
||||
// check that all objects were parsed
|
||||
if (objectIndex != beatmap.objects.length)
|
||||
ErrorHandler.error(String.format("Parsed %d objects for beatmap '%s', %d objects expected.",
|
||||
objectIndex, beatmap.toString(), beatmap.objects.length), new Exception("no")).show();
|
||||
explode(String.format("Parsed %d objects for beatmap '%s', %d objects expected.",
|
||||
objectIndex, beatmap.toString(), beatmap.objects.length), new Exception("no"),
|
||||
DEFAULT_OPTIONS);
|
||||
} catch (IOException e) {
|
||||
String err = String.format("Failed to read file '%s'.", beatmap.getFile().getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
logAndShowErrorNotification(e, "Failed to read file '%s'.",
|
||||
beatmap.getFile().getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -904,4 +887,10 @@ public class BeatmapParser {
|
|||
return DBString;
|
||||
}
|
||||
|
||||
private static void logAndShowErrorNotification(Exception e, String message, Object... formatArgs) {
|
||||
message = String.format(message, formatArgs);
|
||||
Log.error(message, e);
|
||||
BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED);
|
||||
}
|
||||
|
||||
}
|
|
@ -21,8 +21,8 @@ package itdelatrisu.opsu.beatmap;
|
|||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.audio.MusicController;
|
||||
import itdelatrisu.opsu.db.BeatmapDB;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -215,7 +215,7 @@ public class BeatmapSetList {
|
|||
try {
|
||||
Utils.deleteToTrash(dir);
|
||||
} catch (IOException e) {
|
||||
EventBus.post(new BubbleNotificationEvent("Could not delete song group", BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Could not delete song group", Colors.BUB_ORANGE);
|
||||
}
|
||||
if (ws != null)
|
||||
ws.resume();
|
||||
|
@ -271,7 +271,7 @@ public class BeatmapSetList {
|
|||
try {
|
||||
Utils.deleteToTrash(file);
|
||||
} catch (IOException e) {
|
||||
EventBus.post(new BubbleNotificationEvent("Could not delete song", BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Could not delete song", Colors.BUB_ORANGE);
|
||||
}
|
||||
if (ws != null)
|
||||
ws.resume();
|
||||
|
|
|
@ -38,12 +38,12 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/*
|
||||
|
@ -83,6 +83,7 @@ import static yugecin.opsudance.options.Options.*;
|
|||
* @author The Java Tutorials (http://docs.oracle.com/javase/tutorial/essential/io/examples/WatchDir.java) (base)
|
||||
*/
|
||||
public class BeatmapWatchService {
|
||||
|
||||
/** Beatmap watcher service instance. */
|
||||
private static BeatmapWatchService ws;
|
||||
|
||||
|
@ -90,17 +91,17 @@ public class BeatmapWatchService {
|
|||
* Creates a new watch service instance (overwriting any previous instance),
|
||||
* registers the beatmap directory, and starts processing events.
|
||||
*/
|
||||
public static void create(InstanceContainer instanceContainer) {
|
||||
public static void create() {
|
||||
// close the existing watch service
|
||||
destroy();
|
||||
|
||||
// create a new watch service
|
||||
try {
|
||||
ws = instanceContainer.provide(BeatmapWatchService.class);
|
||||
ws.register(instanceContainer.provide(Configuration.class).beatmapDir.toPath());
|
||||
ws = new BeatmapWatchService();
|
||||
ws.register(config.beatmapDir.toPath());
|
||||
} catch (IOException e) {
|
||||
Log.error("Could not create watch service", e);
|
||||
EventBus.post(new BubbleNotificationEvent("Could not create watch service", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Could not create watch service", Colors.BUB_RED);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -121,8 +122,9 @@ public class BeatmapWatchService {
|
|||
ws.service.shutdownNow();
|
||||
ws = null;
|
||||
} catch (IOException e) {
|
||||
Log.error("An I/O exception occurred while closing the previous watch service.", e);
|
||||
EventBus.post(new BubbleNotificationEvent("An I/O exception occurred while closing the previous watch service.", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
String msg = "An I/O exception occurred while closing the previous watch service.";
|
||||
Log.error(msg, e);
|
||||
BarNotifListener.EVENT.make().onBarNotif(msg);
|
||||
ws = null;
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +139,10 @@ public class BeatmapWatchService {
|
|||
return ws;
|
||||
}
|
||||
|
||||
/** Watch service listener interface. */
|
||||
/**
|
||||
* Watch service listener interface.
|
||||
* TODO: replace by event system?
|
||||
*/
|
||||
public interface BeatmapWatchServiceListener {
|
||||
/**
|
||||
* Indication that an event was received.
|
||||
|
|
|
@ -23,36 +23,27 @@ import java.io.FilenameFilter;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import net.lingala.zip4j.core.ZipFile;
|
||||
import net.lingala.zip4j.exception.ZipException;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Unpacker for OSZ (ZIP) archives.
|
||||
*/
|
||||
public class OszUnpacker {
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
/** The index of the current file being unpacked. */
|
||||
private int fileIndex = -1;
|
||||
|
||||
/** The total number of files to unpack. */
|
||||
private File[] files;
|
||||
|
||||
@Inject
|
||||
public OszUnpacker() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the unpacker for each OSZ archive in a root directory.
|
||||
* @param root the root directory
|
||||
* @param dest the destination directory
|
||||
* @return an array containing the new (unpacked) directories, or null
|
||||
* if no OSZs found
|
||||
*/
|
||||
|
@ -106,7 +97,7 @@ public class OszUnpacker {
|
|||
} catch (ZipException e) {
|
||||
String err = String.format("Failed to unzip file %s to dest %s.", file.getAbsolutePath(), dest.getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,8 +33,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Handles connections and queries with the cached beatmap database.
|
||||
|
@ -89,17 +90,10 @@ public class BeatmapDB {
|
|||
/** Current size of beatmap cache table. */
|
||||
private static int cacheSize = -1;
|
||||
|
||||
// This class should not be instantiated.
|
||||
private BeatmapDB() {}
|
||||
|
||||
private static Configuration config; // TODO
|
||||
|
||||
/**
|
||||
* Initializes the database connection.
|
||||
*/
|
||||
public static void init(Configuration config) {
|
||||
BeatmapDB.config = config;
|
||||
|
||||
public static void init() {
|
||||
// create a database connection
|
||||
connection = DBController.createConnection(config.BEATMAP_DB.getPath());
|
||||
if (connection == null)
|
||||
|
@ -115,7 +109,7 @@ public class BeatmapDB {
|
|||
try {
|
||||
updateSizeStmt = connection.prepareStatement("REPLACE INTO info (key, value) VALUES ('size', ?)");
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to prepare beatmap statements.", e).show();
|
||||
explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
|
||||
// retrieve the cache size
|
||||
|
@ -137,7 +131,7 @@ public class BeatmapDB {
|
|||
updatePlayStatsStmt = connection.prepareStatement("UPDATE beatmaps SET playCount = ?, lastPlayed = ? WHERE dir = ? AND file = ?");
|
||||
setFavoriteStmt = connection.prepareStatement("UPDATE beatmaps SET favorite = ? WHERE dir = ? AND file = ?");
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to prepare beatmap statements.", e).show();
|
||||
explode("Failed to prepare beatmap statements.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +169,7 @@ public class BeatmapDB {
|
|||
sql = String.format("INSERT OR IGNORE INTO info(key, value) VALUES('version', '%s')", DATABASE_VERSION);
|
||||
stmt.executeUpdate(sql);
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Coudl not create beatmap database.", e).show();
|
||||
explode("Could not create beatmap database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +221,7 @@ public class BeatmapDB {
|
|||
ps.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to update beatmap database.", e).show();
|
||||
explode("Failed to update beatmap database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +239,7 @@ public class BeatmapDB {
|
|||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Could not get beatmap cache size.", e).show();
|
||||
explode("Could not get beatmap cache size.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +254,7 @@ public class BeatmapDB {
|
|||
updateSizeStmt.setString(1, Integer.toString(Math.max(cacheSize, 0)));
|
||||
updateSizeStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Could not update beatmap cache size.", e).show();
|
||||
explode("Could not update beatmap cache size.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,7 +272,7 @@ public class BeatmapDB {
|
|||
cacheSize = 0;
|
||||
updateCacheSize();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Could not drop beatmap database.", e).show();
|
||||
explode("Could not drop beatmap database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
createDatabase();
|
||||
}
|
||||
|
@ -296,7 +290,7 @@ public class BeatmapDB {
|
|||
cacheSize += insertStmt.executeUpdate();
|
||||
updateCacheSize();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to add beatmap to database.", e).show();
|
||||
explode("Failed to add beatmap to database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,7 +343,7 @@ public class BeatmapDB {
|
|||
// update cache size
|
||||
updateCacheSize();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to add beatmaps to database.", e).show();
|
||||
explode("Failed to add beatmaps to database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,7 +431,7 @@ public class BeatmapDB {
|
|||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to load Beatmap from database.", e).show();
|
||||
explode("Failed to load Beatmap from database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +494,7 @@ public class BeatmapDB {
|
|||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to load beatmaps from database.", e).show();
|
||||
explode("Failed to load beatmaps from database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -601,7 +595,7 @@ public class BeatmapDB {
|
|||
rs.close();
|
||||
return map;
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to get last modified map from database.", e).show();
|
||||
explode("Failed to get last modified map from database.", e, DEFAULT_OPTIONS);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -621,7 +615,7 @@ public class BeatmapDB {
|
|||
cacheSize -= deleteMapStmt.executeUpdate();
|
||||
updateCacheSize();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to delete beatmap entry from database.", e).show();
|
||||
explode("Failed to delete beatmap entry from database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -638,7 +632,7 @@ public class BeatmapDB {
|
|||
cacheSize -= deleteGroupStmt.executeUpdate();
|
||||
updateCacheSize();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to delete beatmap group entry from database.", e).show();
|
||||
explode("Failed to delete beatmap group entry from database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,8 +650,8 @@ public class BeatmapDB {
|
|||
setStarsStmt.setString(3, beatmap.getFile().getName());
|
||||
setStarsStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error(String.format("Failed to save star rating '%.4f' for beatmap '%s' in database.",
|
||||
beatmap.starRating, beatmap.toString()), e).show();
|
||||
explode(String.format("Failed to save star rating '%.4f' for beatmap '%s' in database.",
|
||||
beatmap.starRating, beatmap.toString()), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,8 +670,8 @@ public class BeatmapDB {
|
|||
updatePlayStatsStmt.setString(4, beatmap.getFile().getName());
|
||||
updatePlayStatsStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error(String.format("Failed to update play statistics for beatmap '%s' in database.",
|
||||
beatmap.toString()), e).show();
|
||||
explode(String.format("Failed to update play statistics for beatmap '%s' in database.",
|
||||
beatmap.toString()), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,8 +689,8 @@ public class BeatmapDB {
|
|||
setFavoriteStmt.setString(3, beatmap.getFile().getName());
|
||||
setFavoriteStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error(String.format("Failed to update favorite status for beatmap '%s' in database.",
|
||||
beatmap.toString()), e).show();
|
||||
explode(String.format("Failed to update favorite status for beatmap '%s' in database.",
|
||||
beatmap.toString()), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,7 +710,7 @@ public class BeatmapDB {
|
|||
connection.close();
|
||||
connection = null;
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to close beatmap database.", e).show();
|
||||
explode("Failed to close beatmap database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,12 @@
|
|||
|
||||
package itdelatrisu.opsu.db;
|
||||
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Database controller.
|
||||
*/
|
||||
|
@ -35,17 +34,17 @@ public class DBController {
|
|||
/**
|
||||
* Initializes all databases.
|
||||
*/
|
||||
public static void init(Configuration config) {
|
||||
public static void init() {
|
||||
// load the sqlite-JDBC driver using the current class loader
|
||||
try {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
} catch (ClassNotFoundException e) {
|
||||
ErrorHandler.error("Could not load sqlite-JDBC driver.", e).show();
|
||||
explode("Could not load sqlite-JDBC driver.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
|
||||
// initialize the databases
|
||||
BeatmapDB.init(config);
|
||||
ScoreDB.init(config);
|
||||
BeatmapDB.init();
|
||||
ScoreDB.init();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +65,7 @@ public class DBController {
|
|||
return DriverManager.getConnection(String.format("jdbc:sqlite:%s", path));
|
||||
} catch (SQLException e) {
|
||||
// if the error message is "out of memory", it probably means no database file is found
|
||||
ErrorHandler.error(String.format("Could not connect to database: '%s'.", path), e).show();
|
||||
explode(String.format("Could not connect to database: '%s'.", path), e, DEFAULT_OPTIONS);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ package itdelatrisu.opsu.db;
|
|||
|
||||
import itdelatrisu.opsu.ScoreData;
|
||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -36,6 +34,9 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Handles connections and queries with the scores database.
|
||||
*/
|
||||
|
@ -77,13 +78,10 @@ public class ScoreDB {
|
|||
/** Score deletion statement. */
|
||||
private static PreparedStatement deleteSongStmt, deleteScoreStmt;
|
||||
|
||||
// This class should not be instantiated.
|
||||
private ScoreDB() {}
|
||||
|
||||
/**
|
||||
* Initializes the database connection.
|
||||
*/
|
||||
public static void init(Configuration config) {
|
||||
public static void init() {
|
||||
// create a database connection
|
||||
connection = DBController.createConnection(config.SCORE_DB.getPath());
|
||||
if (connection == null)
|
||||
|
@ -124,7 +122,7 @@ public class ScoreDB {
|
|||
// TODO: extra playerName checks not needed if name is guaranteed not null
|
||||
);
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to prepare score statements.", e).show();
|
||||
explode("Failed to prepare score statements.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +155,7 @@ public class ScoreDB {
|
|||
sql = String.format("INSERT OR IGNORE INTO info(key, value) VALUES('version', %d)", DATABASE_VERSION);
|
||||
stmt.executeUpdate(sql);
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Could not create score database.", e).show();
|
||||
explode("Could not create score database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +207,7 @@ public class ScoreDB {
|
|||
ps.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to update score database.", e).show();
|
||||
explode("Failed to update score database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +225,7 @@ public class ScoreDB {
|
|||
insertStmt.setString(19, data.playerName);
|
||||
insertStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to save score to database.", e).show();
|
||||
explode("Failed to save score to database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +245,7 @@ public class ScoreDB {
|
|||
deleteScoreStmt.setString(21, data.playerName);
|
||||
deleteScoreStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to delete score from database.", e).show();
|
||||
explode("Failed to delete score from database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +265,7 @@ public class ScoreDB {
|
|||
deleteSongStmt.setString(5, beatmap.version);
|
||||
deleteSongStmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to delete scores from database.", e).show();
|
||||
explode("Failed to delete scores from database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +333,7 @@ public class ScoreDB {
|
|||
}
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to read scores from database.", e).show();
|
||||
explode("Failed to read scores from database.", e, DEFAULT_OPTIONS);
|
||||
return null;
|
||||
}
|
||||
return getSortedArray(list);
|
||||
|
@ -377,7 +375,7 @@ public class ScoreDB {
|
|||
map.put(version, getSortedArray(list));
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to read scores from database.", e).show();
|
||||
explode("Failed to read scores from database.", e, DEFAULT_OPTIONS);
|
||||
return null;
|
||||
}
|
||||
return map;
|
||||
|
@ -406,7 +404,7 @@ public class ScoreDB {
|
|||
connection.close();
|
||||
connection = null;
|
||||
} catch (SQLException e) {
|
||||
ErrorHandler.error("Failed to close score database.", e).show();
|
||||
explode("Failed to close score database.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,11 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* File download.
|
||||
|
@ -92,7 +93,7 @@ public class Download {
|
|||
private String localPath;
|
||||
|
||||
/** The local path to rename the file to when finished. */
|
||||
private String rename;
|
||||
private String renamedFileName;
|
||||
|
||||
/** The download URL. */
|
||||
private URL url;
|
||||
|
@ -137,18 +138,20 @@ public class Download {
|
|||
* Constructor.
|
||||
* @param remoteURL the download URL
|
||||
* @param localPath the path to save the download
|
||||
* @param rename the file name to rename the download to when complete
|
||||
* @param renamedFileName the file name to rename the download to when complete
|
||||
*/
|
||||
public Download(String remoteURL, String localPath, String rename) {
|
||||
public Download(String remoteURL, String localPath, String renamedFileName) {
|
||||
try {
|
||||
this.url = new URL(remoteURL);
|
||||
} catch (MalformedURLException e) {
|
||||
this.status = Status.ERROR;
|
||||
ErrorHandler.error(String.format("Bad download URL: '%s'", remoteURL), e).show();
|
||||
explode(String.format("Bad download URL: '%s'", remoteURL), e, DEFAULT_OPTIONS);
|
||||
return;
|
||||
}
|
||||
this.localPath = localPath;
|
||||
this.rename = Utils.cleanFileName(rename, '-');
|
||||
if (renamedFileName != null) {
|
||||
this.renamedFileName = Utils.cleanFileName(renamedFileName, '-');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,7 +162,7 @@ public class Download {
|
|||
/**
|
||||
* Returns the local path to save the download (after renamed).
|
||||
*/
|
||||
public String getLocalPath() { return (rename != null) ? rename : localPath; }
|
||||
public String getLocalPath() { return (renamedFileName != null) ? renamedFileName : localPath; }
|
||||
|
||||
/**
|
||||
* Sets the download listener.
|
||||
|
@ -217,7 +220,7 @@ public class Download {
|
|||
else if (redirectCount > MAX_REDIRECTS)
|
||||
error = String.format("Download for URL '%s' is attempting too many redirects (over %d).", base.toString(), MAX_REDIRECTS);
|
||||
if (error != null) {
|
||||
EventBus.post(new BubbleNotificationEvent(error, BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif(error, Colors.BUB_ORANGE);
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
|
@ -263,9 +266,9 @@ public class Download {
|
|||
status = Status.COMPLETE;
|
||||
rbc.close();
|
||||
fos.close();
|
||||
if (rename != null) {
|
||||
if (renamedFileName != null) {
|
||||
Path source = new File(localPath).toPath();
|
||||
Files.move(source, source.resolveSibling(rename), StandardCopyOption.REPLACE_EXISTING);
|
||||
Files.move(source, source.resolveSibling(renamedFileName), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
if (listener != null)
|
||||
listener.completed();
|
||||
|
@ -419,7 +422,7 @@ public class Download {
|
|||
}
|
||||
} catch (IOException e) {
|
||||
this.status = Status.ERROR;
|
||||
ErrorHandler.error("Failed to cancel download.", e).show();
|
||||
explode("Failed to cancel download.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,12 +33,10 @@ import java.io.File;
|
|||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Image;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -46,9 +44,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class DownloadNode {
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
/** The associated Download object. */
|
||||
private Download download;
|
||||
|
||||
|
@ -285,12 +280,14 @@ public class DownloadNode {
|
|||
download.setListener(new DownloadListener() {
|
||||
@Override
|
||||
public void completed() {
|
||||
EventBus.post(new BarNotificationEvent(String.format("Download complete: %s", getTitle())));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
String.format("Download complete: %s", getTitle()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error() {
|
||||
EventBus.post(new BarNotificationEvent("Download failed due to a connection error."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"Download failed due to a connection error.");
|
||||
}
|
||||
});
|
||||
this.download = download;
|
||||
|
@ -412,7 +409,9 @@ public class DownloadNode {
|
|||
public void drawDownload(Graphics g, float position, int id, boolean hover) {
|
||||
Download download = this.download; // in case clearDownload() is called asynchronously
|
||||
if (download == null) {
|
||||
EventBus.post(new BubbleNotificationEvent("Trying to draw download information for button without Download object", BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
"Trying to draw download information for button without Download object",
|
||||
Colors.BUB_ORANGE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,26 +35,17 @@ import java.util.Properties;
|
|||
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.core.Constants;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Handles automatic program updates.
|
||||
*/
|
||||
public class Updater {
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
private static Updater updater;
|
||||
|
||||
public static Updater get() {
|
||||
return updater;
|
||||
}
|
||||
|
||||
/** The exit confirmation message. */
|
||||
public static final String EXIT_CONFIRMATION = "An opsu! update is being downloaded.\nAre you sure you want to quit opsu!?";
|
||||
|
||||
|
@ -95,7 +86,7 @@ public class Updater {
|
|||
* Returns the status description.
|
||||
*/
|
||||
public String getDescription() { return description; }
|
||||
};
|
||||
}
|
||||
|
||||
/** The current updater status. */
|
||||
private Status status;
|
||||
|
@ -119,10 +110,8 @@ public class Updater {
|
|||
return currentVersion.getMajorVersion() + "." + currentVersion.getMinorVersion() + "." + currentVersion.getIncrementalVersion();
|
||||
}
|
||||
|
||||
@Inject
|
||||
public Updater() {
|
||||
status = Status.INITIAL;
|
||||
updater = this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,7 +134,7 @@ public class Updater {
|
|||
Date date = null;
|
||||
try {
|
||||
Properties props = new Properties();
|
||||
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
|
||||
props.load(ResourceLoader.getResourceAsStream(Constants.VERSION_FILE));
|
||||
String build = props.getProperty("build.date");
|
||||
if (build == null || build.equals("${timestamp}") || build.equals("${maven.build.timestamp}"))
|
||||
date = new Date();
|
||||
|
@ -214,16 +203,16 @@ public class Updater {
|
|||
|
||||
// get current version
|
||||
Properties props = new Properties();
|
||||
props.load(ResourceLoader.getResourceAsStream(config.VERSION_FILE));
|
||||
props.load(ResourceLoader.getResourceAsStream(Constants.VERSION_FILE));
|
||||
if ((currentVersion = getVersion(props)) == null)
|
||||
return;
|
||||
|
||||
// get latest version
|
||||
String s = null;
|
||||
try {
|
||||
s = Utils.readDataFromUrl(new URL(config.VERSION_REMOTE));
|
||||
s = Utils.readDataFromUrl(new URL(Constants.VERSION_REMOTE));
|
||||
} catch (UnknownHostException e) {
|
||||
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", config.VERSION_REMOTE));
|
||||
Log.warn(String.format("Check for updates failed. Please check your internet connection, or your connection to %s.", Constants.VERSION_REMOTE));
|
||||
}
|
||||
if (s == null) {
|
||||
status = Status.CONNECTION_ERROR;
|
||||
|
@ -252,13 +241,14 @@ public class Updater {
|
|||
@Override
|
||||
public void completed() {
|
||||
status = Status.UPDATE_DOWNLOADED;
|
||||
EventBus.post(new BarNotificationEvent("Update has finished downloading"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Update has finished downloading");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error() {
|
||||
status = Status.CONNECTION_ERROR;
|
||||
EventBus.post(new BarNotificationEvent("Update failed due to a connection error."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"Update failed due to a connection error.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -301,7 +291,7 @@ public class Updater {
|
|||
pb.start();
|
||||
} catch (IOException e) {
|
||||
status = Status.INTERNAL_ERROR;
|
||||
ErrorHandler.error("Failed to start new process.", e).show();
|
||||
explode("Failed to start new process.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,18 +33,14 @@ import java.util.Date;
|
|||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Download server: http://bloodcat.com/osu/
|
||||
*/
|
||||
public class BloodcatServer extends DownloadServer {
|
||||
|
||||
@Inject
|
||||
public InstanceContainer instanceContainer;
|
||||
|
||||
/** Server name. */
|
||||
private static final String SERVER_NAME = "Bloodcat";
|
||||
|
||||
|
@ -60,10 +56,6 @@ public class BloodcatServer extends DownloadServer {
|
|||
/** Total result count from the last query. */
|
||||
private int totalResults = -1;
|
||||
|
||||
@Inject
|
||||
public BloodcatServer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return SERVER_NAME; }
|
||||
|
||||
|
@ -89,12 +81,12 @@ public class BloodcatServer extends DownloadServer {
|
|||
nodes = new DownloadNode[arr.length()];
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
JSONObject item = arr.getJSONObject(i);
|
||||
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||
nodes[i] = new DownloadNode(
|
||||
item.getInt("id"), formatDate(item.getString("synced")), //"date"
|
||||
item.getString("title"), item.isNull("titleU") ? null : item.getString("titleU"), //"titleUnicode"
|
||||
item.getString("artist"), item.isNull("artistU") ? null : item.getString("artistU"), //"artistUnicode"
|
||||
item.getString("creator")
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
// store total result count
|
||||
|
@ -104,7 +96,7 @@ public class BloodcatServer extends DownloadServer {
|
|||
resultCount++;
|
||||
this.totalResults = resultCount;
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
|
|
@ -29,9 +29,8 @@ import java.net.URLEncoder;
|
|||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Download server: https://osu.hexide.com/
|
||||
|
@ -40,9 +39,6 @@ import yugecin.opsudance.core.inject.InstanceContainer;
|
|||
*/
|
||||
public class HexideServer extends DownloadServer {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
/** Server name. */
|
||||
private static final String SERVER_NAME = "Hexide";
|
||||
|
||||
|
@ -64,10 +60,6 @@ public class HexideServer extends DownloadServer {
|
|||
/** Total result count from the last query. */
|
||||
private int totalResults = -1;
|
||||
|
||||
@Inject
|
||||
public HexideServer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return SERVER_NAME; }
|
||||
|
||||
|
@ -124,10 +116,10 @@ public class HexideServer extends DownloadServer {
|
|||
artist = creator = "?";
|
||||
}
|
||||
}
|
||||
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||
nodes[i] = new DownloadNode(
|
||||
item.getInt("ranked_id"), item.getString("date"),
|
||||
title, null, artist, null, creator
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
// store total result count
|
||||
|
@ -135,7 +127,7 @@ public class HexideServer extends DownloadServer {
|
|||
// all results at once; this approach just gets pagination correct.
|
||||
this.totalResults = arr.length() + resultIndex;
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
|
|
@ -29,18 +29,14 @@ import java.net.URLEncoder;
|
|||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Download server: http://osu.mengsky.net/
|
||||
*/
|
||||
public class MengSkyServer extends DownloadServer {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
/** Server name. */
|
||||
private static final String SERVER_NAME = "MengSky";
|
||||
|
||||
|
@ -56,10 +52,6 @@ public class MengSkyServer extends DownloadServer {
|
|||
/** Total result count from the last query. */
|
||||
private int totalResults = -1;
|
||||
|
||||
@Inject
|
||||
public MengSkyServer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return SERVER_NAME; }
|
||||
|
||||
|
@ -93,10 +85,10 @@ public class MengSkyServer extends DownloadServer {
|
|||
// sometimes titleU is artistU instead of the proper title
|
||||
if (titleU.equals(artistU) && !titleU.equals(title))
|
||||
titleU = title;
|
||||
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||
nodes[i] = new DownloadNode(
|
||||
item.getInt("id"), item.getString("syncedDateTime"),
|
||||
title, titleU, artist, artistU, creator
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
// store total result count
|
||||
|
@ -107,7 +99,7 @@ public class MengSkyServer extends DownloadServer {
|
|||
}
|
||||
this.totalResults = resultCount;
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@ package itdelatrisu.opsu.downloads.servers;
|
|||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import itdelatrisu.opsu.downloads.DownloadNode;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
@ -34,14 +31,13 @@ import java.util.List;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Download server: http://osu.uu.gl/
|
||||
*/
|
||||
public class MnetworkServer extends DownloadServer {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
/** Server name. */
|
||||
private static final String SERVER_NAME = "Mnetwork";
|
||||
|
||||
|
@ -57,10 +53,6 @@ public class MnetworkServer extends DownloadServer {
|
|||
/** Beatmap pattern. */
|
||||
private Pattern BEATMAP_PATTERN = Pattern.compile("^(\\d+) ([^-]+) - (.+)\\.osz$");
|
||||
|
||||
@Inject
|
||||
public MnetworkServer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return SERVER_NAME; }
|
||||
|
||||
|
@ -119,7 +111,7 @@ public class MnetworkServer extends DownloadServer {
|
|||
if (!m.matches())
|
||||
continue;
|
||||
|
||||
nodeList.add(instanceContainer.injectFields(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, "")));
|
||||
nodeList.add(new DownloadNode(Integer.parseInt(m.group(1)), date, m.group(3), null, m.group(2), null, ""));
|
||||
}
|
||||
|
||||
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
|
||||
|
@ -127,7 +119,7 @@ public class MnetworkServer extends DownloadServer {
|
|||
// store total result count
|
||||
this.totalResults = nodes.length;
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
|
|
@ -35,9 +35,8 @@ import java.util.TimeZone;
|
|||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Download server: http://loli.al/
|
||||
|
@ -46,9 +45,6 @@ import yugecin.opsudance.core.inject.InstanceContainer;
|
|||
*/
|
||||
public class OsuMirrorServer extends DownloadServer {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
/** Server name. */
|
||||
private static final String SERVER_NAME = "osu!Mirror";
|
||||
|
||||
|
@ -73,10 +69,6 @@ public class OsuMirrorServer extends DownloadServer {
|
|||
/** Lookup table from beatmap set ID -> server download ID. */
|
||||
private HashMap<Integer, Integer> idTable = new HashMap<Integer, Integer>();
|
||||
|
||||
@Inject
|
||||
public OsuMirrorServer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return SERVER_NAME; }
|
||||
|
||||
|
@ -113,12 +105,12 @@ public class OsuMirrorServer extends DownloadServer {
|
|||
JSONObject item = arr.getJSONObject(i);
|
||||
int beatmapSetID = item.getInt("OSUSetid");
|
||||
int serverID = item.getInt("id");
|
||||
nodes[i] = instanceContainer.injectFields(new DownloadNode(
|
||||
nodes[i] = new DownloadNode(
|
||||
beatmapSetID, formatDate(item.getString("ModifyDate")),
|
||||
item.getString("Title"), null,
|
||||
item.getString("Artist"), null,
|
||||
item.getString("Mapper")
|
||||
));
|
||||
);
|
||||
idTable.put(beatmapSetID, serverID);
|
||||
if (serverID > maxServerID)
|
||||
maxServerID = serverID;
|
||||
|
@ -130,7 +122,7 @@ public class OsuMirrorServer extends DownloadServer {
|
|||
else
|
||||
this.totalResults = maxServerID;
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
|
|
@ -33,18 +33,14 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
|
||||
/**
|
||||
* Download server: http://osu.yas-online.net/
|
||||
*/
|
||||
public class YaSOnlineServer extends DownloadServer {
|
||||
|
||||
@Inject
|
||||
public InstanceContainer instanceContainer;
|
||||
|
||||
/** Server name. */
|
||||
private static final String SERVER_NAME = "YaS Online";
|
||||
|
||||
|
@ -72,10 +68,6 @@ public class YaSOnlineServer extends DownloadServer {
|
|||
/** Max server download ID seen (for approximating total pages). */
|
||||
private int maxServerID = 0;
|
||||
|
||||
@Inject
|
||||
public YaSOnlineServer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return SERVER_NAME; }
|
||||
|
||||
|
@ -121,7 +113,8 @@ public class YaSOnlineServer extends DownloadServer {
|
|||
String downloadLink = item.getString("downloadLink");
|
||||
return String.format(DOWNLOAD_FETCH_URL, downloadLink);
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e).show();
|
||||
explode(String.format("Problem retrieving download URL for beatmap '%d'.", beatmapSetID), e,
|
||||
DEFAULT_OPTIONS);
|
||||
return null;
|
||||
} finally {
|
||||
Utils.setSSLCertValidation(true);
|
||||
|
@ -183,7 +176,7 @@ public class YaSOnlineServer extends DownloadServer {
|
|||
if (serverID > maxServerID)
|
||||
maxServerID = serverID;
|
||||
|
||||
nodeList.add(instanceContainer.injectFields(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, "")));
|
||||
nodeList.add(new DownloadNode(item.getInt("mapid"), date, title, null, artist, null, ""));
|
||||
}
|
||||
nodes = nodeList.toArray(new DownloadNode[nodeList.size()]);
|
||||
|
||||
|
@ -193,7 +186,7 @@ public class YaSOnlineServer extends DownloadServer {
|
|||
else
|
||||
this.totalResults = maxServerID;
|
||||
} catch (MalformedURLException | UnsupportedEncodingException e) {
|
||||
ErrorHandler.error(String.format("Problem loading result list for query '%s'.", query), e).show();
|
||||
explode(String.format("Problem loading result list for query '%s'.", query), e, DEFAULT_OPTIONS);
|
||||
} finally {
|
||||
Utils.setSSLCertValidation(true);
|
||||
}
|
||||
|
|
|
@ -30,9 +30,8 @@ import itdelatrisu.opsu.ui.Colors;
|
|||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.Dancer;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -40,9 +39,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class Circle extends GameObject {
|
||||
|
||||
@Inject
|
||||
private GameObjectRenderer gameObjectRenderer;
|
||||
|
||||
/** The associated HitObject. */
|
||||
private HitObject hitObject;
|
||||
|
||||
|
@ -156,7 +152,7 @@ public class Circle extends GameObject {
|
|||
@Override
|
||||
public boolean mousePressed(int x, int y, int trackPosition) {
|
||||
double distance = Math.hypot(this.x - x, this.y - y);
|
||||
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
|
||||
if (distance < gameObjectRenderer.circleDiameter / 2) {
|
||||
int timeDiff = trackPosition - hitObject.getTime();
|
||||
int result = hitResult(timeDiff);
|
||||
|
||||
|
|
|
@ -35,11 +35,9 @@ import org.newdawn.slick.Color;
|
|||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Image;
|
||||
import yugecin.opsudance.Dancer;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -47,12 +45,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class Slider extends GameObject {
|
||||
|
||||
@Inject
|
||||
private DisplayContainer displayContainer;
|
||||
|
||||
@Inject
|
||||
private GameObjectRenderer gameObjectRenderer;
|
||||
|
||||
/** Slider ball frames. */
|
||||
private static Image[] sliderBallImages;
|
||||
|
||||
|
@ -605,7 +597,7 @@ public class Slider extends GameObject {
|
|||
return false;
|
||||
|
||||
double distance = Math.hypot(this.x - x, this.y - y);
|
||||
if (distance < gameObjectRenderer.getCircleDiameter() / 2) {
|
||||
if (distance < gameObjectRenderer.circleDiameter / 2) {
|
||||
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
||||
int[] hitResultOffset = game.getHitResultOffsets();
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.lwjgl.opengl.GL20;
|
|||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -316,7 +316,7 @@ public class CurveRenderState {
|
|||
double diff_x = x - last_x;
|
||||
double diff_y = y - last_y;
|
||||
float dist = Utils.distance(x, y, last_x, last_y);
|
||||
if (dist < GameObjectRenderer.instance.getCircleDiameter() / 8) {
|
||||
if (dist < gameObjectRenderer.circleDiameter / 8) {
|
||||
x = (float) (x - diff_x / 2);
|
||||
y = (float) (y - diff_y / 2);
|
||||
} else {
|
||||
|
|
|
@ -39,15 +39,15 @@ import java.util.ArrayList;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.apache.commons.compress.compressors.lzma.LZMACompressorInputStream;
|
||||
import org.newdawn.slick.util.Log;
|
||||
|
||||
import lzma.streams.LzmaOutputStream;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Captures osu! replay data.
|
||||
|
@ -57,9 +57,6 @@ import yugecin.opsudance.options.Configuration;
|
|||
*/
|
||||
public class Replay {
|
||||
|
||||
@Inject
|
||||
public Configuration config;
|
||||
|
||||
/** The associated file. */
|
||||
private File file;
|
||||
|
||||
|
@ -278,7 +275,7 @@ public class Replay {
|
|||
public void save() {
|
||||
// create replay directory
|
||||
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
|
||||
EventBus.post(new BubbleNotificationEvent("Failed to create replay directory.", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Failed to create replay directory", Colors.BUB_RED);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -347,7 +344,7 @@ public class Replay {
|
|||
compressedOut.write(bytes);
|
||||
} catch (IOException e) {
|
||||
// possible OOM: https://github.com/jponge/lzma-java/issues/9
|
||||
ErrorHandler.error("LZMA compression failed (possible out-of-memory error).", e).show();
|
||||
explode("LZMA compression failed (possible out-of-memory error).", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
compressedOut.close();
|
||||
bout.close();
|
||||
|
@ -361,7 +358,7 @@ public class Replay {
|
|||
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
ErrorHandler.error("Could not save replay data.", e).show();
|
||||
explode("Could not save replay data.", e, DEFAULT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
|
|
|
@ -28,24 +28,17 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Importer for replay files.
|
||||
*/
|
||||
public class ReplayImporter {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
/** The subdirectory (within the replay import directory) to move replays that could not be imported. */
|
||||
private final String FAILED_IMPORT_DIR = "failed";
|
||||
|
||||
|
@ -55,10 +48,6 @@ public class ReplayImporter {
|
|||
/** The total number of replays to import. */
|
||||
private File[] files;
|
||||
|
||||
@Inject
|
||||
public ReplayImporter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the importer for each OSR file in the replay import dir, adding the replay
|
||||
* to the score database and moving the file into the replay directory.
|
||||
|
@ -80,21 +69,21 @@ public class ReplayImporter {
|
|||
if (!config.replayDir.isDirectory() && !config.replayDir.mkdir()) {
|
||||
String err = String.format("Failed to create replay directory '%s'.", config.replayDir.getAbsolutePath());
|
||||
Log.error(err);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
return;
|
||||
}
|
||||
|
||||
// import OSRs
|
||||
for (File file : files) {
|
||||
fileIndex++;
|
||||
Replay r = instanceContainer.injectFields(new Replay(file));
|
||||
Replay r = new Replay(file);
|
||||
try {
|
||||
r.loadHeader();
|
||||
} catch (IOException e) {
|
||||
moveToFailedDirectory(file);
|
||||
String err = String.format("Failed to import replay '%s'. The replay file could not be parsed.", file.getName());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
continue;
|
||||
}
|
||||
Beatmap beatmap = BeatmapSetList.get().getBeatmapFromHash(r.beatmapHash);
|
||||
|
@ -113,7 +102,7 @@ public class ReplayImporter {
|
|||
moveToFailedDirectory(file);
|
||||
String err = String.format("Failed to import replay '%s'. The associated beatmap could not be found.", file.getName());
|
||||
Log.error(err);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ import java.io.InputStreamReader;
|
|||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
/**
|
||||
* Loads skin configuration files.
|
||||
|
@ -293,7 +293,7 @@ public class SkinLoader {
|
|||
} catch (IOException e) {
|
||||
String err = String.format("Failed to read file '%s'.", skinFile.getAbsolutePath());
|
||||
Log.error(err, e);
|
||||
EventBus.post(new BubbleNotificationEvent(err, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(err, Colors.BUB_RED);
|
||||
}
|
||||
|
||||
return skin;
|
||||
|
|
|
@ -35,14 +35,15 @@ import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.Input;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Generic button menu state.
|
||||
* <p>
|
||||
|
@ -68,7 +69,7 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
BEATMAP (new Button[] { Button.CLEAR_SCORES, Button.FAVORITE_ADD, Button.DELETE, Button.CANCEL }) {
|
||||
@Override
|
||||
public String[] getTitle() {
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
String beatmapString = (node != null) ? BeatmapSetList.get().getBaseNode(node.index).toString() : "";
|
||||
return new String[] { beatmapString, "What do you want to do with this beatmap?" };
|
||||
}
|
||||
|
@ -99,7 +100,7 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
BEATMAP_DELETE_SELECT (new Button[] { Button.DELETE_GROUP, Button.DELETE_SONG, Button.CANCEL_DELETE }) {
|
||||
@Override
|
||||
public String[] getTitle() {
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
String beatmapString = (node != null) ? node.toString() : "";
|
||||
return new String[] { String.format("Are you sure you wish to delete '%s' from disk?", beatmapString) };
|
||||
}
|
||||
|
@ -179,7 +180,7 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected float getBaseY(DisplayContainer displayContainer) {
|
||||
protected float getBaseY() {
|
||||
return displayContainer.height * 2f / 3;
|
||||
}
|
||||
|
||||
|
@ -268,9 +269,6 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
}
|
||||
};
|
||||
|
||||
public static DisplayContainer displayContainer;
|
||||
public static InstanceContainer instanceContainer;
|
||||
|
||||
/** The buttons in the state. */
|
||||
private final Button[] buttons;
|
||||
|
||||
|
@ -299,7 +297,7 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
*/
|
||||
public void revalidate(Image button, Image buttonL, Image buttonR) {
|
||||
float center = displayContainer.width / 2;
|
||||
float baseY = getBaseY(displayContainer);
|
||||
float baseY = getBaseY();
|
||||
float offsetY = button.getHeight() * 1.25f;
|
||||
|
||||
menuButtons = new MenuButton[buttons.length];
|
||||
|
@ -314,7 +312,7 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
/**
|
||||
* Returns the base Y coordinate for the buttons.
|
||||
*/
|
||||
protected float getBaseY(DisplayContainer displayContainer) {
|
||||
protected float getBaseY() {
|
||||
float baseY = displayContainer.height * 0.2f;
|
||||
baseY += ((getTitle().length - 1) * Fonts.LARGE.getLineHeight());
|
||||
return baseY;
|
||||
|
@ -437,62 +435,62 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
displayContainer.switchState(MainMenu.class);
|
||||
displayContainer.switchState(mainmenuState);
|
||||
}
|
||||
},
|
||||
CLEAR_SCORES ("Clear local scores", Color.magenta) {
|
||||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP, node);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
songMenuState.doStateActionOnLoad(MenuState.BEATMAP, node);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
FAVORITE_ADD ("Add to Favorites", Color.blue) {
|
||||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
node.getBeatmapSet().setFavorite(true);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
FAVORITE_REMOVE ("Remove from Favorites", Color.blue) {
|
||||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
node.getBeatmapSet().setFavorite(false);
|
||||
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_FAVORITE);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
songMenuState.doStateActionOnLoad(MenuState.BEATMAP_FAVORITE);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
DELETE ("Delete...", Color.red) {
|
||||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
MenuState ms = (node.beatmapIndex == -1 || node.getBeatmapSet().size() == 1) ?
|
||||
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(ms, node);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(ms, node);
|
||||
displayContainer.switchState(buttonState);
|
||||
}
|
||||
},
|
||||
CANCEL ("Cancel", Color.gray) {
|
||||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
DELETE_CONFIRM ("Yes, delete this beatmap!", Color.red) {
|
||||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
songMenuState.doStateActionOnLoad(MenuState.BEATMAP_DELETE_CONFIRM, node);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
DELETE_GROUP ("Yes, delete all difficulties!", Color.red) {
|
||||
|
@ -505,9 +503,9 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
BeatmapSetNode node = instanceContainer.provide(ButtonMenu.class).getNode();
|
||||
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
BeatmapSetNode node = buttonState.getNode();
|
||||
songMenuState.doStateActionOnLoad(MenuState.BEATMAP_DELETE_SELECT, node);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
CANCEL_DELETE ("Nooooo! I didn't mean to!", Color.gray) {
|
||||
|
@ -520,8 +518,8 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.RELOAD);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
songMenuState.doStateActionOnLoad(MenuState.RELOAD);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
RELOAD_CANCEL ("Cancel", Color.red) {
|
||||
|
@ -534,9 +532,9 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
@Override
|
||||
public void click() {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
ScoreData scoreData = instanceContainer.provide(ButtonMenu.class).getScoreData();
|
||||
instanceContainer.provide(SongMenu.class).doStateActionOnLoad(MenuState.SCORE, scoreData);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
ScoreData scoreData = buttonState.getScoreData();
|
||||
songMenuState.doStateActionOnLoad(MenuState.SCORE, scoreData);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
},
|
||||
CLOSE ("Close", Color.gray) {
|
||||
|
@ -556,9 +554,6 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
}
|
||||
};
|
||||
|
||||
public static DisplayContainer displayContainer;
|
||||
public static InstanceContainer instanceContainer;
|
||||
|
||||
/** The text to show on the button. */
|
||||
private final String text;
|
||||
|
||||
|
@ -600,12 +595,6 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
/** The score data to process in the state. */
|
||||
private ScoreData scoreData;
|
||||
|
||||
public ButtonMenu(DisplayContainer displayContainer, InstanceContainer instanceContainer) {
|
||||
super();
|
||||
Button.displayContainer = MenuState.displayContainer = displayContainer;
|
||||
Button.instanceContainer = MenuState.instanceContainer = instanceContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revalidate() {
|
||||
super.revalidate();
|
||||
|
@ -662,7 +651,7 @@ public class ButtonMenu extends BaseOpsuState {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
menuState.leave();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,10 +22,8 @@ import itdelatrisu.opsu.GameImage;
|
|||
import itdelatrisu.opsu.audio.MusicController;
|
||||
import itdelatrisu.opsu.audio.SoundController;
|
||||
import itdelatrisu.opsu.audio.SoundEffect;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapSetList;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapSetNode;
|
||||
import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||
import itdelatrisu.opsu.downloads.Download;
|
||||
import itdelatrisu.opsu.downloads.DownloadList;
|
||||
import itdelatrisu.opsu.downloads.DownloadNode;
|
||||
|
@ -54,12 +52,11 @@ import org.newdawn.slick.Input;
|
|||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.gui.TextField;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.ComplexOpsuState;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* Downloads menu.
|
||||
|
@ -69,18 +66,6 @@ import yugecin.opsudance.options.Configuration;
|
|||
*/
|
||||
public class DownloadsMenu extends ComplexOpsuState {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
@Inject
|
||||
private OszUnpacker oszUnpacker;
|
||||
|
||||
@Inject
|
||||
private BeatmapParser beatmapParser;
|
||||
|
||||
/** Delay time, in milliseconds, between each search. */
|
||||
private static final int SEARCH_DELAY = 700;
|
||||
|
||||
|
@ -275,32 +260,35 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
} finally {
|
||||
finished = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Imports all packed beatmaps. */
|
||||
private void importBeatmaps() {
|
||||
// invoke unpacker and parser
|
||||
File[] dirs = oszUnpacker.unpackAll();
|
||||
if (dirs != null && dirs.length > 0) {
|
||||
this.importedNode = beatmapParser.parseDirectories(dirs);
|
||||
if (importedNode != null) {
|
||||
// send notification
|
||||
EventBus.post(new BarNotificationEvent((dirs.length == 1) ? "Imported 1 new song." :
|
||||
String.format("Imported %d new songs.", dirs.length)));
|
||||
}
|
||||
}
|
||||
File[] dirs = oszunpacker.unpackAll();
|
||||
this.importedNode = beatmapParser.parseDirectories(dirs);
|
||||
|
||||
DownloadList.get().clearDownloads(Download.Status.COMPLETE);
|
||||
|
||||
if (this.importedNode == null) {
|
||||
return;
|
||||
}
|
||||
String msg;
|
||||
if (dirs.length == 1) {
|
||||
msg = "Imported 1 new song.";
|
||||
} else {
|
||||
msg = String.format("Imported %d new songs.", dirs.length);
|
||||
}
|
||||
BarNotifListener.EVENT.make().onBarNotif(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
public DownloadsMenu(InstanceContainer instanceContainer) {
|
||||
public DownloadsMenu() {
|
||||
SERVERS = new DownloadServer[] {
|
||||
instanceContainer.provide(BloodcatServer.class),
|
||||
instanceContainer.provide(YaSOnlineServer.class),
|
||||
instanceContainer.provide(MnetworkServer.class),
|
||||
instanceContainer.provide(MengSkyServer.class),
|
||||
new BloodcatServer(),
|
||||
new YaSOnlineServer(),
|
||||
new MnetworkServer(),
|
||||
new MengSkyServer(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -319,7 +307,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
// search
|
||||
searchTimer = SEARCH_DELAY;
|
||||
searchResultString = "Loading data from server...";
|
||||
search = new TextField(displayContainer, Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) {
|
||||
search = new TextField(Fonts.DEFAULT, baseX, searchY, searchWidth, Fonts.MEDIUM.getLineHeight()) {
|
||||
@Override
|
||||
public boolean isFocusable() {
|
||||
return false;
|
||||
|
@ -555,7 +543,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
|
||||
// focus new beatmap
|
||||
// NOTE: This can't be called in another thread because it makes OpenGL calls.
|
||||
instanceContainer.provide(SongMenu.class).setFocus(importedNode, -1, true, true);
|
||||
songMenuState.setFocus(importedNode, -1, true, true);
|
||||
}
|
||||
importThread = null;
|
||||
}
|
||||
|
@ -633,7 +621,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
// back
|
||||
if (UI.getBackButton().contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
displayContainer.switchState(MainMenu.class);
|
||||
displayContainer.switchState(mainmenuState);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -698,7 +686,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
if (playing)
|
||||
previewID = node.getID();
|
||||
} catch (SlickException e) {
|
||||
EventBus.post(new BarNotificationEvent("Failed to load track preview. See log for details."));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Failed to load track preview. See log for details.");
|
||||
Log.error(e);
|
||||
}
|
||||
}
|
||||
|
@ -721,7 +709,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
if (!DownloadList.get().contains(node.getID())) {
|
||||
node.createDownload(serverMenu.getSelectedItem());
|
||||
if (node.getDownload() == null) {
|
||||
EventBus.post(new BarNotificationEvent("The download could not be started"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("The download could not be started");
|
||||
} else {
|
||||
DownloadList.get().addNode(node);
|
||||
node.getDownload().start();
|
||||
|
@ -901,12 +889,12 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
}
|
||||
|
||||
// block input during beatmap importing
|
||||
if (importThread != null && key != Input.KEY_ESCAPE) {
|
||||
if (importThread != null && key != KEY_ESCAPE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
case KEY_ESCAPE:
|
||||
if (importThread != null) {
|
||||
// beatmap importing: stop parsing beatmaps by sending interrupt to BeatmapParser
|
||||
importThread.interrupt();
|
||||
|
@ -918,16 +906,16 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
} else {
|
||||
// return to main menu
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
displayContainer.switchState(MainMenu.class);
|
||||
displayContainer.switchState(mainmenuState);
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_ENTER:
|
||||
case KEY_RETURN:
|
||||
if (!search.getText().isEmpty()) {
|
||||
pageDir = Page.RESET;
|
||||
resetSearchTimer();
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_F5:
|
||||
case KEY_F5:
|
||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||
lastQuery = null;
|
||||
pageDir = Page.CURRENT;
|
||||
|
@ -937,7 +925,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
return true;
|
||||
}
|
||||
// wait for user to finish typing
|
||||
if (Character.isLetterOrDigit(c) || key == Input.KEY_BACK) {
|
||||
if (Character.isLetterOrDigit(c) || key == KEY_BACK) {
|
||||
search.keyPressed(key, c);
|
||||
searchTimer = 0;
|
||||
pageDir = Page.RESET;
|
||||
|
@ -963,7 +951,7 @@ public class DownloadsMenu extends ComplexOpsuState {
|
|||
pageDir = Page.RESET;
|
||||
previewID = -1;
|
||||
if (barNotificationOnLoad != null) {
|
||||
EventBus.post(new BarNotificationEvent(barNotificationOnLoad));
|
||||
BarNotifListener.EVENT.make().onBarNotif(barNotificationOnLoad);
|
||||
barNotificationOnLoad = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import itdelatrisu.opsu.audio.MusicController;
|
|||
import itdelatrisu.opsu.audio.SoundController;
|
||||
import itdelatrisu.opsu.audio.SoundEffect;
|
||||
import itdelatrisu.opsu.beatmap.Beatmap;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||
import itdelatrisu.opsu.beatmap.HitObject;
|
||||
import itdelatrisu.opsu.beatmap.TimingPoint;
|
||||
import itdelatrisu.opsu.db.BeatmapDB;
|
||||
|
@ -60,41 +59,26 @@ import org.newdawn.slick.Input;
|
|||
import org.newdawn.slick.SlickException;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.*;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.ComplexOpsuState;
|
||||
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
|
||||
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.objects.curves.FakeCombinedCurve;
|
||||
import yugecin.opsudance.options.OptionGroups;
|
||||
import yugecin.opsudance.options.Options;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
import yugecin.opsudance.sbv2.MoveStoryboard;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.ui.OptionsOverlay;
|
||||
import yugecin.opsudance.ui.StoryboardOverlay;
|
||||
import yugecin.opsudance.utils.GLHelper;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* "Game" state.
|
||||
*/
|
||||
public class Game extends ComplexOpsuState {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private GameObjectRenderer gameObjectRenderer;
|
||||
|
||||
@Inject
|
||||
private BeatmapParser beatmapParser;
|
||||
|
||||
public static boolean isInGame; // TODO delete this when #79 is fixed
|
||||
/** Game restart states. */
|
||||
public enum Restart {
|
||||
|
@ -332,7 +316,7 @@ public class Game extends ComplexOpsuState {
|
|||
|
||||
private boolean skippedToCheckpoint;
|
||||
|
||||
public Game(DisplayContainer displayContainer) {
|
||||
public Game() {
|
||||
super();
|
||||
mirrorCursor = new Cursor(true);
|
||||
this.moveStoryboardOverlay = new MoveStoryboard(displayContainer);
|
||||
|
@ -354,7 +338,9 @@ public class Game extends ComplexOpsuState {
|
|||
gOffscreen.setBackground(Color.black);
|
||||
} catch (SlickException e) {
|
||||
Log.error("could not create offscreen graphics", e);
|
||||
EventBus.post(new BubbleNotificationEvent("Exception while creating offscreen graphics. See logfile for details.", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(
|
||||
"Exception while creating offscreen graphics. See logfile for details.",
|
||||
Colors.BUB_RED);
|
||||
}
|
||||
|
||||
// initialize music position bar location
|
||||
|
@ -370,8 +356,7 @@ public class Game extends ComplexOpsuState {
|
|||
scoreboardStarStream.setDurationSpread(700, 100);
|
||||
|
||||
// create the associated GameData object
|
||||
data = instanceContainer.injectFields(new GameData(displayContainer.width, displayContainer.height));
|
||||
gameObjectRenderer.setGameData(data);
|
||||
gameObjectRenderer.gameData = data = new GameData();
|
||||
}
|
||||
|
||||
|
||||
|
@ -725,10 +710,10 @@ public class Game extends ComplexOpsuState {
|
|||
displayContainer.cursor.draw(replayKeyPressed);
|
||||
} else if (GameMod.AUTO.isActive()) {
|
||||
displayContainer.cursor.draw(autoMousePressed);
|
||||
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||
if (OPTION_DANCE_MIRROR.state) {
|
||||
mirrorCursor.draw(autoMousePressed);
|
||||
}
|
||||
} else if (GameMod.AUTOPILOT.isActive()) {
|
||||
} else {
|
||||
displayContainer.cursor.draw(Utils.isGameKeyPressed());
|
||||
}
|
||||
|
||||
|
@ -775,13 +760,6 @@ public class Game extends ComplexOpsuState {
|
|||
if (!isLeadIn())
|
||||
MusicController.resume();
|
||||
}
|
||||
|
||||
// focus lost: go back to pause screen
|
||||
else if (!Display.isActive()) {
|
||||
displayContainer.switchStateNow(GamePauseMenu.class);
|
||||
pausePulse = 0f;
|
||||
}
|
||||
|
||||
// advance pulse animation
|
||||
else {
|
||||
pausePulse += delta / 750f;
|
||||
|
@ -895,7 +873,7 @@ public class Game extends ComplexOpsuState {
|
|||
onCloseRequest();
|
||||
} else {
|
||||
// go to ranking screen
|
||||
displayContainer.switchState(GameRanking.class);
|
||||
displayContainer.switchState(gameRankingState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -942,14 +920,16 @@ public class Game extends ComplexOpsuState {
|
|||
} else if (GameMod.AUTO.isActive()) {
|
||||
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
|
||||
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive()) {
|
||||
double dx = autoMousePosition.x - Options.width / 2d;
|
||||
double dy = autoMousePosition.y - Options.height / 2d;
|
||||
double dx = autoMousePosition.x - displayContainer.width / 2d;
|
||||
double dy = autoMousePosition.y - displayContainer.height / 2d;
|
||||
double d = Math.sqrt(dx * dx + dy * dy);
|
||||
double a = Math.atan2(dy, dx) + Math.PI;
|
||||
mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + Options.width / 2), (int) (Math.sin(a) * d + Options.height / 2));
|
||||
mirrorCursor.setCursorPosition(displayContainer.delta, (int) (Math.cos(a) * d + displayContainer.width / 2), (int) (Math.sin(a) * d + displayContainer.height / 2));
|
||||
}
|
||||
} else if (GameMod.AUTOPILOT.isActive()) {
|
||||
displayContainer.cursor.setCursorPosition(displayContainer.delta, (int) autoMousePosition.x, (int) autoMousePosition.y);
|
||||
} else {
|
||||
displayContainer.cursor.setCursorPosition(displayContainer.delta, displayContainer.mouseX, displayContainer.mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -977,7 +957,7 @@ public class Game extends ComplexOpsuState {
|
|||
// save score and replay
|
||||
if (!checkpointLoaded) {
|
||||
boolean unranked = (GameMod.AUTO.isActive() || GameMod.RELAX.isActive() || GameMod.AUTOPILOT.isActive());
|
||||
instanceContainer.provide(GameRanking.class).setGameData(data);
|
||||
gameRankingState.setGameData(data);
|
||||
if (isReplay)
|
||||
data.setReplay(replay);
|
||||
else if (replayFrames != null) {
|
||||
|
@ -1063,7 +1043,7 @@ public class Game extends ComplexOpsuState {
|
|||
if (MusicController.isPlaying() || isLeadIn()) {
|
||||
pauseTime = trackPosition;
|
||||
}
|
||||
displayContainer.switchStateNow(GamePauseMenu.class);
|
||||
displayContainer.switchStateInstantly(pauseState);
|
||||
}
|
||||
|
||||
// drain health
|
||||
|
@ -1090,7 +1070,7 @@ public class Game extends ComplexOpsuState {
|
|||
rotations = new IdentityHashMap<>();
|
||||
SoundController.playSound(SoundEffect.FAIL);
|
||||
|
||||
displayContainer.switchState(GamePauseMenu.class, FadeOutTransitionState.class, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, FadeInTransitionState.class, 300);
|
||||
displayContainer.switchState(pauseState, MUSIC_FADEOUT_TIME - LOSE_FADEOUT_TIME, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1123,8 +1103,8 @@ public class Game extends ComplexOpsuState {
|
|||
|
||||
@Override
|
||||
public boolean onCloseRequest() {
|
||||
instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
songMenuState.resetGameDataOnLoad();
|
||||
displayContainer.switchState(songMenuState);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1156,7 +1136,7 @@ public class Game extends ComplexOpsuState {
|
|||
}
|
||||
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
case KEY_ESCAPE:
|
||||
// "auto" mod or watching replay: go back to song menu
|
||||
if (GameMod.AUTO.isActive() || isReplay) {
|
||||
onCloseRequest();
|
||||
|
@ -1171,15 +1151,15 @@ public class Game extends ComplexOpsuState {
|
|||
if (MusicController.isPlaying() || isLeadIn()) {
|
||||
pauseTime = trackPosition;
|
||||
}
|
||||
displayContainer.switchStateNow(GamePauseMenu.class);
|
||||
displayContainer.switchStateInstantly(pauseState);
|
||||
break;
|
||||
case Input.KEY_SPACE:
|
||||
case KEY_SPACE:
|
||||
// skip intro
|
||||
skipIntro();
|
||||
break;
|
||||
case Input.KEY_R:
|
||||
case KEY_R:
|
||||
// restart
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
|
||||
if (input.isControlDown()) {
|
||||
if (trackPosition < beatmap.objects[0].getTime()) {
|
||||
retries--; // don't count this retry (cancel out later increment)
|
||||
}
|
||||
|
@ -1188,9 +1168,9 @@ public class Game extends ComplexOpsuState {
|
|||
skipIntro();
|
||||
}
|
||||
break;
|
||||
case Input.KEY_S:
|
||||
case KEY_S:
|
||||
// save checkpoint
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
|
||||
if (input.isControlDown()) {
|
||||
if (isLeadIn()) {
|
||||
break;
|
||||
}
|
||||
|
@ -1200,40 +1180,40 @@ public class Game extends ComplexOpsuState {
|
|||
if (0 <= time && time < 3600) {
|
||||
OPTION_CHECKPOINT.setValue(time);
|
||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||
EventBus.post(new BarNotificationEvent("Checkpoint saved."));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Checkpoint saved.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Input.KEY_L:
|
||||
case KEY_L:
|
||||
// load checkpoint
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
|
||||
if (input.isControlDown()) {
|
||||
int checkpoint = OPTION_CHECKPOINT.val * 1000;
|
||||
if (checkpoint == 0 || checkpoint > beatmap.endTime)
|
||||
break; // invalid checkpoint
|
||||
loadCheckpoint(checkpoint);
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
EventBus.post(new BarNotificationEvent("Checkpoint loaded."));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Checkpoint loaded.");
|
||||
}
|
||||
break;
|
||||
case Input.KEY_F:
|
||||
case KEY_F:
|
||||
// change playback speed
|
||||
if (isReplay || GameMod.AUTO.isActive()) {
|
||||
playbackSpeed = playbackSpeed.next();
|
||||
MusicController.setPitch(GameMod.getSpeedMultiplier() * playbackSpeed.getModifier());
|
||||
}
|
||||
break;
|
||||
case Input.KEY_UP:
|
||||
case KEY_UP:
|
||||
UI.changeVolume(1);
|
||||
break;
|
||||
case Input.KEY_DOWN:
|
||||
case KEY_DOWN:
|
||||
UI.changeVolume(-1);
|
||||
break;
|
||||
case Input.KEY_TAB:
|
||||
case KEY_TAB:
|
||||
if (!OPTION_DANCE_HIDE_UI.state) {
|
||||
scoreboardVisible = !scoreboardVisible;
|
||||
}
|
||||
break;
|
||||
case Input.KEY_M:
|
||||
case KEY_M:
|
||||
if (OPTION_DANCE_MIRROR.state) {
|
||||
mirrorTo = objectIndex;
|
||||
} else {
|
||||
|
@ -1243,7 +1223,7 @@ public class Game extends ComplexOpsuState {
|
|||
}
|
||||
OPTION_DANCE_MIRROR.toggle();
|
||||
break;
|
||||
case Input.KEY_P:
|
||||
case KEY_P:
|
||||
if (OPTION_DANCE_MIRROR.state) {
|
||||
mirrorTo = objectIndex;
|
||||
} else {
|
||||
|
@ -1253,14 +1233,14 @@ public class Game extends ComplexOpsuState {
|
|||
}
|
||||
OPTION_DANCE_MIRROR.toggle();
|
||||
break;
|
||||
case Input.KEY_MINUS:
|
||||
case KEY_MINUS:
|
||||
currentMapMusicOffset += 5;
|
||||
EventBus.post(new BarNotificationEvent("Current map offset: " + currentMapMusicOffset));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
|
||||
break;
|
||||
}
|
||||
if (key == Input.KEY_ADD || c == '+') {
|
||||
if (key == KEY_ADD || c == '+') {
|
||||
currentMapMusicOffset -= 5;
|
||||
EventBus.post(new BarNotificationEvent("Current map offset: " + currentMapMusicOffset));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Current map offset: " + currentMapMusicOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1324,7 +1304,7 @@ public class Game extends ComplexOpsuState {
|
|||
if (MusicController.isPlaying() || isLeadIn()) {
|
||||
pauseTime = trackPosition;
|
||||
}
|
||||
displayContainer.switchStateNow(GamePauseMenu.class);
|
||||
displayContainer.switchStateInstantly(pauseState);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1425,7 +1405,7 @@ public class Game extends ComplexOpsuState {
|
|||
keys = ReplayFrame.KEY_K2;
|
||||
}
|
||||
if (keys != ReplayFrame.KEY_NONE) {
|
||||
gameKeyReleased(keys, displayContainer.input.getMouseX(), displayContainer.input.getMouseY(), MusicController.getPosition());
|
||||
gameKeyReleased(keys, input.getMouseX(), input.getMouseY(), MusicController.getPosition());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1511,9 +1491,7 @@ public class Game extends ComplexOpsuState {
|
|||
hue += hueshift;
|
||||
}
|
||||
|
||||
if (isReplay || GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
|
||||
displayContainer.drawCursor = false;
|
||||
}
|
||||
displayContainer.drawCursor = false;
|
||||
|
||||
isInGame = true;
|
||||
if (!skippedToCheckpoint) {
|
||||
|
@ -1521,8 +1499,8 @@ public class Game extends ComplexOpsuState {
|
|||
}
|
||||
|
||||
if (beatmap == null || beatmap.objects == null) {
|
||||
EventBus.post(new BubbleNotificationEvent("Game was running without a beatmap", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
displayContainer.switchStateInstantly(SongMenu.class);
|
||||
BubNotifListener.EVENT.make().onBubNotif("Game was running without a beatmap", Colors.BUB_RED);
|
||||
displayContainer.switchStateInstantly(songMenuState);
|
||||
}
|
||||
|
||||
Dancer.instance.reset();
|
||||
|
@ -1619,16 +1597,16 @@ public class Game extends ComplexOpsuState {
|
|||
|
||||
try {
|
||||
if (hitObject.isCircle()) {
|
||||
gameObjects[i] = instanceContainer.injectFields(new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
|
||||
gameObjects[i] = new Circle(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
|
||||
} else if (hitObject.isSlider()) {
|
||||
gameObjects[i] = instanceContainer.injectFields(new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd));
|
||||
gameObjects[i] = new Slider(hitObject, this, data, hitObject.getComboIndex(), comboEnd);
|
||||
} else if (hitObject.isSpinner()) {
|
||||
gameObjects[i] = new Spinner(hitObject, this, data);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String message = String.format("Failed to create %s at index %d:\n%s", hitObject.getTypeName(), i, hitObject.toString());
|
||||
Log.error(message, e);
|
||||
EventBus.post(new BubbleNotificationEvent(message, BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif(message, Colors.BUB_RED);
|
||||
gameObjects[i] = new DummyObject(hitObject);
|
||||
}
|
||||
}
|
||||
|
@ -1909,7 +1887,7 @@ public class Game extends ComplexOpsuState {
|
|||
gameObj.draw(g, trackPosition, false);
|
||||
if (OPTION_DANCE_MIRROR.state && GameMod.AUTO.isActive() && idx < mirrorTo && idx >= mirrorFrom) {
|
||||
g.pushTransform();
|
||||
g.rotate(Options.width / 2f, Options.height / 2f, 180f);
|
||||
g.rotate(displayContainer.width / 2f, displayContainer.height / 2f, 180f);
|
||||
gameObj.draw(g, trackPosition, true);
|
||||
g.popTransform();
|
||||
}
|
||||
|
@ -2053,7 +2031,7 @@ public class Game extends ComplexOpsuState {
|
|||
skipButton.setHoverExpand(1.1f, MenuButton.Expand.UP_LEFT);
|
||||
|
||||
// load other images...
|
||||
instanceContainer.provide(GamePauseMenu.class).loadImages();
|
||||
pauseState.loadImages();
|
||||
data.loadImages();
|
||||
}
|
||||
|
||||
|
@ -2090,7 +2068,7 @@ public class Game extends ComplexOpsuState {
|
|||
|
||||
// initialize objects
|
||||
gameObjectRenderer.initForGame(data, diameter);
|
||||
Slider.init(gameObjectRenderer.getCircleDiameter(), beatmap);
|
||||
Slider.init(gameObjectRenderer.circleDiameter, beatmap);
|
||||
Spinner.init(displayContainer, overallDifficulty);
|
||||
Color sliderBorderColor = SkinService.skin.getSliderBorderColor();
|
||||
if (!OPTION_IGNORE_BEATMAP_SKINS.state && beatmap.getSliderBorderColor() != null) {
|
||||
|
@ -2214,7 +2192,8 @@ public class Game extends ComplexOpsuState {
|
|||
this.replay = null;
|
||||
} else {
|
||||
if (replay.frames == null) {
|
||||
EventBus.post(new BubbleNotificationEvent("Attempting to set a replay with no frames.", BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Attempting to set a replay with no frames.",
|
||||
Colors.BUB_ORANGE);
|
||||
return;
|
||||
}
|
||||
this.isReplay = true;
|
||||
|
|
|
@ -30,10 +30,10 @@ import org.lwjgl.input.Keyboard;
|
|||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -44,12 +44,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class GamePauseMenu extends BaseOpsuState {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private Game gameState;
|
||||
|
||||
private MenuButton continueButton, retryButton, backButton;
|
||||
|
||||
@Override
|
||||
|
@ -101,24 +95,24 @@ public class GamePauseMenu extends BaseOpsuState {
|
|||
}
|
||||
}
|
||||
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == KEY_ESCAPE) {
|
||||
// 'esc' will normally unpause, but will return to song menu if health is zero
|
||||
if (gameState.getRestart() == Game.Restart.LOSE) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
|
||||
songMenuState.resetGameDataOnLoad();
|
||||
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
displayContainer.switchState(songMenuState);
|
||||
} else {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
gameState.setRestart(Game.Restart.FALSE);
|
||||
displayContainer.switchState(Game.class);
|
||||
displayContainer.switchState(gameState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == Input.KEY_R && (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL))) {
|
||||
if (key == KEY_R && input.isControlDown()) {
|
||||
gameState.setRestart(Game.Restart.MANUAL);
|
||||
displayContainer.switchState(Game.class);
|
||||
displayContainer.switchState(gameState);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -139,14 +133,14 @@ public class GamePauseMenu extends BaseOpsuState {
|
|||
if (continueButton.contains(x, y) && !loseState) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
gameState.setRestart(Game.Restart.FALSE);
|
||||
displayContainer.switchState(Game.class);
|
||||
displayContainer.switchState(gameState);
|
||||
} else if (retryButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
gameState.setRestart(Game.Restart.MANUAL);
|
||||
displayContainer.switchState(Game.class);
|
||||
displayContainer.switchState(gameState);
|
||||
} else if (backButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
instanceContainer.provide(SongMenu.class).resetGameDataOnLoad();
|
||||
songMenuState.resetGameDataOnLoad();
|
||||
if (loseState)
|
||||
MusicController.playAt(MusicController.getBeatmap().previewTime, true);
|
||||
else
|
||||
|
@ -155,7 +149,7 @@ public class GamePauseMenu extends BaseOpsuState {
|
|||
displayContainer.resetCursor();
|
||||
}
|
||||
MusicController.setPitch(1.0f);
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -188,10 +182,9 @@ public class GamePauseMenu extends BaseOpsuState {
|
|||
|
||||
@Override
|
||||
public boolean onCloseRequest() {
|
||||
SongMenu songmenu = instanceContainer.provide(SongMenu.class);
|
||||
songmenu.resetTrackOnLoad();
|
||||
songmenu.resetGameDataOnLoad();
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
songMenuState.resetTrackOnLoad();
|
||||
songMenuState.resetGameDataOnLoad();
|
||||
displayContainer.switchState(songMenuState);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,15 +32,15 @@ import itdelatrisu.opsu.ui.UI;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* "Game Ranking" (score card) state.
|
||||
|
@ -51,9 +51,6 @@ import yugecin.opsudance.events.BarNotificationEvent;
|
|||
*/
|
||||
public class GameRanking extends BaseOpsuState {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
/** Associated GameData object. */
|
||||
private GameData data;
|
||||
|
||||
|
@ -125,7 +122,7 @@ public class GameRanking extends BaseOpsuState {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
returnToSongMenu();
|
||||
}
|
||||
return true;
|
||||
|
@ -149,7 +146,6 @@ public class GameRanking extends BaseOpsuState {
|
|||
}
|
||||
|
||||
// replay
|
||||
Game gameState = instanceContainer.provide(Game.class);
|
||||
boolean returnToGame = false;
|
||||
boolean replayButtonPressed = replayButton.contains(x, y);
|
||||
if (replayButtonPressed && !(data.isGameplay() && GameMod.AUTO.isActive())) {
|
||||
|
@ -161,13 +157,14 @@ public class GameRanking extends BaseOpsuState {
|
|||
gameState.setRestart((data.isGameplay()) ? Game.Restart.REPLAY : Game.Restart.NEW);
|
||||
returnToGame = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
EventBus.post(new BarNotificationEvent("Replay file not found."));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Replay file not found.");
|
||||
} catch (IOException e) {
|
||||
Log.error("Failed to load replay data.", e);
|
||||
EventBus.post(new BarNotificationEvent("Failed to load replay data. See log for details."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"Failed to load replay data. See log for details.");
|
||||
}
|
||||
} else
|
||||
EventBus.post(new BarNotificationEvent("Replay file not found."));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Replay file not found.");
|
||||
}
|
||||
|
||||
// retry
|
||||
|
@ -183,7 +180,7 @@ public class GameRanking extends BaseOpsuState {
|
|||
Beatmap beatmap = MusicController.getBeatmap();
|
||||
gameState.loadBeatmap(beatmap);
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
displayContainer.switchState(Game.class);
|
||||
displayContainer.switchState(gameState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -217,12 +214,11 @@ public class GameRanking extends BaseOpsuState {
|
|||
|
||||
@Override
|
||||
public boolean onCloseRequest() {
|
||||
SongMenu songmenu = instanceContainer.provide(SongMenu.class);
|
||||
if (data != null && data.isGameplay()) {
|
||||
songmenu.resetTrackOnLoad();
|
||||
songMenuState.resetTrackOnLoad();
|
||||
}
|
||||
songmenu.resetGameDataOnLoad();
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
songMenuState.resetGameDataOnLoad();
|
||||
displayContainer.switchState(songMenuState);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -232,25 +228,24 @@ public class GameRanking extends BaseOpsuState {
|
|||
private void returnToSongMenu() {
|
||||
SoundController.muteSoundComponent();
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
SongMenu songMenu = instanceContainer.provide(SongMenu.class);
|
||||
if (data.isGameplay()) {
|
||||
songMenu.resetTrackOnLoad();
|
||||
songMenuState.resetTrackOnLoad();
|
||||
}
|
||||
songMenu.resetGameDataOnLoad();
|
||||
songMenuState.resetGameDataOnLoad();
|
||||
if (displayContainer.cursor.isBeatmapSkinned()) {
|
||||
displayContainer.resetCursor();
|
||||
}
|
||||
displayContainer.switchState(SongMenu.class);
|
||||
displayContainer.switchState(songMenuState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the associated GameData object.
|
||||
* @param data the GameData
|
||||
*/
|
||||
public void setGameData(GameData data) { this.data = data; }
|
||||
public void setGameData(GameData data) { this.data = data; } // TODO why is this unused
|
||||
|
||||
/**
|
||||
* Returns the current GameData object (usually null unless state active).
|
||||
*/
|
||||
public GameData getGameData() { return data; }
|
||||
public GameData getGameData() { return data; } // TODO why is this unused
|
||||
}
|
||||
|
|
|
@ -45,14 +45,14 @@ import org.newdawn.slick.Graphics;
|
|||
import org.newdawn.slick.Image;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.Constants;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
import yugecin.opsudance.core.state.OpsuState;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -62,12 +62,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class MainMenu extends BaseOpsuState {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private Updater updater;
|
||||
|
||||
/** Idle time, in milliseconds, before returning the logo to its original position. */
|
||||
private static final short LOGO_IDLE_DELAY = 10000;
|
||||
|
||||
|
@ -472,12 +466,11 @@ public class MainMenu extends BaseOpsuState {
|
|||
UI.enter();
|
||||
if (!enterNotification) {
|
||||
if (updater.getStatus() == Updater.Status.UPDATE_AVAILABLE) {
|
||||
EventBus.post(new BarNotificationEvent("An opsu! update is available."));
|
||||
enterNotification = true;
|
||||
BarNotifListener.EVENT.make().onBarNotif("An opsu! update is available.");
|
||||
} else if (updater.justUpdated()) {
|
||||
EventBus.post(new BarNotificationEvent("opsu! is now up to date!"));
|
||||
enterNotification = true;
|
||||
BarNotifListener.EVENT.make().onBarNotif("opsu! is now up to date!");
|
||||
}
|
||||
enterNotification = true;
|
||||
}
|
||||
|
||||
// reset measure info
|
||||
|
@ -538,58 +531,60 @@ public class MainMenu extends BaseOpsuState {
|
|||
if (musicPlay.contains(x, y)) {
|
||||
if (MusicController.isPlaying()) {
|
||||
MusicController.pause();
|
||||
EventBus.post(new BarNotificationEvent("Pause"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Pause");
|
||||
} else if (!MusicController.isTrackLoading()) {
|
||||
MusicController.resume();
|
||||
EventBus.post(new BarNotificationEvent("Play"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Play");
|
||||
}
|
||||
return true;
|
||||
} else if (musicNext.contains(x, y)) {
|
||||
nextTrack(true);
|
||||
EventBus.post(new BarNotificationEvent(">> Next"));
|
||||
BarNotifListener.EVENT.make().onBarNotif(">> Next");
|
||||
return true;
|
||||
} else if (musicPrevious.contains(x, y)) {
|
||||
lastMeasureProgress = 0f;
|
||||
if (!previous.isEmpty()) {
|
||||
instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
|
||||
songMenuState.setFocus(BeatmapSetList.get().getBaseNode(previous.pop()), -1, true, false);
|
||||
if (OPTION_DYNAMIC_BACKGROUND.state) {
|
||||
bgAlpha.setTime(0);
|
||||
}
|
||||
} else {
|
||||
MusicController.setPosition(0);
|
||||
}
|
||||
EventBus.post(new BarNotificationEvent("<< Previous"));
|
||||
BarNotifListener.EVENT.make().onBarNotif("<< Previous");
|
||||
return true;
|
||||
}
|
||||
|
||||
// downloads button actions
|
||||
if (downloadsButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
displayContainer.switchState(DownloadsMenu.class);
|
||||
displayContainer.switchState(downloadState);
|
||||
return true;
|
||||
}
|
||||
|
||||
// repository button actions
|
||||
if (repoButton != null && repoButton.contains(x, y)) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(config.REPOSITORY_URI);
|
||||
Desktop.getDesktop().browse(Constants.REPOSITORY_URI);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"The repository web page could not be opened.");
|
||||
} catch (IOException e) {
|
||||
Log.error("could not browse to repo", e);
|
||||
EventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Could not browse to repo", Colors.BUB_ORANGE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (danceRepoButton != null && danceRepoButton.contains(x, y)) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(config.DANCE_REPOSITORY_URI);
|
||||
Desktop.getDesktop().browse(Constants.DANCE_REPOSITORY_URI);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
EventBus.post(new BarNotificationEvent("The repository web page could not be opened."));
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"The repository web page could not be opened.");
|
||||
} catch (IOException e) {
|
||||
Log.error("could not browse to repo", e);
|
||||
EventBus.post(new BubbleNotificationEvent("Could not browse to repo", BubbleNotificationEvent.COLOR_ORANGE));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Could not browse to repo", Colors.BUB_ORANGE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -657,18 +652,18 @@ public class MainMenu extends BaseOpsuState {
|
|||
}
|
||||
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
case Input.KEY_Q:
|
||||
case KEY_ESCAPE:
|
||||
case KEY_Q:
|
||||
if (logoTimer > 0) {
|
||||
logoState = LogoState.CLOSING;
|
||||
logoClose.setTime(0);
|
||||
logoTimer = 0;
|
||||
break;
|
||||
}
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.EXIT);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(MenuState.EXIT);
|
||||
displayContainer.switchState(buttonState);
|
||||
return true;
|
||||
case Input.KEY_P:
|
||||
case KEY_P:
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
if (logoState == LogoState.DEFAULT || logoState == LogoState.CLOSING) {
|
||||
logoState = LogoState.OPENING;
|
||||
|
@ -679,17 +674,17 @@ public class MainMenu extends BaseOpsuState {
|
|||
} else
|
||||
enterSongMenu();
|
||||
return true;
|
||||
case Input.KEY_D:
|
||||
case KEY_D:
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
displayContainer.switchState(DownloadsMenu.class);
|
||||
displayContainer.switchState(downloadState);
|
||||
return true;
|
||||
case Input.KEY_R:
|
||||
case KEY_R:
|
||||
nextTrack(true);
|
||||
return true;
|
||||
case Input.KEY_UP:
|
||||
case KEY_UP:
|
||||
UI.changeVolume(1);
|
||||
return true;
|
||||
case Input.KEY_DOWN:
|
||||
case KEY_DOWN:
|
||||
UI.changeVolume(-1);
|
||||
return true;
|
||||
}
|
||||
|
@ -719,7 +714,7 @@ public class MainMenu extends BaseOpsuState {
|
|||
MusicController.playAt(0, false);
|
||||
return;
|
||||
}
|
||||
BeatmapSetNode node = instanceContainer.provide(SongMenu.class).setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
|
||||
BeatmapSetNode node = songMenuState.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, false);
|
||||
boolean sameAudio = false;
|
||||
if (node != null) {
|
||||
sameAudio = MusicController.getBeatmap().audioFilename.equals(node.getBeatmapSet().get(0).audioFilename);
|
||||
|
@ -735,10 +730,10 @@ public class MainMenu extends BaseOpsuState {
|
|||
* Enters the song menu, or the downloads menu if no beatmaps are loaded.
|
||||
*/
|
||||
private void enterSongMenu() {
|
||||
Class<? extends OpsuState> state = SongMenu.class;
|
||||
OpsuState state = songMenuState;
|
||||
if (BeatmapSetList.get().getMapSetCount() == 0) {
|
||||
instanceContainer.provide(DownloadsMenu.class).notifyOnLoad("Download some beatmaps to get started!");
|
||||
state = DownloadsMenu.class;
|
||||
downloadState.notifyOnLoad("Download some beatmaps to get started!");
|
||||
state = downloadState;
|
||||
}
|
||||
displayContainer.switchState(state);
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import itdelatrisu.opsu.beatmap.BeatmapSortOrder;
|
|||
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapWatchService.BeatmapWatchServiceListener;
|
||||
import itdelatrisu.opsu.beatmap.LRUCache;
|
||||
import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||
import itdelatrisu.opsu.db.BeatmapDB;
|
||||
import itdelatrisu.opsu.db.ScoreDB;
|
||||
import itdelatrisu.opsu.states.ButtonMenu.MenuState;
|
||||
|
@ -56,6 +55,7 @@ import java.nio.file.WatchEvent.Kind;
|
|||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.newdawn.slick.Animation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
|
@ -63,16 +63,13 @@ import org.newdawn.slick.Image;
|
|||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.SpriteSheet;
|
||||
import org.newdawn.slick.gui.TextField;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.ComplexOpsuState;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.options.OptionGroups;
|
||||
import yugecin.opsudance.ui.OptionsOverlay;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -83,18 +80,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class SongMenu extends ComplexOpsuState {
|
||||
|
||||
@Inject
|
||||
private InstanceContainer instanceContainer;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
@Inject
|
||||
private OszUnpacker oszUnpacker;
|
||||
|
||||
@Inject
|
||||
private BeatmapParser beatmapParser;
|
||||
|
||||
/** The max number of song buttons to be shown on each screen. */
|
||||
public static final int MAX_SONG_BUTTONS = 6;
|
||||
|
||||
|
@ -246,7 +231,7 @@ public class SongMenu extends ComplexOpsuState {
|
|||
private void reloadBeatmaps() {
|
||||
if (fullReload) {
|
||||
BeatmapDB.clearDatabase();
|
||||
oszUnpacker.unpackAll();
|
||||
oszunpacker.unpackAll();
|
||||
}
|
||||
beatmapParser.parseAll();
|
||||
}
|
||||
|
@ -328,7 +313,7 @@ public class SongMenu extends ComplexOpsuState {
|
|||
|
||||
private final OptionsOverlay optionsOverlay;
|
||||
|
||||
public SongMenu(DisplayContainer displayContainer) {
|
||||
public SongMenu() {
|
||||
super();
|
||||
optionsOverlay = new OptionsOverlay(displayContainer, OptionGroups.normalOptions);
|
||||
overlays.add(optionsOverlay);
|
||||
|
@ -406,7 +391,7 @@ public class SongMenu extends ComplexOpsuState {
|
|||
// search
|
||||
int textFieldX = (int) (displayContainer.width * 0.7125f + Fonts.BOLD.getWidth("Search: "));
|
||||
int textFieldY = (int) (headerY + Fonts.BOLD.getLineHeight() / 2);
|
||||
searchTextField = new TextField(displayContainer, Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
|
||||
searchTextField = new TextField(Fonts.BOLD, textFieldX, textFieldY, (int) (displayContainer.width * 0.99f) - textFieldX, Fonts.BOLD.getLineHeight()) {
|
||||
@Override
|
||||
public boolean isFocusable() {
|
||||
return false;
|
||||
|
@ -454,12 +439,15 @@ public class SongMenu extends ComplexOpsuState {
|
|||
BeatmapWatchService.addListener(new BeatmapWatchServiceListener() {
|
||||
@Override
|
||||
public void eventReceived(Kind<?> kind, Path child) {
|
||||
if (!songFolderChanged && kind != StandardWatchEventKinds.ENTRY_MODIFY) {
|
||||
songFolderChanged = true;
|
||||
if (displayContainer.isInState(SongMenu.class)) {
|
||||
EventBus.post(new BarNotificationEvent("Changed is Songs folder detected. Hit F5 to refresh."));
|
||||
}
|
||||
if (songFolderChanged || kind == StandardWatchEventKinds.ENTRY_MODIFY) {
|
||||
return;
|
||||
}
|
||||
songFolderChanged = true;
|
||||
if (!displayContainer.isInState(SongMenu.class)) {
|
||||
return;
|
||||
}
|
||||
BarNotifListener.EVENT.make().onBarNotif(
|
||||
"Changed is Songs folder detected. Hit F5 to refresh.");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -761,8 +749,8 @@ public class SongMenu extends ComplexOpsuState {
|
|||
if (focusNode != null) {
|
||||
MenuState state = focusNode.getBeatmapSet().isFavorite() ?
|
||||
MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP;
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(state, focusNode);
|
||||
displayContainer.switchState(buttonState);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -922,19 +910,19 @@ public class SongMenu extends ComplexOpsuState {
|
|||
|
||||
if (UI.getBackButton().contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
displayContainer.switchState(MainMenu.class);
|
||||
displayContainer.switchState(mainmenuState);
|
||||
return true;
|
||||
}
|
||||
|
||||
// selection buttons
|
||||
if (selectModsButton.contains(x, y)) {
|
||||
this.keyPressed(Input.KEY_F1, '\0');
|
||||
this.keyPressed(KEY_F1, '\0');
|
||||
return true;
|
||||
} else if (selectRandomButton.contains(x, y)) {
|
||||
this.keyPressed(Input.KEY_F2, '\0');
|
||||
this.keyPressed(KEY_F2, '\0');
|
||||
return true;
|
||||
} else if (selectMapOptionsButton.contains(x, y)) {
|
||||
this.keyPressed(Input.KEY_F3, '\0');
|
||||
this.keyPressed(KEY_F3, '\0');
|
||||
return true;
|
||||
} else if (selectOptionsButton.contains(x, y)) {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
|
@ -944,30 +932,32 @@ public class SongMenu extends ComplexOpsuState {
|
|||
|
||||
// group tabs
|
||||
for (BeatmapGroup group : BeatmapGroup.values()) {
|
||||
if (group.contains(x, y)) {
|
||||
if (group != BeatmapGroup.current()) {
|
||||
BeatmapGroup.set(group);
|
||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||
startNode = focusNode = null;
|
||||
oldFocusNode = null;
|
||||
randomStack = new Stack<SongNode>();
|
||||
songInfo = null;
|
||||
scoreMap = null;
|
||||
focusScores = null;
|
||||
searchTextField.setText("");
|
||||
searchTimer = SEARCH_DELAY;
|
||||
searchTransitionTimer = SEARCH_TRANSITION_TIME;
|
||||
searchResultString = null;
|
||||
BeatmapSetList.get().reset();
|
||||
BeatmapSetList.get().init();
|
||||
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||
|
||||
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) {
|
||||
EventBus.post(new BarNotificationEvent(group.getEmptyMessage()));
|
||||
}
|
||||
}
|
||||
if (!group.contains(x, y)) {
|
||||
continue;
|
||||
}
|
||||
if (group == BeatmapGroup.current()) {
|
||||
return true;
|
||||
}
|
||||
BeatmapGroup.set(group);
|
||||
SoundController.playSound(SoundEffect.MENUCLICK);
|
||||
startNode = focusNode = null;
|
||||
oldFocusNode = null;
|
||||
randomStack = new Stack<SongNode>();
|
||||
songInfo = null;
|
||||
scoreMap = null;
|
||||
focusScores = null;
|
||||
searchTextField.setText("");
|
||||
searchTimer = SEARCH_DELAY;
|
||||
searchTransitionTimer = SEARCH_TRANSITION_TIME;
|
||||
searchResultString = null;
|
||||
BeatmapSetList.get().reset();
|
||||
BeatmapSetList.get().init();
|
||||
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||
|
||||
if (BeatmapSetList.get().size() < 1 && group.getEmptyMessage() != null) {
|
||||
BarNotifListener.EVENT.make().onBarNotif(group.getEmptyMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (focusNode == null) {
|
||||
|
@ -1029,12 +1019,12 @@ public class SongMenu extends ComplexOpsuState {
|
|||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
if (button != Input.MOUSE_RIGHT_BUTTON) {
|
||||
// view score
|
||||
instanceContainer.provide(GameRanking.class).setGameData(instanceContainer.injectFields(new GameData(focusScores[rank], displayContainer.width, displayContainer.height)));
|
||||
displayContainer.switchState(GameRanking.class);
|
||||
gameRankingState.setGameData(new GameData(focusScores[rank]));
|
||||
displayContainer.switchState(gameRankingState);
|
||||
} else {
|
||||
// score management
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.SCORE, focusScores[rank]);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(MenuState.SCORE, focusScores[rank]);
|
||||
displayContainer.switchState(buttonState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1050,14 +1040,12 @@ public class SongMenu extends ComplexOpsuState {
|
|||
}
|
||||
|
||||
// block input
|
||||
if ((reloadThread != null && key != Input.KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) {
|
||||
if ((reloadThread != null && key != KEY_ESCAPE) || beatmapMenuTimer > -1 || isScrollingToFocusNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Input input = displayContainer.input;
|
||||
|
||||
switch (key) {
|
||||
case Input.KEY_ESCAPE:
|
||||
case KEY_ESCAPE:
|
||||
if (reloadThread != null) {
|
||||
// beatmap reloading: stop parsing beatmaps by sending interrupt to BeatmapParser
|
||||
reloadThread.interrupt();
|
||||
|
@ -1070,19 +1058,19 @@ public class SongMenu extends ComplexOpsuState {
|
|||
} else {
|
||||
// return to main menu
|
||||
SoundController.playSound(SoundEffect.MENUBACK);
|
||||
displayContainer.switchState(MainMenu.class);
|
||||
displayContainer.switchState(mainmenuState);
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_F1:
|
||||
case KEY_F1:
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.MODS);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(MenuState.MODS);
|
||||
displayContainer.switchState(buttonState);
|
||||
return true;
|
||||
case Input.KEY_F2:
|
||||
case KEY_F2:
|
||||
if (focusNode == null)
|
||||
break;
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
|
||||
if (isKeyDown(KEY_RSHIFT) || isKeyDown(KEY_LSHIFT)) {
|
||||
// shift key: previous random track
|
||||
SongNode prev;
|
||||
if (randomStack.isEmpty() || (prev = randomStack.pop()) == null)
|
||||
|
@ -1098,47 +1086,47 @@ public class SongMenu extends ComplexOpsuState {
|
|||
setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_F3:
|
||||
case KEY_F3:
|
||||
if (focusNode == null)
|
||||
break;
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
MenuState state = focusNode.getBeatmapSet().isFavorite() ?
|
||||
MenuState.BEATMAP_FAVORITE : MenuState.BEATMAP;
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(state, focusNode);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(state, focusNode);
|
||||
displayContainer.switchState(buttonState);
|
||||
return true;
|
||||
case Input.KEY_F5:
|
||||
case KEY_F5:
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
if (songFolderChanged)
|
||||
reloadBeatmaps(false);
|
||||
else {
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(MenuState.RELOAD);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(MenuState.RELOAD);
|
||||
displayContainer.switchState(buttonState);
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_DELETE:
|
||||
case KEY_DELETE:
|
||||
if (focusNode == null)
|
||||
break;
|
||||
if (input.isKeyDown(Input.KEY_RSHIFT) || input.isKeyDown(Input.KEY_LSHIFT)) {
|
||||
if (isKeyDown(KEY_RSHIFT) || isKeyDown(KEY_LSHIFT)) {
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
MenuState ms = (focusNode.beatmapIndex == -1 || focusNode.getBeatmapSet().size() == 1) ?
|
||||
MenuState.BEATMAP_DELETE_CONFIRM : MenuState.BEATMAP_DELETE_SELECT;
|
||||
instanceContainer.provide(ButtonMenu.class).setMenuState(ms, focusNode);
|
||||
displayContainer.switchState(ButtonMenu.class);
|
||||
buttonState.setMenuState(ms, focusNode);
|
||||
displayContainer.switchState(buttonState);
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_ENTER:
|
||||
case KEY_RETURN:
|
||||
if (focusNode == null)
|
||||
break;
|
||||
startGame();
|
||||
return true;
|
||||
case Input.KEY_DOWN:
|
||||
case KEY_DOWN:
|
||||
changeIndex(1);
|
||||
return true;
|
||||
case Input.KEY_UP:
|
||||
case KEY_UP:
|
||||
changeIndex(-1);
|
||||
return true;
|
||||
case Input.KEY_RIGHT:
|
||||
case KEY_RIGHT:
|
||||
if (focusNode == null)
|
||||
break;
|
||||
BeatmapSetNode next = focusNode.next;
|
||||
|
@ -1154,7 +1142,7 @@ public class SongMenu extends ComplexOpsuState {
|
|||
}
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_LEFT:
|
||||
case KEY_LEFT:
|
||||
if (focusNode == null)
|
||||
break;
|
||||
BeatmapSetNode prev = focusNode.prev;
|
||||
|
@ -1170,25 +1158,25 @@ public class SongMenu extends ComplexOpsuState {
|
|||
}
|
||||
}
|
||||
return true;
|
||||
case Input.KEY_NEXT:
|
||||
case KEY_NEXT:
|
||||
changeIndex(MAX_SONG_BUTTONS);
|
||||
return true;
|
||||
case Input.KEY_PRIOR:
|
||||
case KEY_PRIOR:
|
||||
changeIndex(-MAX_SONG_BUTTONS);
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_O && (input.isKeyDown(Input.KEY_LCONTROL) || input.isKeyDown(Input.KEY_RCONTROL))) {
|
||||
if (key == KEY_O && input.isControlDown()) {
|
||||
optionsOverlay.show();
|
||||
return true;
|
||||
}
|
||||
// wait for user to finish typing
|
||||
// TODO: accept all characters (current conditions are from TextField class)
|
||||
if ((c > 31 && c < 127) || key == Input.KEY_BACK) {
|
||||
if ((c > 31 && c < 127) || key == KEY_BACK) {
|
||||
searchTimer = 0;
|
||||
searchTextField.keyPressed(key, c);
|
||||
int textLength = searchTextField.getText().length();
|
||||
if (lastSearchTextLength != textLength) {
|
||||
if (key == Input.KEY_BACK) {
|
||||
if (key == KEY_BACK) {
|
||||
if (textLength == 0)
|
||||
searchTransitionTimer = 0;
|
||||
} else if (textLength == 1)
|
||||
|
@ -1216,9 +1204,9 @@ public class SongMenu extends ComplexOpsuState {
|
|||
|
||||
// check mouse button (right click scrolls faster on songs)
|
||||
int multiplier;
|
||||
if (displayContainer.input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
|
||||
if (Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON)) {
|
||||
multiplier = 10;
|
||||
} else if (displayContainer.input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
|
||||
} else if (Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON)) {
|
||||
multiplier = 1;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1238,8 +1226,6 @@ public class SongMenu extends ComplexOpsuState {
|
|||
return true;
|
||||
}
|
||||
|
||||
Input input = displayContainer.input;
|
||||
|
||||
if (isInputBlocked()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1310,7 +1296,7 @@ public class SongMenu extends ComplexOpsuState {
|
|||
|
||||
// reset game data
|
||||
if (resetGame) {
|
||||
instanceContainer.provide(Game.class).resetGameData();
|
||||
gameState.resetGameData();
|
||||
|
||||
// destroy extra Clips
|
||||
MultiClip.destroyExtraClips();
|
||||
|
@ -1775,22 +1761,20 @@ public class SongMenu extends ComplexOpsuState {
|
|||
|
||||
Beatmap beatmap = MusicController.getBeatmap();
|
||||
if (focusNode == null || beatmap != focusNode.getSelectedBeatmap()) {
|
||||
EventBus.post(new BarNotificationEvent("Unable to load the beatmap audio."));
|
||||
BarNotifListener.EVENT.make().onBarNotif("Unable to load the beatmap audio.");
|
||||
return;
|
||||
}
|
||||
|
||||
// turn on "auto" mod if holding "ctrl" key
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_RCONTROL) || displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) {
|
||||
if (!GameMod.AUTO.isActive())
|
||||
GameMod.AUTO.toggle(true);
|
||||
if (input.isControlDown() && !GameMod.AUTO.isActive()) {
|
||||
GameMod.AUTO.toggle(true);
|
||||
}
|
||||
|
||||
SoundController.playSound(SoundEffect.MENUHIT);
|
||||
MultiClip.destroyExtraClips();
|
||||
Game gameState = instanceContainer.provide(Game.class);
|
||||
gameState.loadBeatmap(beatmap);
|
||||
gameState.setRestart(Game.Restart.NEW);
|
||||
gameState.setReplay(null);
|
||||
displayContainer.switchState(Game.class);
|
||||
displayContainer.switchState(gameState);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,20 +21,18 @@ package itdelatrisu.opsu.states;
|
|||
import itdelatrisu.opsu.GameImage;
|
||||
import itdelatrisu.opsu.audio.MusicController;
|
||||
import itdelatrisu.opsu.audio.SoundController;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapSetList;
|
||||
import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.opengl.renderer.Renderer;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
|
@ -44,18 +42,6 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class Splash extends BaseOpsuState {
|
||||
|
||||
@Inject
|
||||
private SongMenu songMenu;
|
||||
|
||||
@Inject
|
||||
private ReplayImporter replayImporter;
|
||||
|
||||
@Inject
|
||||
private OszUnpacker oszUnpacker;
|
||||
|
||||
@Inject
|
||||
private BeatmapParser beatmapParser;
|
||||
|
||||
/** Whether or not loading has completed. */
|
||||
private boolean finished;
|
||||
|
||||
|
@ -73,7 +59,7 @@ public class Splash extends BaseOpsuState {
|
|||
super.revalidate();
|
||||
|
||||
// pre-revalidate some states to reduce lag between switching
|
||||
songMenu.revalidate();
|
||||
songMenuState.revalidate();
|
||||
|
||||
if (inited) {
|
||||
return;
|
||||
|
@ -86,7 +72,7 @@ public class Splash extends BaseOpsuState {
|
|||
thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
oszUnpacker.unpackAll();
|
||||
oszunpacker.unpackAll();
|
||||
beatmapParser.parseAll();
|
||||
replayImporter.importAll();
|
||||
|
||||
|
@ -109,7 +95,7 @@ public class Splash extends BaseOpsuState {
|
|||
// initialize song list
|
||||
if (BeatmapSetList.get().size() == 0) {
|
||||
MusicController.playThemeSong(config.themeBeatmap);
|
||||
displayContainer.switchStateInstantly(MainMenu.class);
|
||||
displayContainer.switchStateInstantly(mainmenuState);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -117,9 +103,9 @@ public class Splash extends BaseOpsuState {
|
|||
if (OPTION_ENABLE_THEME_SONG.state) {
|
||||
MusicController.playThemeSong(config.themeBeatmap);
|
||||
} else {
|
||||
songMenu.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||
songMenuState.setFocus(BeatmapSetList.get().getRandomNode(), -1, true, true);
|
||||
}
|
||||
displayContainer.switchStateInstantly(MainMenu.class);
|
||||
displayContainer.switchStateInstantly(mainmenuState);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,7 +133,7 @@ public class Splash extends BaseOpsuState {
|
|||
|
||||
@Override
|
||||
public boolean keyPressed(int key, char c) {
|
||||
if (key != Input.KEY_ESCAPE) {
|
||||
if (key != Keyboard.KEY_ESCAPE) {
|
||||
return false;
|
||||
}
|
||||
if (++escapeCount >= 3) {
|
||||
|
|
|
@ -49,6 +49,11 @@ public class Colors {
|
|||
BLACK_BG_NORMAL = new Color(0, 0, 0, 0.25f),
|
||||
BLACK_BG_HOVER = new Color(0, 0, 0, 0.5f),
|
||||
BLACK_BG_FOCUS = new Color(0, 0, 0, 0.75f),
|
||||
BUB_GREEN = new Color(98, 131, 59),
|
||||
BUB_WHITE = new Color(220, 220, 220),
|
||||
BUB_PURPLE = new Color(94, 46, 149),
|
||||
BUB_RED = new Color(141, 49, 16),
|
||||
BUB_ORANGE = new Color(138, 72, 51),
|
||||
GHOST_LOGO = new Color(1.0f, 1.0f, 1.0f, 0.25f);
|
||||
|
||||
// This class should not be instantiated.
|
||||
|
|
|
@ -22,6 +22,7 @@ import itdelatrisu.opsu.GameImage;
|
|||
import itdelatrisu.opsu.ui.animations.AnimatedValue;
|
||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Font;
|
||||
import org.newdawn.slick.Graphics;
|
||||
|
@ -82,7 +83,7 @@ public class DropdownMenu<E> extends Component {
|
|||
|
||||
@Override
|
||||
public void keyPressed(int key, char c) {
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
this.expanded = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.newdawn.slick.font.effects.ColorEffect;
|
|||
import org.newdawn.slick.font.effects.Effect;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.core.Constants;
|
||||
|
||||
/**
|
||||
* Fonts used for drawing.
|
||||
|
@ -54,9 +54,9 @@ public class Fonts {
|
|||
* @throws FontFormatException if any font stream data does not contain the required font tables
|
||||
* @throws IOException if a font stream cannot be completely read
|
||||
*/
|
||||
public static void init(Configuration config) throws SlickException, FontFormatException, IOException {
|
||||
public static void init() throws SlickException, FontFormatException, IOException {
|
||||
float fontBase = 12f * GameImage.getUIscale();
|
||||
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, ResourceLoader.getResourceAsStream(config.FONT_NAME));
|
||||
Font javaFont = Font.createFont(Font.TRUETYPE_FONT, ResourceLoader.getResourceAsStream(Constants.FONT_NAME));
|
||||
Font font = javaFont.deriveFont(Font.PLAIN, (int) (fontBase * 4 / 3));
|
||||
DEFAULT = new UnicodeFont(font);
|
||||
BOLD = new UnicodeFont(font.deriveFont(Font.BOLD));
|
||||
|
|
|
@ -47,7 +47,7 @@ public class KineticScrolling {
|
|||
private float totalDelta;
|
||||
|
||||
/** The maximum and minimum value the position can reach. */
|
||||
private float max = Float.MAX_VALUE, min = -Float.MAX_VALUE;
|
||||
public float max = Float.MAX_VALUE, min = -Float.MAX_VALUE;
|
||||
|
||||
/** Whether the mouse is currently pressed or not. */
|
||||
private boolean pressed = false;
|
||||
|
|
10
src/org/newdawn/slick/InputListener.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package org.newdawn.slick;
|
||||
|
||||
/**
|
||||
* A listener that will be notified of keyboard and mouse events
|
||||
* Edited for opsu!
|
||||
*
|
||||
* @author kevin
|
||||
*/
|
||||
public interface InputListener extends MouseListener, KeyListener {
|
||||
}
|
27
src/org/newdawn/slick/KeyListener.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package org.newdawn.slick;
|
||||
|
||||
/**
|
||||
* Describes classes capable of responding to key presses
|
||||
* Edited for opsu!
|
||||
*
|
||||
* @author kevin
|
||||
*/
|
||||
public interface KeyListener {
|
||||
|
||||
/**
|
||||
* Notification that a key was pressed
|
||||
*
|
||||
* @param key The key code that was pressed (@see org.newdawn.slick.Input)
|
||||
* @param c The character of the key that was pressed
|
||||
*/
|
||||
boolean keyPressed(int key, char c);
|
||||
|
||||
/**
|
||||
* Notification that a key was released
|
||||
*
|
||||
* @param key The key code that was released (@see org.newdawn.slick.Input)
|
||||
* @param c The character of the key that was released
|
||||
*/
|
||||
boolean keyReleased(int key, char c);
|
||||
|
||||
}
|
46
src/org/newdawn/slick/MouseListener.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package org.newdawn.slick;
|
||||
|
||||
/**
|
||||
* Description of classes that respond to mouse related input events
|
||||
* Edited for opsu!
|
||||
*
|
||||
* @author kevin
|
||||
*/
|
||||
public interface MouseListener {
|
||||
|
||||
/**
|
||||
* Notification that the mouse wheel position was updated
|
||||
*
|
||||
* @param delta The amount of the wheel has moved
|
||||
*/
|
||||
boolean mouseWheelMoved(int delta);
|
||||
|
||||
/**
|
||||
* Notification that a mouse button was pressed
|
||||
*
|
||||
* @param button The index of the button (starting at 0)
|
||||
* @param x The x position of the mouse when the button was pressed
|
||||
* @param y The y position of the mouse when the button was pressed
|
||||
*/
|
||||
boolean mousePressed(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* Notification that a mouse button was released
|
||||
*
|
||||
* @param button The index of the button (starting at 0)
|
||||
* @param x The x position of the mouse when the button was released
|
||||
* @param y The y position of the mouse when the button was released
|
||||
*/
|
||||
boolean mouseReleased(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* Notification that mouse cursor was dragged
|
||||
*
|
||||
* @param oldx The old x position of the mouse
|
||||
* @param oldy The old y position of the mouse
|
||||
* @param newx The new x position of the mouse
|
||||
* @param newy The new y position of the mouse
|
||||
*/
|
||||
boolean mouseDragged(int oldx, int oldy, int newx, int newy);
|
||||
|
||||
}
|
|
@ -32,12 +32,13 @@ import org.lwjgl.Sys;
|
|||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Font;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.geom.Rectangle;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.components.ActionListener;
|
||||
import yugecin.opsudance.core.components.Component;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* A single text field supporting text entry
|
||||
*
|
||||
|
@ -48,8 +49,6 @@ public class TextField extends Component {
|
|||
private static final int INITIAL_KEY_REPEAT_INTERVAL = 400;
|
||||
private static final int KEY_REPEAT_INTERVAL = 50;
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
|
||||
private String value = "";
|
||||
private Font font;
|
||||
private int maxCharacter = 10000;
|
||||
|
@ -65,8 +64,7 @@ public class TextField extends Component {
|
|||
|
||||
private ActionListener listener;
|
||||
|
||||
public TextField(DisplayContainer displayContainer, Font font, int x, int y, int width, int height) {
|
||||
this.displayContainer = displayContainer;
|
||||
public TextField(Font font, int x, int y, int width, int height) {
|
||||
this.font = font;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
@ -97,7 +95,7 @@ public class TextField extends Component {
|
|||
|
||||
public void render(Graphics g) {
|
||||
if (lastKey != -1) {
|
||||
if (displayContainer.input.isKeyDown(lastKey)) {
|
||||
if (isKeyDown(lastKey)) {
|
||||
if (repeatTimer < System.currentTimeMillis()) {
|
||||
repeatTimer = System.currentTimeMillis() + KEY_REPEAT_INTERVAL;
|
||||
keyPressed(lastKey, lastChar);
|
||||
|
@ -170,10 +168,8 @@ public class TextField extends Component {
|
|||
}
|
||||
|
||||
public void keyPressed(int key, char c) {
|
||||
if (key != -1)
|
||||
{
|
||||
if ((key == Input.KEY_V) &&
|
||||
((displayContainer.input.isKeyDown(Input.KEY_LCONTROL)) || (displayContainer.input.isKeyDown(Input.KEY_RCONTROL)))) {
|
||||
if (key != -1) {
|
||||
if (key == KEY_V && input.isControlDown()) {
|
||||
String text = Sys.getClipboard();
|
||||
if (text != null) {
|
||||
doPaste(text);
|
||||
|
@ -190,7 +186,7 @@ public class TextField extends Component {
|
|||
}
|
||||
lastChar = c;
|
||||
|
||||
if (key == Input.KEY_LEFT) { /*
|
||||
if (key == KEY_LEFT) { /*
|
||||
if (cursorPos > 0) {
|
||||
cursorPos--;
|
||||
}
|
||||
|
@ -198,7 +194,7 @@ public class TextField extends Component {
|
|||
if (consume) {
|
||||
container.getInput().consumeEvent();
|
||||
}
|
||||
*/ } else if (key == Input.KEY_RIGHT) { /*
|
||||
*/ } else if (key == KEY_RIGHT) { /*
|
||||
if (cursorPos < value.length()) {
|
||||
cursorPos++;
|
||||
}
|
||||
|
@ -206,9 +202,9 @@ public class TextField extends Component {
|
|||
if (consume) {
|
||||
container.getInput().consumeEvent();
|
||||
}
|
||||
*/ } else if (key == Input.KEY_BACK) {
|
||||
*/ } else if (key == KEY_BACK) {
|
||||
if ((cursorPos > 0) && (value.length() > 0)) {
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_LCONTROL) || displayContainer.input.isKeyDown(Input.KEY_RCONTROL)) {
|
||||
if (input.isControlDown()) {
|
||||
int sp = 0;
|
||||
boolean startSpace = Character.isWhitespace(value.charAt(cursorPos - 1));
|
||||
boolean charSeen = false;
|
||||
|
@ -240,7 +236,7 @@ public class TextField extends Component {
|
|||
cursorPos--;
|
||||
}
|
||||
}
|
||||
} else if (key == Input.KEY_DELETE) {
|
||||
} else if (key == KEY_DELETE) {
|
||||
if (value.length() > cursorPos) {
|
||||
value = value.substring(0,cursorPos) + value.substring(cursorPos+1);
|
||||
}
|
||||
|
@ -252,7 +248,7 @@ public class TextField extends Component {
|
|||
value = value.substring(0, cursorPos) + c;
|
||||
}
|
||||
cursorPos++;
|
||||
} else if (key == Input.KEY_RETURN) {
|
||||
} else if (key == KEY_RETURN) {
|
||||
if (listener != null) {
|
||||
listener.onAction();
|
||||
}
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
package org.newdawn.slick.state.transition;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.state.GameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
|
||||
/**
|
||||
* A transition to fade out to a given colour after a delay.
|
||||
*
|
||||
* @author kevin (base)
|
||||
*/
|
||||
public class DelayedFadeOutTransition implements Transition {
|
||||
/** The color to fade to */
|
||||
private final Color color;
|
||||
/** The time it takes the fade to happen */
|
||||
private final int fadeTime;
|
||||
/** The time it takes before the fade starts */
|
||||
private final int delay;
|
||||
/** The elapsed time */
|
||||
private int elapsedTime = 0;
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition.
|
||||
*/
|
||||
public DelayedFadeOutTransition() { this(Color.black, 500, 0); }
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
*/
|
||||
public DelayedFadeOutTransition(Color color) { this(color, 500, 0); }
|
||||
|
||||
/**
|
||||
* Create a new delayed fade out transition
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
* @param delay The time before the fade starts (must be less than {@code fadeTime})
|
||||
* @throws IllegalArgumentException if {@code delay} is greater than {@code fadeTime}
|
||||
*/
|
||||
public DelayedFadeOutTransition(Color color, int fadeTime, int delay) {
|
||||
if (delay > fadeTime)
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
this.color = new Color(color);
|
||||
this.color.a = 0;
|
||||
this.fadeTime = fadeTime;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() { return (color.a >= 1); }
|
||||
|
||||
@Override
|
||||
public void postRender(StateBasedGame game, GameContainer container, Graphics g) {
|
||||
Color old = g.getColor();
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, container.getWidth() * 2, container.getHeight() * 2);
|
||||
g.setColor(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(StateBasedGame game, GameContainer container, int delta) {
|
||||
if (elapsedTime < delay) {
|
||||
elapsedTime += delta;
|
||||
return;
|
||||
}
|
||||
|
||||
color.a += delta * (1.0f / (fadeTime - delay));
|
||||
if (color.a > 1)
|
||||
color.a = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRender(StateBasedGame game, GameContainer container, Graphics g) {}
|
||||
|
||||
@Override
|
||||
public void init(GameState firstState, GameState secondState) {}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
package org.newdawn.slick.state.transition;
|
||||
|
||||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.GameContainer;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.state.GameState;
|
||||
import org.newdawn.slick.state.StateBasedGame;
|
||||
|
||||
/**
|
||||
* A transition to fade out to a given colour using an easing function.
|
||||
*
|
||||
* @author kevin (base)
|
||||
*/
|
||||
public class EasedFadeOutTransition implements Transition {
|
||||
/** The color to fade to */
|
||||
private final Color color;
|
||||
/** The time it takes the fade to happen */
|
||||
private final int fadeTime;
|
||||
/** The easing function */
|
||||
private final AnimationEquation eq;
|
||||
/** The transition progress */
|
||||
private float t = 0f;
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*/
|
||||
public EasedFadeOutTransition() { this(Color.black, 500, AnimationEquation.OUT_QUART); }
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
*/
|
||||
public EasedFadeOutTransition(Color color) { this(color, 500, AnimationEquation.OUT_QUART); }
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
*/
|
||||
public EasedFadeOutTransition(Color color, int fadeTime) { this(color, fadeTime, AnimationEquation.OUT_QUART); }
|
||||
|
||||
/**
|
||||
* Create a new eased fade out transition.
|
||||
*
|
||||
* @param color The color we're going to fade out to
|
||||
* @param fadeTime The time it takes the fade to occur
|
||||
* @param eq The easing function to use
|
||||
*/
|
||||
public EasedFadeOutTransition(Color color, int fadeTime, AnimationEquation eq) {
|
||||
this.color = new Color(color);
|
||||
this.color.a = 0;
|
||||
this.fadeTime = fadeTime;
|
||||
this.eq = eq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete() { return (color.a >= 1); }
|
||||
|
||||
@Override
|
||||
public void postRender(StateBasedGame game, GameContainer container, Graphics g) {
|
||||
Color old = g.getColor();
|
||||
g.setColor(color);
|
||||
g.fillRect(0, 0, container.getWidth() * 2, container.getHeight() * 2);
|
||||
g.setColor(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(StateBasedGame game, GameContainer container, int delta) {
|
||||
t += delta * (1.0f / fadeTime);
|
||||
float alpha = t > 1f ? 1f : eq.calc(t);
|
||||
color.a = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRender(StateBasedGame game, GameContainer container, Graphics g) {}
|
||||
|
||||
@Override
|
||||
public void init(GameState firstState, GameState secondState) {}
|
||||
}
|
|
@ -40,6 +40,7 @@ import yugecin.opsudance.spinners.*;
|
|||
|
||||
import java.awt.*;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class Dancer {
|
||||
|
@ -194,12 +195,12 @@ public class Dancer {
|
|||
}
|
||||
isCurrentLazySlider = false;
|
||||
// detect lazy sliders, should work pretty good
|
||||
if (c.isSlider() && OPTION_DANCE_LAZY_SLIDERS.state && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||
if (c.isSlider() && OPTION_DANCE_LAZY_SLIDERS.state && Utils.distance(c.start.x, c.start.y, c.end.x, c.end.y) <= gameObjectRenderer.circleDiameter * 0.8f) {
|
||||
Slider s = (Slider) c;
|
||||
Vec2f mid = s.getCurve().pointAt(1f);
|
||||
if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||
if (s.getRepeats() == 1 || Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= gameObjectRenderer.circleDiameter * 0.8f) {
|
||||
mid = s.getCurve().pointAt(0.5f);
|
||||
if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= GameObjectRenderer.instance.getCircleDiameter() * 0.8f) {
|
||||
if (Utils.distance(c.start.x, c.start.y, mid.x, mid.y) <= gameObjectRenderer.circleDiameter * 0.8f) {
|
||||
isCurrentLazySlider = true;
|
||||
}
|
||||
}
|
||||
|
@ -251,8 +252,8 @@ public class Dancer {
|
|||
}
|
||||
}
|
||||
Pippi.dance(time, c, isCurrentLazySlider);
|
||||
x = Utils.clamp(x, 10, width - 10);
|
||||
y = Utils.clamp(y, 10, height - 10);
|
||||
x = Utils.clamp(x, 10, displayContainer.width - 10);
|
||||
y = Utils.clamp(y, 10, displayContainer.height - 10);
|
||||
}
|
||||
|
||||
private void createNewMover() {
|
||||
|
|
|
@ -21,22 +21,16 @@ import itdelatrisu.opsu.Utils;
|
|||
import itdelatrisu.opsu.beatmap.BeatmapWatchService;
|
||||
import itdelatrisu.opsu.db.DBController;
|
||||
import itdelatrisu.opsu.downloads.DownloadList;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.states.Splash;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.options.OptionsService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import static yugecin.opsudance.core.errorhandling.ErrorHandler.*;
|
||||
import static yugecin.opsudance.core.Entrypoint.sout;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/*
|
||||
|
@ -44,30 +38,13 @@ import static yugecin.opsudance.options.Options.*;
|
|||
*/
|
||||
public class OpsuDance {
|
||||
|
||||
@Inject
|
||||
private DisplayContainer container;
|
||||
|
||||
@Inject
|
||||
private OptionsService optionsService;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
|
||||
@Inject
|
||||
private Updater updater;
|
||||
|
||||
private ServerSocket singleInstanceSocket;
|
||||
|
||||
@Inject
|
||||
public OpsuDance() {
|
||||
}
|
||||
|
||||
public void start(String[] args) {
|
||||
try {
|
||||
sout("initialized");
|
||||
|
||||
checkRunningDirectory();
|
||||
optionsService.loadOptions();
|
||||
optionservice.loadOptions();
|
||||
ensureSingleInstance();
|
||||
sout("prechecks done and options parsed");
|
||||
|
||||
|
@ -75,15 +52,15 @@ public class OpsuDance {
|
|||
initUpdater(args);
|
||||
sout("database & updater initialized");
|
||||
|
||||
container.init(Splash.class);
|
||||
displayContainer.init(splashState);
|
||||
} catch (Exception e) {
|
||||
errorAndExit("startup failure", e);
|
||||
}
|
||||
|
||||
while (rungame());
|
||||
container.teardownAL();
|
||||
displayContainer.teardownAL();
|
||||
|
||||
optionsService.saveOptions();
|
||||
optionservice.saveOptions();
|
||||
closeSingleInstanceSocket();
|
||||
DBController.closeConnections();
|
||||
DownloadList.get().cancelAllDownloads();
|
||||
|
@ -95,26 +72,26 @@ public class OpsuDance {
|
|||
|
||||
private boolean rungame() {
|
||||
try {
|
||||
container.setup();
|
||||
container.resume();
|
||||
displayContainer.setup();
|
||||
displayContainer.resume();
|
||||
} catch (Exception e) {
|
||||
ErrorHandler.error("could not initialize GL", e).allowTerminate().preventContinue().show();
|
||||
explode("could not initialize GL", e, ALLOW_TERMINATE | PREVENT_CONTINUE);
|
||||
return false;
|
||||
}
|
||||
Exception caughtException = null;
|
||||
try {
|
||||
container.run();
|
||||
displayContainer.run();
|
||||
} catch (Exception e) {
|
||||
caughtException = e;
|
||||
}
|
||||
container.teardown();
|
||||
container.pause();
|
||||
return caughtException != null && ErrorHandler.error("update/render error", caughtException).allowTerminate().show().shouldIgnoreAndContinue();
|
||||
displayContainer.teardown();
|
||||
displayContainer.pause();
|
||||
return caughtException != null && explode("update/render error", caughtException, ALLOW_TERMINATE);
|
||||
}
|
||||
|
||||
private void initDatabase() {
|
||||
try {
|
||||
DBController.init(config);
|
||||
DBController.init();
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
errorAndExit("Could not initialize database.", e);
|
||||
}
|
||||
|
@ -142,20 +119,6 @@ public class OpsuDance {
|
|||
}.start();
|
||||
}
|
||||
|
||||
private void checkRunningDirectory() {
|
||||
if (!Utils.isJarRunning()) {
|
||||
return;
|
||||
}
|
||||
File runningDir = Utils.getRunningDirectory();
|
||||
if (runningDir == null) {
|
||||
return;
|
||||
}
|
||||
if (runningDir.getAbsolutePath().indexOf('!') == -1) {
|
||||
return;
|
||||
}
|
||||
errorAndExit("Cannot run from a path that contains a '!'. Please move or rename the jar and try again.");
|
||||
}
|
||||
|
||||
private void ensureSingleInstance() {
|
||||
if (OPTION_NOSINGLEINSTANCE.state) {
|
||||
return;
|
||||
|
@ -183,13 +146,8 @@ public class OpsuDance {
|
|||
}
|
||||
}
|
||||
|
||||
private void errorAndExit(String errstr) {
|
||||
ErrorHandler.error(errstr, new Throwable()).allowTerminate().preventContinue().show();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private void errorAndExit(String errstr, Throwable cause) {
|
||||
ErrorHandler.error(errstr, cause).preventContinue().show();
|
||||
explode(errstr, cause, PREVENT_CONTINUE);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ package yugecin.opsudance;
|
|||
|
||||
import itdelatrisu.opsu.objects.GameObject;
|
||||
import itdelatrisu.opsu.objects.Slider;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class Pippi {
|
||||
|
||||
|
@ -38,14 +38,14 @@ public class Pippi {
|
|||
|
||||
public static void setRadiusPercent(int radiusPercent) {
|
||||
Pippi.radiusPercent = radiusPercent;
|
||||
pippiminrad = pippirad = (GameObjectRenderer.instance.getCircleDiameter() / 2d - 10d) * radiusPercent / 100d;
|
||||
pippiminrad = pippirad = (gameObjectRenderer.circleDiameter / 2d - 10d) * radiusPercent / 100d;
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
angle = 0;
|
||||
currentdelta = 0;
|
||||
setRadiusPercent(radiusPercent);
|
||||
pippimaxrad = GameObjectRenderer.instance.getCircleDiameter() - 10d;
|
||||
pippimaxrad = gameObjectRenderer.circleDiameter - 10d;
|
||||
}
|
||||
|
||||
public static void dance(int time, GameObject c, boolean isCurrentLazySlider) {
|
||||
|
@ -92,7 +92,7 @@ public class Pippi {
|
|||
}
|
||||
|
||||
public static boolean shouldPreventWobblyStream(double distance) {
|
||||
return OPTION_PIPPI_ENABLE.state && distance < GameObjectRenderer.instance.getCircleDiameter() * 0.93f && OPTION_PIPPI_PREVENT_WOBBLY_STREAMS.state;
|
||||
return OPTION_PIPPI_ENABLE.state && distance < gameObjectRenderer.circleDiameter * 0.93f && OPTION_PIPPI_PREVENT_WOBBLY_STREAMS.state;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance;
|
||||
|
||||
import itdelatrisu.opsu.NativeLoader;
|
||||
import org.newdawn.slick.util.FileSystemLocation;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class PreStartupInitializer {
|
||||
|
||||
private final Configuration config;
|
||||
|
||||
@Inject
|
||||
public PreStartupInitializer(Configuration config) {
|
||||
this.config = config;
|
||||
loadNatives();
|
||||
setResourcePath();
|
||||
}
|
||||
|
||||
private void loadNatives() {
|
||||
File nativeDir = loadNativesUsingOptionsPath();
|
||||
|
||||
System.setProperty("org.lwjgl.librarypath", nativeDir.getAbsolutePath());
|
||||
System.setProperty("java.library.path", nativeDir.getAbsolutePath());
|
||||
|
||||
try {
|
||||
// Workaround for "java.library.path" property being read-only.
|
||||
// http://stackoverflow.com/a/24988095
|
||||
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
|
||||
fieldSysPath.setAccessible(true);
|
||||
fieldSysPath.set(null, null);
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
Log.warn("Failed to set 'sys_paths' field.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private File loadNativesUsingOptionsPath() {
|
||||
File nativeDir = config.NATIVE_DIR;
|
||||
try {
|
||||
new NativeLoader(nativeDir).loadNatives();
|
||||
} catch (IOException e) {
|
||||
Log.error("Error loading natives.", e);
|
||||
}
|
||||
return nativeDir;
|
||||
}
|
||||
|
||||
private void setResourcePath() {
|
||||
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
|
||||
}
|
||||
|
||||
}
|
|
@ -15,28 +15,18 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import java.net.URI;
|
||||
|
||||
public abstract class FadeTransitionState extends TransitionState {
|
||||
public class Constants {
|
||||
|
||||
private final Color black;
|
||||
|
||||
public FadeTransitionState() {
|
||||
super();
|
||||
black = new Color(Color.black);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics g) {
|
||||
applicableState.render(g);
|
||||
black.a = getMaskAlphaLevel((float) transitionTime / transitionTargetTime);
|
||||
g.setColor(black);
|
||||
g.fillRect(0, 0, displayContainer.width, displayContainer.height);
|
||||
}
|
||||
|
||||
protected abstract float getMaskAlphaLevel(float fadeProgress);
|
||||
public static final String PROJECT_NAME = "opsu!dance";
|
||||
public static final String FONT_NAME = "DroidSansFallback.ttf";
|
||||
public static final String VERSION_FILE = "version";
|
||||
public static final URI REPOSITORY_URI = URI.create("https://github.com/itdelatrisu/opsu");
|
||||
public static final URI DANCE_REPOSITORY_URI = URI.create("https://github.com/yugecin/opsu-dance");
|
||||
public static final String ISSUES_URL = "https://github.com/yugecin/opsu-dance/issues/new?title=%s&body=%s";
|
||||
public static final String VERSION_REMOTE = "https://raw.githubusercontent.com/yugecin/opsu-dance/master/version";
|
||||
|
||||
}
|
|
@ -26,10 +26,12 @@ import itdelatrisu.opsu.downloads.DownloadNode;
|
|||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.render.CurveRenderState;
|
||||
import itdelatrisu.opsu.replay.PlaybackSpeed;
|
||||
import itdelatrisu.opsu.ui.Colors;
|
||||
import itdelatrisu.opsu.ui.Cursor;
|
||||
import itdelatrisu.opsu.ui.Fonts;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.DisplayMode;
|
||||
|
@ -39,58 +41,38 @@ import org.newdawn.slick.opengl.InternalTextureLoader;
|
|||
import org.newdawn.slick.opengl.renderer.Renderer;
|
||||
import org.newdawn.slick.opengl.renderer.SGL;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.core.inject.InstanceContainer;
|
||||
import yugecin.opsudance.core.state.OpsuState;
|
||||
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubNotifState;
|
||||
import yugecin.opsudance.core.state.specialstates.FpsRenderState;
|
||||
import yugecin.opsudance.core.state.transitions.*;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
import yugecin.opsudance.events.SkinChangedListener;
|
||||
import yugecin.opsudance.utils.GLHelper;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import static yugecin.opsudance.core.Entrypoint.sout;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
/**
|
||||
* based on org.newdawn.slick.AppGameContainer
|
||||
*/
|
||||
public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListener {
|
||||
|
||||
@Inject
|
||||
private SkinService skinService;
|
||||
|
||||
@Inject
|
||||
private Configuration config;
|
||||
public class DisplayContainer implements ErrorDumpable, ResolutionChangedListener, SkinChangedListener {
|
||||
|
||||
private static SGL GL = Renderer.get();
|
||||
|
||||
private final InstanceContainer instanceContainer;
|
||||
|
||||
private FpsRenderState fpsState;
|
||||
private BarNotificationState barNotifState;
|
||||
private BubbleNotificationState bubNotifState;
|
||||
|
||||
private TransitionState outTransitionState;
|
||||
private TransitionState inTransitionState;
|
||||
|
||||
private final TransitionFinishedListener outTransitionListener;
|
||||
private final TransitionFinishedListener inTransitionListener;
|
||||
private BubNotifState bubNotifState;
|
||||
|
||||
private OpsuState state;
|
||||
|
||||
public final DisplayMode nativeDisplayMode;
|
||||
|
||||
private Graphics graphics;
|
||||
public Input input;
|
||||
|
||||
public int width;
|
||||
public int height;
|
||||
|
@ -123,38 +105,52 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
public final Cursor cursor;
|
||||
public boolean drawCursor;
|
||||
|
||||
@Inject
|
||||
public DisplayContainer(InstanceContainer instanceContainer) {
|
||||
this.instanceContainer = instanceContainer;
|
||||
class Transition {
|
||||
int in;
|
||||
int out;
|
||||
int total;
|
||||
int progress = -1;
|
||||
OpsuState nextstate;
|
||||
Color OVERLAY = new Color(Color.black);
|
||||
|
||||
public void update() {
|
||||
if (progress == -1) {
|
||||
return;
|
||||
}
|
||||
progress += delta;
|
||||
if (progress > out && nextstate != null) {
|
||||
switchStateInstantly(nextstate);
|
||||
nextstate = null;
|
||||
}
|
||||
if (progress > total) {
|
||||
progress = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void render(Graphics graphics) {
|
||||
if (progress == -1) {
|
||||
return;
|
||||
}
|
||||
int relprogress = progress;
|
||||
int reltotal = out;
|
||||
if (progress > out) {
|
||||
reltotal = in;
|
||||
relprogress = total - progress;
|
||||
}
|
||||
OVERLAY.a = (float) relprogress / reltotal;
|
||||
graphics.setColor(OVERLAY);
|
||||
graphics.fillRect(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
private final Transition transition = new Transition();
|
||||
|
||||
public DisplayContainer() {
|
||||
this.cursor = new Cursor();
|
||||
drawCursor = true;
|
||||
|
||||
outTransitionListener = new TransitionFinishedListener() {
|
||||
@Override
|
||||
public void onFinish() {
|
||||
state.leave();
|
||||
outTransitionState.getApplicableState().leave();
|
||||
state = inTransitionState;
|
||||
state.enter();
|
||||
inTransitionState.getApplicableState().enter();
|
||||
}
|
||||
};
|
||||
|
||||
inTransitionListener = new TransitionFinishedListener() {
|
||||
@Override
|
||||
public void onFinish() {
|
||||
state.leave();
|
||||
state = inTransitionState.getApplicableState();
|
||||
}
|
||||
};
|
||||
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
destroyImages();
|
||||
reinit();
|
||||
}
|
||||
});
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
SkinChangedListener.EVENT.addListener(this);
|
||||
|
||||
this.nativeDisplayMode = Display.getDisplayMode();
|
||||
targetBackgroundRenderInterval = 41; // ~24 fps
|
||||
|
@ -163,13 +159,25 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
renderDelta = 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
destroyImages();
|
||||
reinit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkinChanged(String stringName) {
|
||||
destroyImages();
|
||||
reinit();
|
||||
}
|
||||
|
||||
private void reinit() {
|
||||
// this used to be in Utils.init
|
||||
// TODO find a better place for this?
|
||||
setFPS(targetFPS[targetFPSIndex]);
|
||||
MusicController.setMusicVolume(OPTION_MUSIC_VOLUME.val / 100f * OPTION_MASTER_VOLUME.val / 100f);
|
||||
|
||||
skinService.loadSkin();
|
||||
skinservice.loadSkin();
|
||||
|
||||
// initialize game images
|
||||
for (GameImage img : GameImage.values()) {
|
||||
|
@ -196,16 +204,16 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
targetRenderInterval = 1000 / targetRendersPerSecond;
|
||||
}
|
||||
|
||||
public void init(Class<? extends OpsuState> startingState) {
|
||||
public void init(OpsuState startingState) {
|
||||
setUPS(OPTION_TARGET_UPS.val);
|
||||
setFPS(targetFPS[targetFPSIndex]);
|
||||
|
||||
state = instanceContainer.provide(startingState);
|
||||
state.enter();
|
||||
fpsState = new FpsRenderState();
|
||||
bubNotifState = new BubNotifState();
|
||||
barNotifState = new BarNotificationState();
|
||||
|
||||
fpsState = instanceContainer.provide(FpsRenderState.class);
|
||||
bubNotifState = instanceContainer.provide(BubbleNotificationState.class);
|
||||
barNotifState = instanceContainer.provide(BarNotificationState.class);
|
||||
state = startingState;
|
||||
state.enter();
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,6 +228,7 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
mouseX = input.getMouseX();
|
||||
mouseY = input.getMouseY();
|
||||
|
||||
transition.update();
|
||||
fpsState.update();
|
||||
|
||||
state.update();
|
||||
|
@ -254,13 +263,17 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
|
||||
cursor.updateAngle(renderDelta);
|
||||
if (drawCursor) {
|
||||
cursor.draw(input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON) || input.isMouseButtonDown(Input.MOUSE_RIGHT_BUTTON));
|
||||
cursor.draw(Mouse.isButtonDown(Input.MOUSE_LEFT_BUTTON) ||
|
||||
Mouse.isButtonDown(Input.MOUSE_RIGHT_BUTTON));
|
||||
}
|
||||
UI.drawTooltip(graphics);
|
||||
|
||||
transition.render(graphics);
|
||||
|
||||
timeSinceLastRender = 0;
|
||||
|
||||
Display.update(false);
|
||||
GL11.glFlush();
|
||||
}
|
||||
|
||||
Display.processMessages();
|
||||
|
@ -270,8 +283,8 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
|
||||
public void setup() throws Exception {
|
||||
width = height = -1;
|
||||
Input.disableControllers();
|
||||
Display.setTitle("opsu!dance");
|
||||
setupResolutionOptionlist(nativeDisplayMode.getWidth(), nativeDisplayMode.getHeight());
|
||||
updateDisplayMode(OPTION_SCREEN_RESOLUTION.getValueString());
|
||||
Display.create();
|
||||
GLHelper.setIcons(new String[] { "icon16.png", "icon32.png" });
|
||||
|
@ -281,6 +294,19 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
GLHelper.hideNativeCursor();
|
||||
}
|
||||
|
||||
// TODO: move this elsewhere
|
||||
private void setupResolutionOptionlist(int width, int height) {
|
||||
final Object[] resolutions = OPTION_SCREEN_RESOLUTION.getListItems();
|
||||
final String nativeRes = width + "x" + height;
|
||||
resolutions[0] = nativeRes;
|
||||
for (int i = 0; i < resolutions.length; i++) {
|
||||
if (nativeRes.equals(resolutions[i].toString())) {
|
||||
resolutions[i] = resolutions[i] + " (borderless)";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void teardown() {
|
||||
destroyImages();
|
||||
CurveRenderState.shutdown();
|
||||
|
@ -316,13 +342,13 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
return true;
|
||||
}
|
||||
if (DownloadList.get().hasActiveDownloads()) {
|
||||
EventBus.post(new BubbleNotificationEvent(DownloadList.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
||||
BubNotifListener.EVENT.make().onBubNotif(DownloadList.EXIT_CONFIRMATION, Colors.BUB_RED);
|
||||
exitRequested = false;
|
||||
exitconfirmation = System.currentTimeMillis();
|
||||
return false;
|
||||
}
|
||||
if (Updater.get().getStatus() == Updater.Status.UPDATE_DOWNLOADING) {
|
||||
EventBus.post(new BubbleNotificationEvent(Updater.EXIT_CONFIRMATION, BubbleNotificationEvent.COMMONCOLOR_PURPLE));
|
||||
if (updater.getStatus() == Updater.Status.UPDATE_DOWNLOADING) {
|
||||
BubNotifListener.EVENT.make().onBubNotif(Updater.EXIT_CONFIRMATION, Colors.BUB_PURPLE);
|
||||
exitRequested = false;
|
||||
exitconfirmation = System.currentTimeMillis();
|
||||
return false;
|
||||
|
@ -334,6 +360,11 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
int screenWidth = nativeDisplayMode.getWidth();
|
||||
int screenHeight = nativeDisplayMode.getHeight();
|
||||
|
||||
int eos = resolutionString.indexOf(' ');
|
||||
if (eos > -1) {
|
||||
resolutionString = resolutionString.substring(0, eos);
|
||||
}
|
||||
|
||||
int width = screenWidth;
|
||||
int height = screenHeight;
|
||||
if (resolutionString.matches("^[0-9]+x[0-9]+$")) {
|
||||
|
@ -348,18 +379,17 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
height = 600;
|
||||
}
|
||||
|
||||
if (!OPTION_FULLSCREEN.state) {
|
||||
boolean borderless = (screenWidth == width && screenHeight == height);
|
||||
System.setProperty("org.lwjgl.opengl.Window.undecorated", Boolean.toString(borderless));
|
||||
}
|
||||
|
||||
try {
|
||||
setDisplayMode(width, height, OPTION_FULLSCREEN.state);
|
||||
} catch (Exception e) {
|
||||
EventBus.post(new BubbleNotificationEvent("Failed to change resolution", BubbleNotificationEvent.COMMONCOLOR_RED));
|
||||
BubNotifListener.EVENT.make().onBubNotif("Failed to change resolution", Colors.BUB_RED);
|
||||
Log.error("Failed to set display mode.", e);
|
||||
}
|
||||
|
||||
if (OPTION_FULLSCREEN.state) {
|
||||
// set borderless window if dimensions match screen size
|
||||
boolean borderless = (screenWidth == width && screenHeight == height);
|
||||
System.setProperty("org.lwjgl.opengl.Window.undecorated", Boolean.toString(borderless));
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisplayMode(int width, int height, boolean fullscreen) throws Exception {
|
||||
|
@ -377,8 +407,9 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
displayMode = new DisplayMode(width, height);
|
||||
if (fullscreen) {
|
||||
fullscreen = false;
|
||||
Log.warn("could not find fullscreen displaymode for " + width + "x" + height);
|
||||
EventBus.post(new BubbleNotificationEvent("Fullscreen mode is not supported for " + width + "x" + height, BubbleNotificationEvent.COLOR_ORANGE));
|
||||
String msg = String.format("Fullscreen mode is not supported for %sx%s", width, height);
|
||||
Log.warn(msg);
|
||||
BubNotifListener.EVENT.make().onBubNotif(msg, Colors.BUB_ORANGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,17 +435,20 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
graphics = new Graphics(width, height);
|
||||
graphics.setAntiAlias(false);
|
||||
|
||||
input = new Input(height);
|
||||
input.enableKeyRepeat();
|
||||
input.addKeyListener(this);
|
||||
input.addMouseListener(this);
|
||||
if (input == null) {
|
||||
input = new Input(height);
|
||||
input.enableKeyRepeat();
|
||||
input.addListener(new GlobalInputListener());
|
||||
input.addMouseListener(bubNotifState);
|
||||
}
|
||||
input.addListener(state);
|
||||
|
||||
sout("GL ready");
|
||||
|
||||
GameImage.init(width, height);
|
||||
Fonts.init(config);
|
||||
Fonts.init();
|
||||
|
||||
EventBus.post(new ResolutionOrSkinChangedEvent(null, width, height));
|
||||
ResolutionChangedListener.EVENT.make().onResolutionChanged(width, height);
|
||||
}
|
||||
|
||||
public void resetCursor() {
|
||||
|
@ -432,110 +466,51 @@ public class DisplayContainer implements ErrorDumpable, KeyListener, MouseListen
|
|||
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
|
||||
}
|
||||
|
||||
public boolean isWidescreen() {
|
||||
return width * 1000 / height > 1500; // 1777 = 16:9, 1333 = 4:3
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeErrorDump(StringWriter dump) {
|
||||
dump.append("> DisplayContainer dump\n");
|
||||
dump.append("OpenGL version: ").append(glVersion).append( "(").append(glVendor).append(")\n");
|
||||
if (isTransitioning()) {
|
||||
dump.append("doing a transition\n");
|
||||
dump.append("using out transition ").append(outTransitionState.getClass().getSimpleName()).append('\n');
|
||||
dump.append("using in transition ").append(inTransitionState.getClass().getSimpleName()).append('\n');
|
||||
if (state == inTransitionState) {
|
||||
dump.append("currently doing the in transition\n");
|
||||
} else {
|
||||
dump.append("currently doing the out transition\n");
|
||||
}
|
||||
if (state == null) {
|
||||
dump.append("state is null!\n");
|
||||
return;
|
||||
}
|
||||
state.writeErrorDump(dump);
|
||||
}
|
||||
|
||||
// TODO change this
|
||||
public boolean isInState(Class<? extends OpsuState> state) {
|
||||
return state.isInstance(state);
|
||||
}
|
||||
|
||||
public boolean isTransitioning() {
|
||||
return state instanceof TransitionState;
|
||||
public void switchState(OpsuState state) {
|
||||
switchState(state, 200, 300);
|
||||
}
|
||||
|
||||
public void switchState(Class<? extends OpsuState> newState) {
|
||||
switchState(newState, FadeOutTransitionState.class, 200, FadeInTransitionState.class, 300);
|
||||
}
|
||||
|
||||
public void switchStateNow(Class<? extends OpsuState> newState) {
|
||||
switchState(newState, EmptyTransitionState.class, 0, FadeInTransitionState.class, 300);
|
||||
}
|
||||
|
||||
public void switchStateInstantly(Class<? extends OpsuState> newState) {
|
||||
state.leave();
|
||||
state = instanceContainer.provide(newState);
|
||||
state.enter();
|
||||
}
|
||||
|
||||
public void switchState(Class<? extends OpsuState> newState, Class<? extends TransitionState> outTransition, int outTime, Class<? extends TransitionState> inTransition, int inTime) {
|
||||
if (isTransitioning()) {
|
||||
public void switchState(OpsuState newstate, int outtime, int intime) {
|
||||
if (transition.progress != -1) {
|
||||
return;
|
||||
}
|
||||
outTransitionState = instanceContainer.provide(outTransition).set(state, outTime, outTransitionListener);
|
||||
inTransitionState = instanceContainer.provide(inTransition).set(instanceContainer.provide(newState), inTime, inTransitionListener);
|
||||
state = outTransitionState;
|
||||
state.enter();
|
||||
}
|
||||
|
||||
/*
|
||||
* input events below, see org.newdawn.slick.KeyListener & org.newdawn.slick.MouseListener
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void keyPressed(int key, char c) {
|
||||
state.keyPressed(key, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(int key, char c) {
|
||||
state.keyReleased(key, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(int change) {
|
||||
state.mouseWheelMoved(change);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(int button, int x, int y, int clickCount) { }
|
||||
|
||||
@Override
|
||||
public void mousePressed(int button, int x, int y) {
|
||||
state.mousePressed(button, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int button, int x, int y) {
|
||||
if (bubNotifState.mouseReleased(x, y)) {
|
||||
return;
|
||||
if (outtime == 0) {
|
||||
switchStateInstantly(newstate);
|
||||
newstate = null;
|
||||
}
|
||||
state.mouseReleased(button, x, y);
|
||||
transition.nextstate = newstate;
|
||||
transition.total = transition.in = intime;
|
||||
transition.out = outtime;
|
||||
transition.total += outtime;
|
||||
transition.progress = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(int oldx, int oldy, int newx, int newy) { }
|
||||
|
||||
@Override
|
||||
public void mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
state.mouseDragged(oldx, oldy, newx, newy);
|
||||
public void switchStateInstantly(OpsuState state) {
|
||||
this.state.leave();
|
||||
input.removeListener(this.state);
|
||||
this.state = state;
|
||||
this.state.enter();
|
||||
input.addListener(this.state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Input input) { }
|
||||
|
||||
@Override
|
||||
public boolean isAcceptingInput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inputEnded() { }
|
||||
|
||||
@Override
|
||||
public void inputStarted() { }
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,11 @@ package yugecin.opsudance.core;
|
|||
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import yugecin.opsudance.OpsuDance;
|
||||
import yugecin.opsudance.core.inject.OpsuDanceInjector;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static yugecin.opsudance.core.Constants.PROJECT_NAME;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class Entrypoint {
|
||||
|
||||
|
@ -27,10 +31,18 @@ public class Entrypoint {
|
|||
|
||||
public static void main(String[] args) {
|
||||
sout("launched");
|
||||
(new OpsuDanceInjector()).provide(OpsuDance.class).start(args);
|
||||
|
||||
if (Updater.get().getStatus() == Updater.Status.UPDATE_FINAL) {
|
||||
Updater.get().runUpdate();
|
||||
try {
|
||||
InstanceContainer.kickstart();
|
||||
} catch (Exception e) {
|
||||
JOptionPane.showMessageDialog(null, e.getMessage(), "Cannot start " + PROJECT_NAME, JOptionPane.ERROR_MESSAGE);
|
||||
// TODO replace with errorhandler
|
||||
}
|
||||
|
||||
new OpsuDance().start(args);
|
||||
|
||||
if (updater.getStatus() == Updater.Status.UPDATE_FINAL) {
|
||||
updater.runUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +51,7 @@ public class Entrypoint {
|
|||
}
|
||||
|
||||
public static void sout(String message) {
|
||||
System.out.println(String.format("[%7d] %s", runtime(), message));
|
||||
System.out.println(String.format("[%8d] %s", runtime(), message));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
53
src/yugecin/opsudance/core/Environment.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static yugecin.opsudance.core.Constants.PROJECT_NAME;
|
||||
|
||||
public class Environment {
|
||||
|
||||
public final boolean isJarRunning;
|
||||
public final File workingdir;
|
||||
public final File jarfile;
|
||||
|
||||
public Environment() {
|
||||
Class thiz = Environment.class;
|
||||
String thisClassLocation = thiz.getResource(thiz.getSimpleName() + ".class").toString();
|
||||
this.isJarRunning = thisClassLocation.startsWith("jar:");
|
||||
if (!isJarRunning) {
|
||||
this.workingdir = Paths.get(".").toAbsolutePath().normalize().toFile();
|
||||
this.jarfile = null;
|
||||
} else {
|
||||
String wdir = thisClassLocation.substring(9); // remove jar:file:
|
||||
String separator = "!/";
|
||||
int separatorIdx = wdir.indexOf(separator);
|
||||
int lastSeparatorIdx = wdir.lastIndexOf(separator);
|
||||
if (separatorIdx != lastSeparatorIdx) {
|
||||
String msg = String.format("%s cannot run from paths containing '!/', please move the file. Current directory: %s",
|
||||
PROJECT_NAME, thisClassLocation.substring(0, lastSeparatorIdx));
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
this.jarfile = new File(wdir.substring(0, separatorIdx));
|
||||
this.workingdir = jarfile.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
84
src/yugecin/opsudance/core/GlobalInputListener.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.InputListener;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
|
||||
import static org.lwjgl.input.Keyboard.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public class GlobalInputListener implements InputListener {
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int key, char c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyReleased(int key, char c) {
|
||||
if (key == KEY_F7) {
|
||||
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
|
||||
BarNotifListener.EVENT.make().onBarNotif(String.format("Frame limiter: %s",
|
||||
OPTION_TARGET_FPS.getValueString()));
|
||||
return true;
|
||||
}
|
||||
if (key == KEY_F10) {
|
||||
OPTION_DISABLE_MOUSE_BUTTONS.toggle();
|
||||
return true;
|
||||
}
|
||||
if (key == KEY_F12) {
|
||||
config.takeScreenShot();
|
||||
return true;
|
||||
}
|
||||
if (key == KEY_S && isKeyDown(KEY_LMENU) && isKeyDown(KEY_LSHIFT) &&
|
||||
input.isControlDown() && !displayContainer.isInState(Game.class)) {
|
||||
skinservice.reloadSkin();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
if (isKeyDown(Input.KEY_LALT) || isKeyDown(Input.KEY_RALT)) {
|
||||
UI.changeVolume((delta < 0) ? -1 : 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int button, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(int button, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
137
src/yugecin/opsudance/core/InstanceContainer.java
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
import itdelatrisu.opsu.NativeLoader;
|
||||
import itdelatrisu.opsu.beatmap.BeatmapParser;
|
||||
import itdelatrisu.opsu.beatmap.OszUnpacker;
|
||||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||
import itdelatrisu.opsu.states.*;
|
||||
import org.newdawn.slick.Input;
|
||||
import org.newdawn.slick.util.FileSystemLocation;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.options.OptionsService;
|
||||
import yugecin.opsudance.render.GameObjectRenderer;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.utils.ManifestWrapper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import static yugecin.opsudance.utils.SyntacticSugar.closeAndSwallow;
|
||||
|
||||
public class InstanceContainer {
|
||||
|
||||
public static Environment env;
|
||||
public static Configuration config;
|
||||
|
||||
public static OptionsService optionservice;
|
||||
public static SkinService skinservice;
|
||||
public static OszUnpacker oszunpacker;
|
||||
public static ReplayImporter replayImporter;
|
||||
public static BeatmapParser beatmapParser;
|
||||
public static Updater updater;
|
||||
|
||||
public static DisplayContainer displayContainer;
|
||||
public static Input input;
|
||||
|
||||
public static GameObjectRenderer gameObjectRenderer;
|
||||
|
||||
public static Splash splashState;
|
||||
public static MainMenu mainmenuState;
|
||||
public static ButtonMenu buttonState;
|
||||
public static SongMenu songMenuState;
|
||||
public static DownloadsMenu downloadState;
|
||||
public static Game gameState;
|
||||
public static GameRanking gameRankingState;
|
||||
public static GamePauseMenu pauseState;
|
||||
|
||||
public static void kickstart() {
|
||||
updater = new Updater();
|
||||
env = new Environment();
|
||||
|
||||
JarFile jarfile = getJarfile();
|
||||
ManifestWrapper manifest = new ManifestWrapper(getJarManifest(jarfile));
|
||||
config = new Configuration(manifest);
|
||||
if (jarfile != null) {
|
||||
try {
|
||||
NativeLoader.loadNatives(jarfile, manifest);
|
||||
} catch (IOException e) {
|
||||
String msg = String.format("Could not unpack native(s): %s", e.getMessage());
|
||||
throw new RuntimeException(msg, e);
|
||||
} finally {
|
||||
closeAndSwallow(jarfile);
|
||||
}
|
||||
}
|
||||
NativeLoader.setNativePath();
|
||||
|
||||
ResourceLoader.addResourceLocation(new FileSystemLocation(new File("./res/")));
|
||||
|
||||
optionservice = new OptionsService();
|
||||
skinservice = new SkinService();
|
||||
oszunpacker = new OszUnpacker();
|
||||
replayImporter = new ReplayImporter();
|
||||
beatmapParser = new BeatmapParser();
|
||||
updater = new Updater();
|
||||
|
||||
displayContainer = new DisplayContainer();
|
||||
|
||||
gameObjectRenderer = new GameObjectRenderer();
|
||||
|
||||
splashState = new Splash();
|
||||
mainmenuState = new MainMenu();
|
||||
buttonState = new ButtonMenu();
|
||||
songMenuState = new SongMenu();
|
||||
downloadState = new DownloadsMenu();
|
||||
gameState = new Game();
|
||||
gameRankingState = new GameRanking();
|
||||
pauseState = new GamePauseMenu();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JarFile getJarfile() {
|
||||
if (env.jarfile == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new JarFile(env.jarfile);
|
||||
} catch (IOException e) {
|
||||
String msg = String.format("Cannot read from jarfile (%s): %s", env.jarfile.getAbsolutePath(),
|
||||
e.getMessage());
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Manifest getJarManifest(@Nullable JarFile jarfile) {
|
||||
if (jarfile == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return jarfile.getManifest();
|
||||
} catch (IOException e) {
|
||||
String msg = String.format("Cannot read manifest from jarfile: %s", e.getMessage());
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -15,13 +15,9 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
public class EmptyTransitionState extends TransitionState {
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
finish();
|
||||
}
|
||||
|
||||
}
|
||||
@Retention(RetentionPolicy.SOURCE) public @interface NotNull {}
|
|
@ -15,10 +15,9 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.events;
|
||||
package yugecin.opsudance.core;
|
||||
|
||||
public interface EventListener<T> {
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
void onEvent(T event);
|
||||
|
||||
}
|
||||
@Retention(RetentionPolicy.SOURCE) public @interface Nullable {}
|
|
@ -19,8 +19,7 @@ package yugecin.opsudance.core.errorhandling;
|
|||
|
||||
import itdelatrisu.opsu.Utils;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.core.Constants;
|
||||
import yugecin.opsudance.utils.MiscUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -35,80 +34,52 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
/**
|
||||
* based on itdelatrisu.opsu.ErrorHandler
|
||||
*/
|
||||
public class ErrorHandler {
|
||||
|
||||
private static ErrorHandler instance;
|
||||
|
||||
private final Configuration config;
|
||||
private final DisplayContainer displayContainer;
|
||||
|
||||
private String customMessage;
|
||||
private Throwable cause;
|
||||
private String errorDump;
|
||||
private String messageBody;
|
||||
|
||||
private boolean preventContinue;
|
||||
private boolean preventReport;
|
||||
private boolean ignoreAndContinue;
|
||||
private boolean allowTerminate;
|
||||
|
||||
public ErrorHandler(DisplayContainer displayContainer, Configuration config) {
|
||||
this.displayContainer = displayContainer;
|
||||
this.config = config;
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private ErrorHandler init(String customMessage, Throwable cause) {
|
||||
this.customMessage = customMessage;
|
||||
this.cause = cause;
|
||||
public final static int DEFAULT_OPTIONS = 0;
|
||||
public final static int PREVENT_CONTINUE = 1;
|
||||
public final static int PREVENT_REPORT = 2;
|
||||
public final static int ALLOW_TERMINATE = 4;
|
||||
|
||||
public static boolean explode(String customMessage, Throwable cause, int flags) {
|
||||
StringWriter dump = new StringWriter();
|
||||
try {
|
||||
displayContainer.writeErrorDump(dump);
|
||||
} catch (Exception e) {
|
||||
dump
|
||||
.append("### ")
|
||||
.append(e.getClass().getSimpleName())
|
||||
.append(" while creating errordump");
|
||||
e.printStackTrace(new PrintWriter(dump));
|
||||
if (displayContainer == null) {
|
||||
dump.append("displayContainer is null!\n");
|
||||
} else {
|
||||
try {
|
||||
displayContainer.writeErrorDump(dump);
|
||||
} catch (Exception e) {
|
||||
dump
|
||||
.append("### ")
|
||||
.append(e.getClass().getSimpleName())
|
||||
.append(" while creating errordump");
|
||||
e.printStackTrace(new PrintWriter(dump));
|
||||
}
|
||||
}
|
||||
errorDump = dump.toString();
|
||||
String errorDump = dump.toString();
|
||||
|
||||
dump = new StringWriter();
|
||||
dump.append(customMessage).append("\n");
|
||||
cause.printStackTrace(new PrintWriter(dump));
|
||||
dump.append("\n").append(errorDump);
|
||||
messageBody = dump.toString();
|
||||
String messageBody = dump.toString();
|
||||
|
||||
Log.error("====== start unhandled exception dump");
|
||||
Log.error(messageBody);
|
||||
Log.error("====== end unhandled exception dump");
|
||||
return this;
|
||||
|
||||
int result = show(messageBody, customMessage, cause, errorDump, flags);
|
||||
|
||||
return (flags & ALLOW_TERMINATE) == 0 || result == 1;
|
||||
}
|
||||
|
||||
public static ErrorHandler error(String message, Throwable cause) {
|
||||
return instance.init(message, cause);
|
||||
}
|
||||
|
||||
public ErrorHandler preventReport() {
|
||||
preventReport = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorHandler allowTerminate() {
|
||||
allowTerminate = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorHandler preventContinue() {
|
||||
preventContinue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorHandler show() {
|
||||
private static int show(final String messageBody, final String customMessage, final Throwable cause,
|
||||
final String errorDump, final int flags) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
|
@ -118,7 +89,7 @@ public class ErrorHandler {
|
|||
String title = "opsu!dance error - " + customMessage;
|
||||
|
||||
String messageText = "opsu!dance has encountered an error.";
|
||||
if (!preventReport) {
|
||||
if ((flags & PREVENT_REPORT) == 0) {
|
||||
messageText += " Please report this!";
|
||||
}
|
||||
JLabel message = new JLabel(messageText);
|
||||
|
@ -132,12 +103,27 @@ public class ErrorHandler {
|
|||
textArea.setWrapStyleWord(true);
|
||||
textArea.setText(messageBody);
|
||||
|
||||
Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(), createReportButton() };
|
||||
ActionListener reportAction = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
URI url = createGithubIssueUrl(customMessage, cause, errorDump);
|
||||
Desktop.getDesktop().browse(url);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open browser to report issue", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not launch a browser",
|
||||
"errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Object[] messageComponents = new Object[] { message, new JScrollPane(textArea), createViewLogButton(),
|
||||
createReportButton(flags, reportAction) };
|
||||
|
||||
String[] buttons;
|
||||
if (!allowTerminate && !preventContinue) {
|
||||
if ((flags & (ALLOW_TERMINATE | PREVENT_CONTINUE)) == 0) {
|
||||
buttons = new String[] { "Ignore & continue" };
|
||||
} else if (preventContinue) {
|
||||
} else if ((flags & PREVENT_CONTINUE) == 0) {
|
||||
buttons = new String[] { "Terminate" };
|
||||
} else {
|
||||
buttons = new String[] { "Terminate", "Ignore & continue" };
|
||||
|
@ -147,52 +133,46 @@ public class ErrorHandler {
|
|||
frame.setUndecorated(true);
|
||||
frame.setVisible(true);
|
||||
frame.setLocationRelativeTo(null);
|
||||
int result = JOptionPane.showOptionDialog(frame,
|
||||
messageComponents,
|
||||
title,
|
||||
JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE,
|
||||
null,
|
||||
buttons,
|
||||
buttons[buttons.length - 1]);
|
||||
ignoreAndContinue = !allowTerminate || result == 1;
|
||||
int result = JOptionPane.showOptionDialog(frame, messageComponents, title, JOptionPane.DEFAULT_OPTION,
|
||||
JOptionPane.ERROR_MESSAGE, null, buttons, buttons[buttons.length - 1]);
|
||||
frame.dispose();
|
||||
|
||||
return this;
|
||||
return result;
|
||||
}
|
||||
|
||||
private JComponent createViewLogButton() {
|
||||
private static JComponent createViewLogButton() {
|
||||
return createButton("View log", Desktop.Action.OPEN, new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
Desktop.getDesktop().open(config.LOG_FILE);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open log file", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not open log file", "errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
openLogfile();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JComponent createReportButton() {
|
||||
if (preventReport) {
|
||||
private static void openLogfile() {
|
||||
if (config == null) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"Cannot open logfile, check your opsu! installation folder for .opsu.cfg",
|
||||
"errorception", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Desktop.getDesktop().open(config.LOG_FILE);
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open log file", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not open log file",
|
||||
"errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private static JComponent createReportButton(int flags, ActionListener reportAction) {
|
||||
if ((flags & PREVENT_REPORT) > 0) {
|
||||
return new JLabel();
|
||||
}
|
||||
return createButton("Report error", Desktop.Action.BROWSE, new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(createGithubIssueUrl());
|
||||
} catch (IOException e) {
|
||||
Log.warn("Could not open browser to report issue", e);
|
||||
JOptionPane.showMessageDialog(null, "whoops could not launch a browser", "errorception", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
});
|
||||
return createButton("Report error", Desktop.Action.BROWSE, reportAction);
|
||||
}
|
||||
|
||||
private JButton createButton(String buttonText, Desktop.Action action, ActionListener listener) {
|
||||
private static JButton createButton(String buttonText, Desktop.Action action, ActionListener listener) {
|
||||
JButton button = new JButton(buttonText);
|
||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(action)) {
|
||||
button.addActionListener(listener);
|
||||
|
@ -202,7 +182,7 @@ public class ErrorHandler {
|
|||
return button;
|
||||
}
|
||||
|
||||
private URI createGithubIssueUrl() {
|
||||
private static URI createGithubIssueUrl(String customMessage, Throwable cause, String errorDump) {
|
||||
StringWriter dump = new StringWriter();
|
||||
|
||||
dump.append(customMessage).append("\n");
|
||||
|
@ -227,15 +207,16 @@ public class ErrorHandler {
|
|||
String issueTitle = "";
|
||||
String issueBody = "";
|
||||
try {
|
||||
issueTitle = URLEncoder.encode("*** Unhandled " + cause.getClass().getSimpleName() + " " + customMessage, "UTF-8");
|
||||
issueTitle = URLEncoder.encode("*** Unhandled " + cause.getClass().getSimpleName() + " " +
|
||||
customMessage, "UTF-8");
|
||||
issueBody = URLEncoder.encode(truncateGithubIssueBody(dump.toString()), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.warn("URLEncoder failed to encode the auto-filled issue report URL.", e);
|
||||
}
|
||||
return URI.create(String.format(config.ISSUES_URL, issueTitle, issueBody));
|
||||
return URI.create(String.format(Constants.ISSUES_URL, issueTitle, issueBody));
|
||||
}
|
||||
|
||||
private String truncateGithubIssueBody(String body) {
|
||||
private static String truncateGithubIssueBody(String body) {
|
||||
if (body.replaceAll("[^a-zA-Z+-]", "").length() < 1750) {
|
||||
return body;
|
||||
}
|
||||
|
@ -243,8 +224,4 @@ public class ErrorHandler {
|
|||
return body.substring(0, 1640) + "** TRUNCATED **\n```";
|
||||
}
|
||||
|
||||
public boolean shouldIgnoreAndContinue() {
|
||||
return ignoreAndContinue;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,38 +17,37 @@
|
|||
*/
|
||||
package yugecin.opsudance.core.events;
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.LinkedList;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class EventBus {
|
||||
public class Event<T> {
|
||||
|
||||
private EventBus() {
|
||||
private final Class<T> type;
|
||||
private final LinkedList<T> listeners;
|
||||
|
||||
public Event(Class<T> type) {
|
||||
this.type = type;
|
||||
this.listeners = new LinkedList<>();
|
||||
}
|
||||
|
||||
private static final List<Subscriber> subscribers = new LinkedList<>();
|
||||
|
||||
public static <T> void subscribe(Class<T> eventType, EventListener<T> eventListener) {
|
||||
subscribers.add(new Subscriber<>(eventType, eventListener));
|
||||
public void addListener(T listener) {
|
||||
this.listeners.add(listener);
|
||||
}
|
||||
|
||||
public static void post(Object event) {
|
||||
for (Subscriber s : subscribers) {
|
||||
if (s.eventType.isInstance(event)) {
|
||||
s.listener.onEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Subscriber<T> {
|
||||
|
||||
private final Class<T> eventType;
|
||||
private final EventListener<T> listener;
|
||||
|
||||
private Subscriber(Class<T> eventType, EventListener<T> listener) {
|
||||
this.eventType = eventType;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public T make() {
|
||||
return (T) Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
for (T listener : listeners) {
|
||||
method.invoke(listener, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
*
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.inject;
|
||||
|
@ -22,14 +23,10 @@ import itdelatrisu.opsu.beatmap.OszUnpacker;
|
|||
import itdelatrisu.opsu.downloads.Updater;
|
||||
import itdelatrisu.opsu.replay.ReplayImporter;
|
||||
import itdelatrisu.opsu.states.*;
|
||||
import yugecin.opsudance.PreStartupInitializer;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.state.specialstates.BarNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubbleNotificationState;
|
||||
import yugecin.opsudance.core.state.specialstates.BubNotifState;
|
||||
import yugecin.opsudance.core.state.specialstates.FpsRenderState;
|
||||
import yugecin.opsudance.core.state.transitions.EmptyTransitionState;
|
||||
import yugecin.opsudance.core.state.transitions.FadeInTransitionState;
|
||||
import yugecin.opsudance.core.state.transitions.FadeOutTransitionState;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorHandler;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.options.OptionsService;
|
||||
|
@ -48,18 +45,14 @@ public class OpsuDanceInjector extends Injector {
|
|||
bind(Updater.class).asLazySingleton();
|
||||
bind(SkinService.class).asEagerSingleton();
|
||||
|
||||
bind(PreStartupInitializer.class).asEagerSingleton();
|
||||
//bind(PreStartupInitializer.class).asEagerSingleton();
|
||||
bind(DisplayContainer.class).asEagerSingleton();
|
||||
|
||||
bind(ErrorHandler.class).asEagerSingleton();
|
||||
|
||||
bind(FpsRenderState.class).asEagerSingleton();
|
||||
bind(BarNotificationState.class).asEagerSingleton();
|
||||
bind(BubbleNotificationState.class).asEagerSingleton();
|
||||
|
||||
bind(EmptyTransitionState.class).asEagerSingleton();
|
||||
bind(FadeInTransitionState.class).asEagerSingleton();
|
||||
bind(FadeOutTransitionState.class).asEagerSingleton();
|
||||
bind(BubNotifState.class).asEagerSingleton();
|
||||
|
||||
bind(GameObjectRenderer.class).asEagerSingleton();
|
||||
|
||||
|
|
|
@ -17,33 +17,12 @@
|
|||
*/
|
||||
package yugecin.opsudance.core.state;
|
||||
|
||||
import itdelatrisu.opsu.states.Game;
|
||||
import itdelatrisu.opsu.ui.UI;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.core.inject.Inject;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.options.Configuration;
|
||||
import yugecin.opsudance.skinning.SkinService;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
|
||||
public abstract class BaseOpsuState implements OpsuState, EventListener<ResolutionOrSkinChangedEvent> {
|
||||
|
||||
@Inject
|
||||
protected DisplayContainer displayContainer;
|
||||
|
||||
@Inject
|
||||
protected Configuration config;
|
||||
|
||||
@Inject
|
||||
protected SkinService skinService;
|
||||
public abstract class BaseOpsuState implements OpsuState, ResolutionChangedListener {
|
||||
|
||||
/**
|
||||
* state is dirty when resolution or skin changed but hasn't rendered yet
|
||||
|
@ -52,7 +31,7 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
|||
private boolean isCurrentState;
|
||||
|
||||
public BaseOpsuState() {
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
protected void revalidate() {
|
||||
|
@ -71,7 +50,7 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
if (isCurrentState) {
|
||||
revalidate();
|
||||
return;
|
||||
|
@ -105,32 +84,11 @@ public abstract class BaseOpsuState implements OpsuState, EventListener<Resoluti
|
|||
|
||||
@Override
|
||||
public boolean keyReleased(int key, char c) {
|
||||
if (key == Input.KEY_F7) {
|
||||
OPTION_TARGET_FPS.clickListItem((targetFPSIndex + 1) % targetFPS.length);
|
||||
EventBus.post(new BarNotificationEvent(String.format("Frame limiter: %s", OPTION_TARGET_FPS.getValueString())));
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_F10) {
|
||||
OPTION_DISABLE_MOUSE_BUTTONS.toggle();
|
||||
return true;
|
||||
}
|
||||
if (key == Input.KEY_F12) {
|
||||
config.takeScreenShot();
|
||||
return true;
|
||||
}
|
||||
Input input = displayContainer.input;
|
||||
if (key == Input.KEY_S && input.isKeyDown(Input.KEY_LMENU) && input.isKeyDown(Input.KEY_LSHIFT) &&input.isKeyDown(Input.KEY_LCONTROL) && !displayContainer.isInState(Game.class)) {
|
||||
skinService.reloadSkin();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
if (displayContainer.input.isKeyDown(Input.KEY_LALT) || displayContainer.input.isKeyDown(Input.KEY_RALT)) {
|
||||
UI.changeVolume((delta < 0) ? -1 : 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
*/
|
||||
package yugecin.opsudance.core.state;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.Input;
|
||||
import yugecin.opsudance.core.components.Component;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public abstract class ComplexOpsuState extends BaseOpsuState {
|
||||
|
||||
protected final LinkedList<Component> components;
|
||||
|
@ -163,7 +165,7 @@ public abstract class ComplexOpsuState extends BaseOpsuState {
|
|||
}
|
||||
}
|
||||
if (focusedComponent != null) {
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
focusedComponent.setFocused(false);
|
||||
focusedComponent = null;
|
||||
return true;
|
||||
|
@ -182,7 +184,7 @@ public abstract class ComplexOpsuState extends BaseOpsuState {
|
|||
}
|
||||
}
|
||||
if (focusedComponent != null) {
|
||||
if (key == Input.KEY_ESCAPE) {
|
||||
if (key == Keyboard.KEY_ESCAPE) {
|
||||
focusedComponent.setFocused(false);
|
||||
focusedComponent = null;
|
||||
return true;
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
package yugecin.opsudance.core.state;
|
||||
|
||||
import org.newdawn.slick.Graphics;
|
||||
import org.newdawn.slick.InputListener;
|
||||
import yugecin.opsudance.core.errorhandling.ErrorDumpable;
|
||||
|
||||
public interface OpsuState extends ErrorDumpable {
|
||||
public interface OpsuState extends ErrorDumpable, InputListener {
|
||||
|
||||
void update();
|
||||
void preRenderUpdate();
|
||||
|
@ -33,34 +34,4 @@ public interface OpsuState extends ErrorDumpable {
|
|||
*/
|
||||
boolean onCloseRequest();
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean keyPressed(int key, char c);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean keyReleased(int key, char c);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mouseWheelMoved(int delta);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mousePressed(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mouseReleased(int button, int x, int y);
|
||||
|
||||
/**
|
||||
* @return false to stop event bubbling
|
||||
*/
|
||||
boolean mouseDragged(int oldx, int oldy, int newx, int newy);
|
||||
|
||||
}
|
||||
|
|
|
@ -21,22 +21,20 @@ import itdelatrisu.opsu.ui.Fonts;
|
|||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.BarNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.events.BarNotifListener;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BarNotificationState implements EventListener<BarNotificationEvent> {
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
public class BarNotificationState implements BarNotifListener, ResolutionChangedListener {
|
||||
|
||||
private final int IN_TIME = 200;
|
||||
private final int DISPLAY_TIME = 5700 + IN_TIME;
|
||||
private final int OUT_TIME = 200;
|
||||
private final int TOTAL_TIME = DISPLAY_TIME + OUT_TIME;
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
private final Color bgcol;
|
||||
private final Color textCol;
|
||||
|
||||
|
@ -49,21 +47,12 @@ public class BarNotificationState implements EventListener<BarNotificationEvent>
|
|||
private int barHalfTargetHeight;
|
||||
private int barHalfHeight;
|
||||
|
||||
public BarNotificationState(DisplayContainer displayContainer) {
|
||||
this.displayContainer = displayContainer;
|
||||
public BarNotificationState() {
|
||||
this.bgcol = new Color(Color.black);
|
||||
this.textCol = new Color(Color.white);
|
||||
this.timeShown = TOTAL_TIME;
|
||||
EventBus.subscribe(BarNotificationEvent.class, this);
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
if (timeShown >= TOTAL_TIME) {
|
||||
return;
|
||||
}
|
||||
calculatePosition();
|
||||
}
|
||||
});
|
||||
BarNotifListener.EVENT.addListener(this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
public void render(Graphics g) {
|
||||
|
@ -108,10 +97,18 @@ public class BarNotificationState implements EventListener<BarNotificationEvent>
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(BarNotificationEvent event) {
|
||||
this.message = event.message;
|
||||
public void onBarNotif(String message) {
|
||||
this.message = message;
|
||||
calculatePosition();
|
||||
timeShown = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
if (timeShown >= TOTAL_TIME) {
|
||||
return;
|
||||
}
|
||||
calculatePosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,40 +21,33 @@ import itdelatrisu.opsu.ui.Fonts;
|
|||
import itdelatrisu.opsu.ui.animations.AnimationEquation;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.BubbleNotificationEvent;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import org.newdawn.slick.MouseListener;
|
||||
import yugecin.opsudance.events.BubNotifListener;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class BubbleNotificationState implements EventListener<BubbleNotificationEvent> {
|
||||
import static yugecin.opsudance.core.InstanceContainer.*;
|
||||
|
||||
public class BubNotifState implements MouseListener, BubNotifListener, ResolutionChangedListener {
|
||||
|
||||
public static final int IN_TIME = 633;
|
||||
public static final int DISPLAY_TIME = 7000 + IN_TIME;
|
||||
public static final int OUT_TIME = 433;
|
||||
public static final int TOTAL_TIME = DISPLAY_TIME + OUT_TIME;
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
private final LinkedList<Notification> bubbles;
|
||||
|
||||
private int addAnimationTime;
|
||||
private int addAnimationHeight;
|
||||
|
||||
public BubbleNotificationState(DisplayContainer displayContainer) {
|
||||
this.displayContainer = displayContainer;
|
||||
public BubNotifState() {
|
||||
this.bubbles = new LinkedList<>();
|
||||
this.addAnimationTime = IN_TIME;
|
||||
EventBus.subscribe(BubbleNotificationEvent.class, this);
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, new EventListener<ResolutionOrSkinChangedEvent>() {
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
calculatePositions();
|
||||
}
|
||||
});
|
||||
BubNotifListener.EVENT.addListener(this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
public void render(Graphics g) {
|
||||
|
@ -79,20 +72,9 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
|||
} while (iter.hasNext());
|
||||
}
|
||||
|
||||
public boolean mouseReleased(int x, int y) {
|
||||
if (x < Notification.finalX) {
|
||||
return false;
|
||||
}
|
||||
for (Notification bubble : bubbles) {
|
||||
if (bubble.mouseReleased(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void calculatePositions() {
|
||||
Notification.width = (int) (displayContainer.width * 0.1703125f);
|
||||
// if width is 0, attempting to wrap it will result in infinite loop
|
||||
Notification.width = Math.max(50, (int) (displayContainer.width * 0.1703125f));
|
||||
Notification.baseLine = (int) (displayContainer.height * 0.9645f);
|
||||
Notification.paddingY = (int) (displayContainer.height * 0.0144f);
|
||||
Notification.finalX = displayContainer.width - Notification.width - (int) (displayContainer.width * 0.01);
|
||||
|
@ -130,9 +112,9 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(BubbleNotificationEvent event) {
|
||||
public void onBubNotif(String message, Color borderColor) {
|
||||
finishAddAnimation();
|
||||
Notification newBubble = new Notification(event.message, event.borderColor);
|
||||
Notification newBubble = new Notification(message, borderColor);
|
||||
bubbles.add(0, newBubble);
|
||||
addAnimationTime = 0;
|
||||
addAnimationHeight = newBubble.height + Notification.paddingY;
|
||||
|
@ -144,6 +126,39 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
calculatePositions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseWheelMoved(int delta) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int button, int x, int y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(int button, int x, int y) {
|
||||
if (x < Notification.finalX) {
|
||||
return false;
|
||||
}
|
||||
for (Notification bubble : bubbles) {
|
||||
if (bubble.mouseReleased(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class Notification {
|
||||
|
||||
private final static int HOVER_ANIM_TIME = 150;
|
||||
|
@ -205,7 +220,7 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
|||
Fonts.SMALLBOLD.drawString(x + fontPaddingX, y, line, textColor);
|
||||
y += lineHeight;
|
||||
}
|
||||
return timeShown > BubbleNotificationState.TOTAL_TIME;
|
||||
return timeShown > BubNotifState.TOTAL_TIME;
|
||||
}
|
||||
|
||||
private void processAnimations(boolean mouseHovered, int delta) {
|
||||
|
@ -218,17 +233,17 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
|||
borderColor.r = targetBorderColor.r + (0.977f - targetBorderColor.r) * hoverProgress;
|
||||
borderColor.g = targetBorderColor.g + (0.977f - targetBorderColor.g) * hoverProgress;
|
||||
borderColor.b = targetBorderColor.b + (0.977f - targetBorderColor.b) * hoverProgress;
|
||||
if (timeShown < BubbleNotificationState.IN_TIME) {
|
||||
float progress = (float) timeShown / BubbleNotificationState.IN_TIME;
|
||||
if (timeShown < BubNotifState.IN_TIME) {
|
||||
float progress = (float) timeShown / BubNotifState.IN_TIME;
|
||||
this.x = finalX + (int) ((1 - AnimationEquation.OUT_BACK.calc(progress)) * width / 2);
|
||||
textColor.a = borderColor.a = bgcol.a = progress;
|
||||
bgcol.a = borderColor.a * 0.8f;
|
||||
return;
|
||||
}
|
||||
x = Notification.finalX;
|
||||
if (timeShown > BubbleNotificationState.DISPLAY_TIME) {
|
||||
if (timeShown > BubNotifState.DISPLAY_TIME) {
|
||||
isFading = true;
|
||||
float progress = (float) (timeShown - BubbleNotificationState.DISPLAY_TIME) / BubbleNotificationState.OUT_TIME;
|
||||
float progress = (float) (timeShown - BubNotifState.DISPLAY_TIME) / BubNotifState.OUT_TIME;
|
||||
textColor.a = borderColor.a = 1f - progress;
|
||||
bgcol.a = borderColor.a * 0.8f;
|
||||
}
|
||||
|
@ -236,7 +251,7 @@ public class BubbleNotificationState implements EventListener<BubbleNotification
|
|||
|
||||
private boolean mouseReleased(int x, int y) {
|
||||
if (!isFading && isMouseHovered(x, y)) {
|
||||
timeShown = BubbleNotificationState.DISPLAY_TIME;
|
||||
timeShown = BubNotifState.DISPLAY_TIME;
|
||||
return true;
|
||||
}
|
||||
return false;
|
|
@ -20,21 +20,18 @@ package yugecin.opsudance.core.state.specialstates;
|
|||
import itdelatrisu.opsu.ui.Fonts;
|
||||
import org.newdawn.slick.Color;
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.DisplayContainer;
|
||||
import yugecin.opsudance.core.events.EventBus;
|
||||
import yugecin.opsudance.core.events.EventListener;
|
||||
import yugecin.opsudance.events.ResolutionOrSkinChangedEvent;
|
||||
import yugecin.opsudance.events.ResolutionChangedListener;
|
||||
import yugecin.opsudance.utils.FPSMeter;
|
||||
|
||||
import static yugecin.opsudance.options.Options.*;
|
||||
import static yugecin.opsudance.core.InstanceContainer.displayContainer;
|
||||
|
||||
public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEvent> {
|
||||
public class FpsRenderState implements ResolutionChangedListener {
|
||||
|
||||
private final static Color GREEN = new Color(171, 218, 25);
|
||||
private final static Color ORANGE = new Color(255, 204, 34);
|
||||
private final static Color DARKORANGE = new Color(255, 149, 24);
|
||||
|
||||
private final DisplayContainer displayContainer;
|
||||
private final FPSMeter fpsMeter;
|
||||
private final FPSMeter upsMeter;
|
||||
|
||||
|
@ -42,11 +39,10 @@ public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEven
|
|||
private int y;
|
||||
private int singleHeight;
|
||||
|
||||
public FpsRenderState(DisplayContainer displayContainer) {
|
||||
this.displayContainer = displayContainer;
|
||||
public FpsRenderState() {
|
||||
fpsMeter = new FPSMeter(10);
|
||||
upsMeter = new FPSMeter(10);
|
||||
EventBus.subscribe(ResolutionOrSkinChangedEvent.class, this);
|
||||
ResolutionChangedListener.EVENT.addListener(this);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
@ -93,7 +89,7 @@ public class FpsRenderState implements EventListener<ResolutionOrSkinChangedEven
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(ResolutionOrSkinChangedEvent event) {
|
||||
public void onResolutionChanged(int w, int h) {
|
||||
singleHeight = Fonts.SMALL.getLineHeight();
|
||||
x = displayContainer.width - 3;
|
||||
y = displayContainer.height - 3 - singleHeight - 10;
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
|
||||
public class FadeOutTransitionState extends FadeTransitionState {
|
||||
|
||||
@Override
|
||||
protected float getMaskAlphaLevel(float fadeProgress) {
|
||||
return fadeProgress;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
|
||||
public interface TransitionFinishedListener {
|
||||
|
||||
void onFinish();
|
||||
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
|
||||
import org.newdawn.slick.Graphics;
|
||||
import yugecin.opsudance.core.state.BaseOpsuState;
|
||||
import yugecin.opsudance.core.state.OpsuState;
|
||||
|
||||
import java.io.StringWriter;
|
||||
|
||||
public abstract class TransitionState extends BaseOpsuState {
|
||||
|
||||
protected OpsuState applicableState;
|
||||
|
||||
protected int transitionTargetTime;
|
||||
protected int transitionTime;
|
||||
|
||||
private TransitionFinishedListener listener;
|
||||
|
||||
public final TransitionState set(OpsuState applicableState, int targetTime, TransitionFinishedListener listener) {
|
||||
this.applicableState = applicableState;
|
||||
this.transitionTargetTime = targetTime;
|
||||
this.listener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final OpsuState getApplicableState() {
|
||||
return applicableState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
applicableState.update();
|
||||
transitionTime += displayContainer.delta;
|
||||
if (transitionTime >= transitionTargetTime) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRenderUpdate() {
|
||||
applicableState.preRenderUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Graphics g) {
|
||||
applicableState.render(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter() {
|
||||
super.enter();
|
||||
transitionTime = 0;
|
||||
}
|
||||
|
||||
protected final void finish() {
|
||||
listener.onFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCloseRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeErrorDump(StringWriter dump) {
|
||||
dump.append("> TransitionState dump\n");
|
||||
dump.append("progress: ").append(String.valueOf(transitionTime)).append("/").append(String.valueOf(transitionTargetTime)).append('\n');
|
||||
dump.append("applicable state: ");
|
||||
if (applicableState == null) {
|
||||
dump.append("IS NULL");
|
||||
return;
|
||||
}
|
||||
dump.append(applicableState.getClass().getSimpleName()).append('\n');
|
||||
applicableState.writeErrorDump(dump);
|
||||
}
|
||||
|
||||
}
|
|
@ -17,12 +17,12 @@
|
|||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
public class BarNotificationEvent {
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
public final String message;
|
||||
public interface BarNotifListener {
|
||||
|
||||
public BarNotificationEvent(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
Event<BarNotifListener> EVENT = new Event<>(BarNotifListener.class);
|
||||
|
||||
void onBarNotif(String message);
|
||||
|
||||
}
|
30
src/yugecin/opsudance/events/BubNotifListener.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
@SuppressWarnings({"UnnecessaryInterfaceModifier", "unused"})
|
||||
public interface BubNotifListener {
|
||||
|
||||
Event<BubNotifListener> EVENT = new Event<>(BubNotifListener.class);
|
||||
|
||||
void onBubNotif(String message, Color borderColor);
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* opsu!dance - fork of opsu! with cursordance auto
|
||||
* Copyright (C) 2017 yugecin
|
||||
*
|
||||
* opsu!dance is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* opsu!dance is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
import org.newdawn.slick.Color;
|
||||
|
||||
public class BubbleNotificationEvent {
|
||||
|
||||
public static final Color COMMONCOLOR_GREEN = new Color(98, 131, 59);
|
||||
public static final Color COMMONCOLOR_WHITE = new Color(220, 220, 220);
|
||||
public static final Color COMMONCOLOR_PURPLE = new Color(94, 46, 149);
|
||||
public static final Color COMMONCOLOR_RED = new Color(141, 49, 16);
|
||||
public static final Color COLOR_ORANGE = new Color(138, 72, 51);
|
||||
|
||||
public final String message;
|
||||
public final Color borderColor;
|
||||
|
||||
public BubbleNotificationEvent(String message, Color borderColor) {
|
||||
this.message = message;
|
||||
this.borderColor = borderColor;
|
||||
}
|
||||
|
||||
}
|
|
@ -17,16 +17,12 @@
|
|||
*/
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
public class ResolutionOrSkinChangedEvent {
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
public final String skin;
|
||||
public final int width;
|
||||
public final int height;
|
||||
public interface ResolutionChangedListener {
|
||||
|
||||
public ResolutionOrSkinChangedEvent(String skin, int width, int height) {
|
||||
this.skin = skin;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
Event<ResolutionChangedListener> EVENT = new Event<>(ResolutionChangedListener.class);
|
||||
|
||||
void onResolutionChanged(int w, int h);
|
||||
|
||||
}
|
|
@ -15,13 +15,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with opsu!dance. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package yugecin.opsudance.core.state.transitions;
|
||||
package yugecin.opsudance.events;
|
||||
|
||||
public class FadeInTransitionState extends FadeTransitionState {
|
||||
import yugecin.opsudance.core.events.Event;
|
||||
|
||||
@Override
|
||||
protected float getMaskAlphaLevel(float fadeProgress) {
|
||||
return 1f - fadeProgress;
|
||||
}
|
||||
public interface SkinChangedListener {
|
||||
|
||||
Event<SkinChangedListener> EVENT = new Event<>(SkinChangedListener.class);
|
||||
|
||||
void onSkinChanged(String stringName);
|
||||
|
||||
}
|