Merge pull request #52 from fluddokt/ReplayTest
Replay Changes: - Saves replay frames as if its repaying, then plays the replay at exact track position. This should give out exact results as the score screen. - Calculates MD5 for beatmap files. (doesn't currently help anything) - Reverse Slider ball (fixes #50)
This commit is contained in:
commit
ba20953634
|
@ -1241,7 +1241,7 @@ public class GameData {
|
||||||
* @param frames the replay frames
|
* @param frames the replay frames
|
||||||
* @return the Replay object, or null if none exists and frames is null
|
* @return the Replay object, or null if none exists and frames is null
|
||||||
*/
|
*/
|
||||||
public Replay getReplay(ReplayFrame[] frames) {
|
public Replay getReplay(ReplayFrame[] frames, OsuFile file) {
|
||||||
if (replay != null && frames == null)
|
if (replay != null && frames == null)
|
||||||
return replay;
|
return replay;
|
||||||
|
|
||||||
|
@ -1251,7 +1251,7 @@ public class GameData {
|
||||||
replay = new Replay();
|
replay = new Replay();
|
||||||
replay.mode = OsuFile.MODE_OSU;
|
replay.mode = OsuFile.MODE_OSU;
|
||||||
replay.version = Updater.get().getBuildDate();
|
replay.version = Updater.get().getBuildDate();
|
||||||
replay.beatmapHash = ""; // TODO
|
replay.beatmapHash = Utils.getMD5(file.getFile());
|
||||||
replay.playerName = ""; // TODO
|
replay.playerName = ""; // TODO
|
||||||
replay.replayHash = Long.toString(System.currentTimeMillis()); // TODO
|
replay.replayHash = Long.toString(System.currentTimeMillis()); // TODO
|
||||||
replay.hit300 = (short) hitResultCount[HIT_300];
|
replay.hit300 = (short) hitResultCount[HIT_300];
|
||||||
|
|
|
@ -25,8 +25,10 @@ import itdelatrisu.opsu.downloads.DownloadNode;
|
||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
@ -34,6 +36,8 @@ import java.net.HttpURLConnection;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -537,4 +541,37 @@ public class Utils {
|
||||||
return s.useDelimiter("\\A").hasNext() ? s.next() : "";
|
return s.useDelimiter("\\A").hasNext() ? s.next() : "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the md5 hash of a file in hex form.
|
||||||
|
* @param file
|
||||||
|
* @return the md5 hash
|
||||||
|
*/
|
||||||
|
public static String getMD5(File file){
|
||||||
|
try {
|
||||||
|
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
int len = in.read(buf);
|
||||||
|
if (len < 0)
|
||||||
|
break;
|
||||||
|
md.update(buf, 0, len);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
byte[] md5byte = md.digest();
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (byte b : md5byte) {
|
||||||
|
result.append(String.format("%02x", b));
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
} catch (NoSuchAlgorithmException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.error(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,11 +132,10 @@ public class Circle implements HitObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mousePressed(int x, int y) {
|
public boolean mousePressed(int x, int y, int trackPosition) {
|
||||||
double distance = Math.hypot(this.x - x, this.y - y);
|
double distance = Math.hypot(this.x - x, this.y - y);
|
||||||
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||||
if (distance < circleRadius) {
|
if (distance < circleRadius) {
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
int timeDiff = trackPosition - hitObject.getTime();
|
int timeDiff = trackPosition - hitObject.getTime();
|
||||||
int result = hitResult(timeDiff);
|
int result = hitResult(timeDiff);
|
||||||
|
|
||||||
|
@ -150,10 +149,9 @@ public class Circle implements HitObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed) {
|
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
|
||||||
int time = hitObject.getTime();
|
int time = hitObject.getTime();
|
||||||
|
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
int[] hitResultOffset = game.getHitResultOffsets();
|
int[] hitResultOffset = game.getHitResultOffsets();
|
||||||
boolean isAutoMod = GameMod.AUTO.isActive();
|
boolean isAutoMod = GameMod.AUTO.isActive();
|
||||||
|
|
||||||
|
@ -176,7 +174,7 @@ public class Circle implements HitObject {
|
||||||
|
|
||||||
// "relax" mod: click automatically
|
// "relax" mod: click automatically
|
||||||
else if (GameMod.RELAX.isActive() && trackPosition >= time)
|
else if (GameMod.RELAX.isActive() && trackPosition >= time)
|
||||||
return mousePressed(mouseX, mouseY);
|
return mousePressed(mouseX, mouseY, trackPosition);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,17 +38,19 @@ public interface HitObject {
|
||||||
* @param mouseX the x coordinate of the mouse
|
* @param mouseX the x coordinate of the mouse
|
||||||
* @param mouseY the y coordinate of the mouse
|
* @param mouseY the y coordinate of the mouse
|
||||||
* @param keyPressed whether or not a game key is currently pressed
|
* @param keyPressed whether or not a game key is currently pressed
|
||||||
|
* @param trackPosition the track Position
|
||||||
* @return true if object ended
|
* @return true if object ended
|
||||||
*/
|
*/
|
||||||
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed);
|
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a mouse click.
|
* Processes a mouse click.
|
||||||
* @param x the x coordinate of the mouse
|
* @param x the x coordinate of the mouse
|
||||||
* @param y the y coordinate of the mouse
|
* @param y the y coordinate of the mouse
|
||||||
|
* @param trackPosition the track Position
|
||||||
* @return true if a hit result was processed
|
* @return true if a hit result was processed
|
||||||
*/
|
*/
|
||||||
public boolean mousePressed(int x, int y);
|
public boolean mousePressed(int x, int y, int trackPosition);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the coordinates of the hit object at a given track position.
|
* Returns the coordinates of the hit object at a given track position.
|
||||||
|
|
|
@ -24,13 +24,11 @@ import itdelatrisu.opsu.GameMod;
|
||||||
import itdelatrisu.opsu.OsuFile;
|
import itdelatrisu.opsu.OsuFile;
|
||||||
import itdelatrisu.opsu.OsuHitObject;
|
import itdelatrisu.opsu.OsuHitObject;
|
||||||
import itdelatrisu.opsu.Utils;
|
import itdelatrisu.opsu.Utils;
|
||||||
import itdelatrisu.opsu.audio.MusicController;
|
|
||||||
import itdelatrisu.opsu.objects.curves.CircumscribedCircle;
|
import itdelatrisu.opsu.objects.curves.CircumscribedCircle;
|
||||||
import itdelatrisu.opsu.objects.curves.Curve;
|
import itdelatrisu.opsu.objects.curves.Curve;
|
||||||
import itdelatrisu.opsu.objects.curves.LinearBezier;
|
import itdelatrisu.opsu.objects.curves.LinearBezier;
|
||||||
import itdelatrisu.opsu.states.Game;
|
import itdelatrisu.opsu.states.Game;
|
||||||
|
|
||||||
import org.newdawn.slick.Animation;
|
|
||||||
import org.newdawn.slick.Color;
|
import org.newdawn.slick.Color;
|
||||||
import org.newdawn.slick.GameContainer;
|
import org.newdawn.slick.GameContainer;
|
||||||
import org.newdawn.slick.Graphics;
|
import org.newdawn.slick.Graphics;
|
||||||
|
@ -41,7 +39,7 @@ import org.newdawn.slick.Image;
|
||||||
*/
|
*/
|
||||||
public class Slider implements HitObject {
|
public class Slider implements HitObject {
|
||||||
/** Slider ball animation. */
|
/** Slider ball animation. */
|
||||||
private static Animation sliderBall;
|
private static Image[] sliderBallImages;
|
||||||
|
|
||||||
/** Slider movement speed multiplier. */
|
/** Slider movement speed multiplier. */
|
||||||
private static float sliderMultiplier = 1.0f;
|
private static float sliderMultiplier = 1.0f;
|
||||||
|
@ -111,7 +109,6 @@ public class Slider implements HitObject {
|
||||||
diameter = (int) (diameter * OsuHitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
diameter = (int) (diameter * OsuHitObject.getXMultiplier()); // convert from Osupixels (640x480)
|
||||||
|
|
||||||
// slider ball
|
// slider ball
|
||||||
Image[] sliderBallImages;
|
|
||||||
if (GameImage.SLIDER_BALL.hasSkinImages() ||
|
if (GameImage.SLIDER_BALL.hasSkinImages() ||
|
||||||
(!GameImage.SLIDER_BALL.hasSkinImage() && GameImage.SLIDER_BALL.getImages() != null))
|
(!GameImage.SLIDER_BALL.hasSkinImage() && GameImage.SLIDER_BALL.getImages() != null))
|
||||||
sliderBallImages = GameImage.SLIDER_BALL.getImages();
|
sliderBallImages = GameImage.SLIDER_BALL.getImages();
|
||||||
|
@ -119,7 +116,6 @@ public class Slider implements HitObject {
|
||||||
sliderBallImages = new Image[]{ GameImage.SLIDER_BALL.getImage() };
|
sliderBallImages = new Image[]{ GameImage.SLIDER_BALL.getImage() };
|
||||||
for (int i = 0; i < sliderBallImages.length; i++)
|
for (int i = 0; i < sliderBallImages.length; i++)
|
||||||
sliderBallImages[i] = sliderBallImages[i].getScaledCopy(diameter * 118 / 128, diameter * 118 / 128);
|
sliderBallImages[i] = sliderBallImages[i].getScaledCopy(diameter * 118 / 128, diameter * 118 / 128);
|
||||||
sliderBall = new Animation(sliderBallImages, 30);
|
|
||||||
|
|
||||||
GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameter * 259 / 128, diameter * 259 / 128));
|
GameImage.SLIDER_FOLLOWCIRCLE.setImage(GameImage.SLIDER_FOLLOWCIRCLE.getImage().getScaledCopy(diameter * 259 / 128, diameter * 259 / 128));
|
||||||
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter));
|
GameImage.REVERSEARROW.setImage(GameImage.REVERSEARROW.getImage().getScaledCopy(diameter, diameter));
|
||||||
|
@ -202,7 +198,9 @@ public class Slider implements HitObject {
|
||||||
if (hitObject.getRepeatCount() - 1 > tcurRepeat) {
|
if (hitObject.getRepeatCount() - 1 > tcurRepeat) {
|
||||||
Image arrow = GameImage.REVERSEARROW.getImage();
|
Image arrow = GameImage.REVERSEARROW.getImage();
|
||||||
if (tcurRepeat != currentRepeats) {
|
if (tcurRepeat != currentRepeats) {
|
||||||
float t = getT(trackPosition, true);
|
if (sliderTime == 0)
|
||||||
|
continue;
|
||||||
|
float t = Math.max(getT(trackPosition, true), 0);
|
||||||
arrow.setAlpha((float) (t - Math.floor(t)));
|
arrow.setAlpha((float) (t - Math.floor(t)));
|
||||||
} else
|
} else
|
||||||
arrow.setAlpha(1f);
|
arrow.setAlpha(1f);
|
||||||
|
@ -218,22 +216,25 @@ public class Slider implements HitObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (timeDiff >= 0) {
|
if (timeDiff >= 0) {
|
||||||
// approach circle
|
// approach circle
|
||||||
color.a = 1 - scale;
|
color.a = 1 - scale;
|
||||||
GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
|
GameImage.APPROACHCIRCLE.getImage().getScaledCopy(approachScale).drawCentered(x, y, color);
|
||||||
} else {
|
} else {
|
||||||
|
//since update might not have run before drawing during replay,
|
||||||
|
//the slider time may not have been calculated.
|
||||||
|
//Which will cause NAN numbers and cause flicker.
|
||||||
|
if (sliderTime == 0)
|
||||||
|
return;
|
||||||
float[] c = curve.pointAt(getT(trackPosition, false));
|
float[] c = curve.pointAt(getT(trackPosition, false));
|
||||||
float[] c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);
|
float[] c2 = curve.pointAt(getT(trackPosition, false) + 0.01f);
|
||||||
|
|
||||||
// slider ball
|
float t = getT(trackPosition, false);
|
||||||
// TODO: deprecated method
|
//float dis = hitObject.getPixelLength()*OsuHitObject.getXMultiplier() * (t -(int)t);
|
||||||
// TODO 2: update the animation based on the distance traveled?
|
//Image sliderBallFrame = sliderBallImages[ (int)(dis/ (diameter*Math.PI) *30)%sliderBallImages.length];
|
||||||
sliderBall.updateNoDraw();
|
Image sliderBallFrame = sliderBallImages[(int) (t * sliderTime * 60 / 1000) % sliderBallImages.length];
|
||||||
Image sliderBallFrame = sliderBall.getCurrentFrame();
|
|
||||||
float angle = (float) (Math.atan2(c2[1] - c[1], c2[0] - c[0]) * 180 / Math.PI);
|
float angle = (float) (Math.atan2(c2[1] - c[1], c2[0] - c[0]) * 180 / Math.PI);
|
||||||
if (currentRepeats % 2 == 1)
|
|
||||||
angle += 180;
|
|
||||||
sliderBallFrame.setRotation(angle);
|
sliderBallFrame.setRotation(angle);
|
||||||
sliderBallFrame.drawCentered(c[0], c[1]);
|
sliderBallFrame.drawCentered(c[0], c[1]);
|
||||||
|
|
||||||
|
@ -283,14 +284,13 @@ public class Slider implements HitObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mousePressed(int x, int y) {
|
public boolean mousePressed(int x, int y, int trackPosition) {
|
||||||
if (sliderClickedInitial) // first circle already processed
|
if (sliderClickedInitial) // first circle already processed
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
double distance = Math.hypot(this.x - x, this.y - y);
|
double distance = Math.hypot(this.x - x, this.y - y);
|
||||||
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
int circleRadius = GameImage.HITCIRCLE.getImage().getWidth() / 2;
|
||||||
if (distance < circleRadius) {
|
if (distance < circleRadius) {
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
int timeDiff = Math.abs(trackPosition - hitObject.getTime());
|
||||||
int[] hitResultOffset = game.getHitResultOffsets();
|
int[] hitResultOffset = game.getHitResultOffsets();
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ public class Slider implements HitObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed) {
|
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
|
||||||
int repeatCount = hitObject.getRepeatCount();
|
int repeatCount = hitObject.getRepeatCount();
|
||||||
|
|
||||||
// slider time and tick calculations
|
// slider time and tick calculations
|
||||||
|
@ -334,7 +334,6 @@ public class Slider implements HitObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
int[] hitResultOffset = game.getHitResultOffsets();
|
int[] hitResultOffset = game.getHitResultOffsets();
|
||||||
boolean isAutoMod = GameMod.AUTO.isActive();
|
boolean isAutoMod = GameMod.AUTO.isActive();
|
||||||
|
|
||||||
|
@ -362,7 +361,7 @@ public class Slider implements HitObject {
|
||||||
|
|
||||||
// "relax" mod: click automatically
|
// "relax" mod: click automatically
|
||||||
else if (GameMod.RELAX.isActive() && trackPosition >= time)
|
else if (GameMod.RELAX.isActive() && trackPosition >= time)
|
||||||
mousePressed(mouseX, mouseY);
|
mousePressed(mouseX, mouseY, trackPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
// end of slider
|
// end of slider
|
||||||
|
|
|
@ -197,11 +197,10 @@ public class Spinner implements HitObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mousePressed(int x, int y) { return false; } // not used
|
public boolean mousePressed(int x, int y, int trackPosition) { return false; } // not used
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed) {
|
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
|
|
||||||
// end of spinner
|
// end of spinner
|
||||||
if (overlap || trackPosition > hitObject.getEndTime()) {
|
if (overlap || trackPosition > hitObject.getEndTime()) {
|
||||||
|
|
|
@ -165,24 +165,18 @@ public class Game extends BasicGameState {
|
||||||
/** The replay cursor coordinates. */
|
/** The replay cursor coordinates. */
|
||||||
private int replayX, replayY;
|
private int replayX, replayY;
|
||||||
|
|
||||||
/** The replay keys pressed. */
|
|
||||||
private int replayKeys;
|
|
||||||
|
|
||||||
/** Whether a replay key is currently pressed. */
|
/** Whether a replay key is currently pressed. */
|
||||||
private boolean replayKeyPressed;
|
private boolean replayKeyPressed;
|
||||||
|
|
||||||
/** The replay skip time, or -1 if none. */
|
/** The replay skip time, or -1 if none. */
|
||||||
private int replaySkipTime = -1;
|
private int replaySkipTime = -1;
|
||||||
|
|
||||||
/** The thread updating the replay frames. */
|
|
||||||
private Thread replayThread;
|
|
||||||
|
|
||||||
/** Whether or not the replay thread should continue running. */
|
|
||||||
private boolean replayThreadRunning;
|
|
||||||
|
|
||||||
/** The last replay frame time. */
|
/** The last replay frame time. */
|
||||||
private int lastReplayTime = 0;
|
private int lastReplayTime = 0;
|
||||||
|
|
||||||
|
/** The keys from the previous replayFrame */
|
||||||
|
private int lastReplayKeys = 0;
|
||||||
|
|
||||||
/** The last game keys pressed. */
|
/** The last game keys pressed. */
|
||||||
private int lastKeysPressed = ReplayFrame.KEY_NONE;
|
private int lastKeysPressed = ReplayFrame.KEY_NONE;
|
||||||
|
|
||||||
|
@ -517,14 +511,15 @@ public class Game extends BasicGameState {
|
||||||
cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY);
|
cursorCirclePulse.drawCentered(pausedMouseX, pausedMouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMod.AUTO.isActive())
|
if (isReplay)
|
||||||
|
UI.draw(g, replayX, replayY, replayKeyPressed);
|
||||||
|
else if (GameMod.AUTO.isActive())
|
||||||
UI.draw(g, autoMouseX, autoMouseY, autoMousePressed);
|
UI.draw(g, autoMouseX, autoMouseY, autoMousePressed);
|
||||||
else if (GameMod.AUTOPILOT.isActive())
|
else if (GameMod.AUTOPILOT.isActive())
|
||||||
UI.draw(g, autoMouseX, autoMouseY, Utils.isGameKeyPressed());
|
UI.draw(g, autoMouseX, autoMouseY, Utils.isGameKeyPressed());
|
||||||
else if (!isReplay)
|
|
||||||
UI.draw(g);
|
|
||||||
else
|
else
|
||||||
UI.draw(g, replayX, replayY, replayKeyPressed);
|
UI.draw(g);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -532,18 +527,41 @@ public class Game extends BasicGameState {
|
||||||
throws SlickException {
|
throws SlickException {
|
||||||
UI.update(delta);
|
UI.update(delta);
|
||||||
int mouseX, mouseY;
|
int mouseX, mouseY;
|
||||||
if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
|
|
||||||
mouseX = autoMouseX;
|
|
||||||
mouseY = autoMouseY;
|
|
||||||
} else if (!isReplay) {
|
|
||||||
mouseX = input.getMouseX();
|
mouseX = input.getMouseX();
|
||||||
mouseY = input.getMouseY();
|
mouseY = input.getMouseY();
|
||||||
|
if (isLeadIn()) { // stop updating during song lead-in
|
||||||
|
leadInTime -= delta;
|
||||||
|
if (!isLeadIn())
|
||||||
|
MusicController.resume();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//hover updates only the real mouse position
|
||||||
|
//but doesn't hover the replays
|
||||||
|
skipButton.hoverUpdate(delta, mouseX, mouseY);
|
||||||
|
|
||||||
|
|
||||||
|
int trackPosition = MusicController.getPosition();
|
||||||
|
if (!isReplay) {
|
||||||
|
addReplayFrameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
|
||||||
} else {
|
} else {
|
||||||
|
//out of frames, use previous data
|
||||||
|
if (replayIndex >= replay.frames.length){
|
||||||
|
updateGame(replayX, replayY, delta, MusicController.getPosition(), lastKeysPressed);
|
||||||
|
}
|
||||||
|
while (replayIndex < replay.frames.length && trackPosition >= replay.frames[replayIndex].getTime()) {
|
||||||
|
ReplayFrame frame = replay.frames[replayIndex];
|
||||||
|
replayX = frame.getScaledX();
|
||||||
|
replayY = frame.getScaledY();
|
||||||
|
replayKeyPressed = frame.isKeyPressed();
|
||||||
|
lastKeysPressed = frame.getKeys();
|
||||||
|
runReplayFrame(frame);
|
||||||
|
|
||||||
|
replayIndex++;
|
||||||
|
}
|
||||||
mouseX = replayX;
|
mouseX = replayX;
|
||||||
mouseY = replayY;
|
mouseY = replayY;
|
||||||
}
|
}
|
||||||
skipButton.hoverUpdate(delta, mouseX, mouseY);
|
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
|
|
||||||
// "flashlight" mod: calculate visible area radius
|
// "flashlight" mod: calculate visible area radius
|
||||||
if (GameMod.FLASHLIGHT.isActive()) {
|
if (GameMod.FLASHLIGHT.isActive()) {
|
||||||
|
@ -600,12 +618,6 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLeadIn()) { // stop updating during song lead-in
|
|
||||||
leadInTime -= delta;
|
|
||||||
if (!isLeadIn())
|
|
||||||
MusicController.resume();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returning from pause screen: must click previous mouse position
|
// returning from pause screen: must click previous mouse position
|
||||||
if (pauseTime > -1) {
|
if (pauseTime > -1) {
|
||||||
|
@ -632,6 +644,42 @@ public class Game extends BasicGameState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.updateDisplays(delta);
|
||||||
|
|
||||||
|
// replays
|
||||||
|
if (isReplay) {
|
||||||
|
// skip intro
|
||||||
|
if (replaySkipTime > 0 && trackPosition > replaySkipTime) {
|
||||||
|
skipIntro();
|
||||||
|
replaySkipTime = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pause game if focus lost
|
||||||
|
if (!container.hasFocus() && !GameMod.AUTO.isActive() && !isReplay) {
|
||||||
|
if (pauseTime < 0) {
|
||||||
|
pausedMouseX = mouseX;
|
||||||
|
pausedMouseY = mouseY;
|
||||||
|
pausePulse = 0f;
|
||||||
|
}
|
||||||
|
if (MusicController.isPlaying() || isLeadIn())
|
||||||
|
pauseTime = trackPosition;
|
||||||
|
game.enterState(Opsu.STATE_GAMEPAUSEMENU);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the game
|
||||||
|
* @param mouseX the mouse x position
|
||||||
|
* @param mouseY
|
||||||
|
* @param delta
|
||||||
|
* @param trackPosition the track position
|
||||||
|
* @param keysPressed the keys that are pressed
|
||||||
|
*/
|
||||||
|
private void updateGame(int mouseX, int mouseY, int delta, int trackPosition, int keysPressed) {
|
||||||
// "Easy" mod: multiple "lives"
|
// "Easy" mod: multiple "lives"
|
||||||
if (GameMod.EASY.isActive() && deathTime > -1) {
|
if (GameMod.EASY.isActive() && deathTime > -1) {
|
||||||
if (data.getHealth() < 99f)
|
if (data.getHealth() < 99f)
|
||||||
|
@ -642,13 +690,12 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.updateDisplays(delta);
|
|
||||||
|
|
||||||
// map complete!
|
// map complete!
|
||||||
if (objectIndex >= hitObjects.length || (MusicController.trackEnded() && objectIndex > 0)) {
|
if (objectIndex >= hitObjects.length || (MusicController.trackEnded() && objectIndex > 0)) {
|
||||||
// track ended before last object was processed: force a hit result
|
// track ended before last object was processed: force a hit result
|
||||||
if (MusicController.trackEnded() && objectIndex < hitObjects.length)
|
if (MusicController.trackEnded() && objectIndex < hitObjects.length)
|
||||||
hitObjects[objectIndex].update(true, delta, mouseX, mouseY, false);
|
hitObjects[objectIndex].update(true, delta, mouseX, mouseY, false, trackPosition);
|
||||||
|
|
||||||
// if checkpoint used, skip ranking screen
|
// if checkpoint used, skip ranking screen
|
||||||
if (checkpointLoaded)
|
if (checkpointLoaded)
|
||||||
|
@ -666,7 +713,7 @@ public class Game extends BasicGameState {
|
||||||
replayFrames.getFirst().setTimeDiff(replaySkipTime * -1);
|
replayFrames.getFirst().setTimeDiff(replaySkipTime * -1);
|
||||||
replayFrames.addFirst(ReplayFrame.getStartFrame(replaySkipTime));
|
replayFrames.addFirst(ReplayFrame.getStartFrame(replaySkipTime));
|
||||||
replayFrames.addFirst(ReplayFrame.getStartFrame(0));
|
replayFrames.addFirst(ReplayFrame.getStartFrame(0));
|
||||||
Replay r = data.getReplay(replayFrames.toArray(new ReplayFrame[replayFrames.size()]));
|
Replay r = data.getReplay(replayFrames.toArray(new ReplayFrame[replayFrames.size()]), osu);
|
||||||
if (r != null && !unranked)
|
if (r != null && !unranked)
|
||||||
r.save();
|
r.save();
|
||||||
}
|
}
|
||||||
|
@ -695,15 +742,6 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// replays
|
|
||||||
if (isReplay) {
|
|
||||||
// skip intro
|
|
||||||
if (replaySkipTime > 0 && trackPosition > replaySkipTime) {
|
|
||||||
skipIntro();
|
|
||||||
replaySkipTime = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// song beginning
|
// song beginning
|
||||||
if (objectIndex == 0 && trackPosition < osu.objects[0].getTime())
|
if (objectIndex == 0 && trackPosition < osu.objects[0].getTime())
|
||||||
return; // nothing to do here
|
return; // nothing to do here
|
||||||
|
@ -728,18 +766,6 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pause game if focus lost
|
|
||||||
if (!container.hasFocus() && !GameMod.AUTO.isActive() && !isReplay) {
|
|
||||||
if (pauseTime < 0) {
|
|
||||||
pausedMouseX = mouseX;
|
|
||||||
pausedMouseY = mouseY;
|
|
||||||
pausePulse = 0f;
|
|
||||||
}
|
|
||||||
if (MusicController.isPlaying() || isLeadIn())
|
|
||||||
pauseTime = trackPosition;
|
|
||||||
game.enterState(Opsu.STATE_GAMEPAUSEMENU);
|
|
||||||
}
|
|
||||||
|
|
||||||
// drain health
|
// drain health
|
||||||
data.changeHealth(delta * -1 * GameData.HP_DRAIN_MULTIPLIER);
|
data.changeHealth(delta * -1 * GameData.HP_DRAIN_MULTIPLIER);
|
||||||
if (!data.isAlive()) {
|
if (!data.isAlive()) {
|
||||||
|
@ -761,14 +787,14 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update objects (loop in unlikely event of any skipped indexes)
|
// update objects (loop in unlikely event of any skipped indexes)
|
||||||
boolean keyPressed = (isReplay) ? replayKeyPressed : Utils.isGameKeyPressed();
|
boolean keyPressed = keysPressed != ReplayFrame.KEY_NONE;
|
||||||
while (objectIndex < hitObjects.length && trackPosition > osu.objects[objectIndex].getTime()) {
|
while (objectIndex < hitObjects.length && trackPosition > osu.objects[objectIndex].getTime()) {
|
||||||
// check if we've already passed the next object's start time
|
// check if we've already passed the next object's start time
|
||||||
boolean overlap = (objectIndex + 1 < hitObjects.length &&
|
boolean overlap = (objectIndex + 1 < hitObjects.length &&
|
||||||
trackPosition > osu.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_300]);
|
trackPosition > osu.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_300]);
|
||||||
|
|
||||||
// update hit object and check completion status
|
// update hit object and check completion status
|
||||||
if (hitObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed))
|
if (hitObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition))
|
||||||
objectIndex++; // done, so increment object index
|
objectIndex++; // done, so increment object index
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
@ -783,11 +809,15 @@ public class Game extends BasicGameState {
|
||||||
int trackPosition = MusicController.getPosition();
|
int trackPosition = MusicController.getPosition();
|
||||||
|
|
||||||
// game keys
|
// game keys
|
||||||
if (!Keyboard.isRepeatEvent() && !isReplay) {
|
int mouseX = input.getMouseX();
|
||||||
|
int mouseY = input.getMouseY();
|
||||||
|
if (!Keyboard.isRepeatEvent()) {
|
||||||
|
int keys = 0;
|
||||||
if (key == Options.getGameKeyLeft())
|
if (key == Options.getGameKeyLeft())
|
||||||
gameKeyPressed(ReplayFrame.KEY_K1, input.getMouseX(), input.getMouseY());
|
keys = ReplayFrame.KEY_K1;
|
||||||
else if (key == Options.getGameKeyRight())
|
else if (key == Options.getGameKeyRight())
|
||||||
gameKeyPressed(ReplayFrame.KEY_K2, input.getMouseX(), input.getMouseY());
|
keys = ReplayFrame.KEY_K2;
|
||||||
|
gameKeyPressed(keys, mouseX, mouseY, trackPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
@ -800,8 +830,8 @@ public class Game extends BasicGameState {
|
||||||
|
|
||||||
// pause game
|
// pause game
|
||||||
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= osu.objects[0].getTime()) {
|
if (pauseTime < 0 && breakTime <= 0 && trackPosition >= osu.objects[0].getTime()) {
|
||||||
pausedMouseX = input.getMouseX();
|
pausedMouseX = mouseX;
|
||||||
pausedMouseY = input.getMouseY();
|
pausedMouseY = mouseY;
|
||||||
pausePulse = 0f;
|
pausePulse = 0f;
|
||||||
}
|
}
|
||||||
if (MusicController.isPlaying() || isLeadIn())
|
if (MusicController.isPlaying() || isLeadIn())
|
||||||
|
@ -846,7 +876,6 @@ public class Game extends BasicGameState {
|
||||||
if (checkpoint == 0 || checkpoint > osu.endTime)
|
if (checkpoint == 0 || checkpoint > osu.endTime)
|
||||||
break; // invalid checkpoint
|
break; // invalid checkpoint
|
||||||
try {
|
try {
|
||||||
killReplayThread();
|
|
||||||
restart = Restart.MANUAL;
|
restart = Restart.MANUAL;
|
||||||
enter(container, game);
|
enter(container, game);
|
||||||
checkpointLoaded = true;
|
checkpointLoaded = true;
|
||||||
|
@ -863,6 +892,7 @@ public class Game extends BasicGameState {
|
||||||
osu.objects[objectIndex++].getTime() <= checkpoint)
|
osu.objects[objectIndex++].getTime() <= checkpoint)
|
||||||
;
|
;
|
||||||
objectIndex--;
|
objectIndex--;
|
||||||
|
lastReplayTime = osu.objects[objectIndex].getTime();
|
||||||
} catch (SlickException e) {
|
} catch (SlickException e) {
|
||||||
ErrorHandler.error("Failed to load checkpoint.", e, false);
|
ErrorHandler.error("Failed to load checkpoint.", e, false);
|
||||||
}
|
}
|
||||||
|
@ -913,7 +943,15 @@ public class Game extends BasicGameState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gameKeyPressed((button == Input.MOUSE_LEFT_BUTTON) ? ReplayFrame.KEY_M1 : ReplayFrame.KEY_M2, x, y);
|
|
||||||
|
int keys = 0;
|
||||||
|
if (button == Input.MOUSE_LEFT_BUTTON)
|
||||||
|
keys = ReplayFrame.KEY_M1;
|
||||||
|
else if (button == Input.MOUSE_RIGHT_BUTTON)
|
||||||
|
keys = ReplayFrame.KEY_M2;
|
||||||
|
|
||||||
|
gameKeyPressed(keys, x, y, MusicController.getPosition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -921,8 +959,9 @@ public class Game extends BasicGameState {
|
||||||
* @param keys the game keys pressed
|
* @param keys the game keys pressed
|
||||||
* @param x the mouse x coordinate
|
* @param x the mouse x coordinate
|
||||||
* @param y the mouse y coordinate
|
* @param y the mouse y coordinate
|
||||||
|
* @param trackPosition the track Position
|
||||||
*/
|
*/
|
||||||
private void gameKeyPressed(int keys, int x, int y) {
|
private void gameKeyPressed(int keys, int x, int y, int trackPosition) {
|
||||||
// returning from pause screen
|
// returning from pause screen
|
||||||
if (pauseTime > -1) {
|
if (pauseTime > -1) {
|
||||||
double distance = Math.hypot(pausedMouseX - x, pausedMouseY - y);
|
double distance = Math.hypot(pausedMouseX - x, pausedMouseY - y);
|
||||||
|
@ -938,42 +977,18 @@ public class Game extends BasicGameState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectIndex >= hitObjects.length) // nothing left to do here
|
|
||||||
return;
|
|
||||||
|
|
||||||
OsuHitObject hitObject = osu.objects[objectIndex];
|
|
||||||
|
|
||||||
// skip beginning
|
// skip beginning
|
||||||
if (skipButton.contains(x, y)) {
|
if (skipButton.contains(x, y)) {
|
||||||
if (skipIntro())
|
if (skipIntro())
|
||||||
return; // successfully skipped
|
return; // successfully skipped
|
||||||
}
|
}
|
||||||
|
|
||||||
// "auto" and "relax" mods: ignore user actions
|
if(!isReplay && keys > 0) {
|
||||||
if (GameMod.AUTO.isActive() || GameMod.RELAX.isActive())
|
lastKeysPressed |= keys; //sets keys bits
|
||||||
return;
|
addReplayFrameAndRun(x, y, lastKeysPressed, trackPosition);
|
||||||
|
}
|
||||||
// "autopilot" mod: ignore actual cursor coordinates
|
|
||||||
int cx, cy;
|
|
||||||
if (GameMod.AUTOPILOT.isActive()) {
|
|
||||||
cx = autoMouseX;
|
|
||||||
cy = autoMouseY;
|
|
||||||
} else {
|
|
||||||
cx = x;
|
|
||||||
cy = y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isReplay)
|
|
||||||
addReplayFrame(cx, cy, lastKeysPressed | keys);
|
|
||||||
|
|
||||||
// circles
|
|
||||||
if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(cx, cy))
|
|
||||||
objectIndex++; // circle hit
|
|
||||||
|
|
||||||
// sliders
|
|
||||||
else if (hitObject.isSlider())
|
|
||||||
hitObjects[objectIndex].mousePressed(cx, cy);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(int button, int x, int y) {
|
public void mouseReleased(int button, int x, int y) {
|
||||||
|
@ -983,26 +998,44 @@ public class Game extends BasicGameState {
|
||||||
if (button == Input.MOUSE_MIDDLE_BUTTON)
|
if (button == Input.MOUSE_MIDDLE_BUTTON)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!isReplay && lastKeysPressed != ReplayFrame.KEY_NONE)
|
int keys = 0;
|
||||||
addReplayFrame(x, y, ReplayFrame.KEY_NONE);
|
if (button == Input.MOUSE_LEFT_BUTTON)
|
||||||
|
keys = ReplayFrame.KEY_M1;
|
||||||
|
else if (button == Input.MOUSE_RIGHT_BUTTON)
|
||||||
|
keys = ReplayFrame.KEY_M2;
|
||||||
|
gameKeyReleased(keys, x, y, MusicController.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(int key, char c) {
|
public void keyReleased(int key, char c) {
|
||||||
if (!isReplay && lastKeysPressed != ReplayFrame.KEY_NONE && (key == Options.getGameKeyLeft() || key == Options.getGameKeyRight()))
|
int keys = 0;
|
||||||
addReplayFrame(input.getMouseX(), input.getMouseY(), ReplayFrame.KEY_NONE);
|
if (key == Options.getGameKeyLeft())
|
||||||
|
keys = ReplayFrame.KEY_K1;
|
||||||
|
else if (key == Options.getGameKeyRight())
|
||||||
|
keys = ReplayFrame.KEY_K2;
|
||||||
|
gameKeyReleased(keys, input.getMouseX(), input.getMouseY(), MusicController.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a game key Released event.
|
||||||
|
* @param keys the game keys released
|
||||||
|
* @param x the mouse x coordinate
|
||||||
|
* @param y the mouse y coordinate
|
||||||
|
* @param trackPosition the track Position
|
||||||
|
*/
|
||||||
|
private void gameKeyReleased(int keys, int x, int y, int trackPosition) {
|
||||||
|
if (!isReplay && keys > 0) {
|
||||||
|
lastKeysPressed &= ~keys; //clears keys bits
|
||||||
|
addReplayFrameAndRun(x, y, lastKeysPressed, trackPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseMoved(int oldx, int oldy, int newx, int newy) {
|
public void mouseMoved(int oldx, int oldy, int newx, int newy) {
|
||||||
if (!isReplay)
|
|
||||||
addReplayFrame(newx, newy, lastKeysPressed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseDragged(int oldx, int oldy, int newx, int newy) {
|
public void mouseDragged(int oldx, int oldy, int newx, int newy) {
|
||||||
if (!isReplay)
|
|
||||||
addReplayFrame(newx, newy, lastKeysPressed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1078,6 +1111,7 @@ public class Game extends BasicGameState {
|
||||||
if (GameMod.AUTO.isActive() || isReplay)
|
if (GameMod.AUTO.isActive() || isReplay)
|
||||||
UI.showCursor();
|
UI.showCursor();
|
||||||
|
|
||||||
|
lastReplayTime = 0;
|
||||||
// load replay frames
|
// load replay frames
|
||||||
if (isReplay) {
|
if (isReplay) {
|
||||||
// load mods
|
// load mods
|
||||||
|
@ -1087,7 +1121,6 @@ public class Game extends BasicGameState {
|
||||||
// load initial data
|
// load initial data
|
||||||
replayX = container.getWidth() / 2;
|
replayX = container.getWidth() / 2;
|
||||||
replayY = container.getHeight() / 2;
|
replayY = container.getHeight() / 2;
|
||||||
replayKeys = ReplayFrame.KEY_NONE;
|
|
||||||
replayKeyPressed = false;
|
replayKeyPressed = false;
|
||||||
replaySkipTime = -1;
|
replaySkipTime = -1;
|
||||||
for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) {
|
for (replayIndex = 0; replayIndex < replay.frames.length; replayIndex++) {
|
||||||
|
@ -1098,56 +1131,14 @@ public class Game extends BasicGameState {
|
||||||
} else if (frame.getTime() == 0) {
|
} else if (frame.getTime() == 0) {
|
||||||
replayX = frame.getScaledX();
|
replayX = frame.getScaledX();
|
||||||
replayY = frame.getScaledY();
|
replayY = frame.getScaledY();
|
||||||
replayKeys = frame.getKeys();
|
|
||||||
replayKeyPressed = frame.isKeyPressed();
|
replayKeyPressed = frame.isKeyPressed();
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// run frame updates in another thread
|
|
||||||
killReplayThread();
|
|
||||||
replayThread = new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (replayThreadRunning) {
|
|
||||||
// update frames
|
|
||||||
int trackPosition = MusicController.getPosition();
|
|
||||||
while (replayIndex < replay.frames.length && trackPosition >= replay.frames[replayIndex].getTime()) {
|
|
||||||
ReplayFrame frame = replay.frames[replayIndex];
|
|
||||||
replayX = frame.getScaledX();
|
|
||||||
replayY = frame.getScaledY();
|
|
||||||
replayKeyPressed = frame.isKeyPressed();
|
|
||||||
int keys = frame.getKeys();
|
|
||||||
if (replayKeyPressed && keys != replayKeys) // send a key press
|
|
||||||
gameKeyPressed(frame.getKeys(), replayX, replayY);
|
|
||||||
replayKeys = keys;
|
|
||||||
replayIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// out of frames
|
|
||||||
if (replayIndex >= replay.frames.length)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// sleep execution
|
|
||||||
try {
|
|
||||||
int diff = replay.frames[replayIndex].getTime() - trackPosition - 1;
|
|
||||||
if (diff < 1)
|
|
||||||
Thread.sleep(0, 256000);
|
|
||||||
else
|
|
||||||
Thread.sleep(diff);
|
|
||||||
} catch (InterruptedException e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!GameMod.AUTO.isActive()) { // "auto" mod: ignore replay frames
|
|
||||||
replayThreadRunning = true;
|
|
||||||
replayThread.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize replay-recording structures
|
// initialize replay-recording structures
|
||||||
else {
|
else {
|
||||||
lastReplayTime = 0;
|
|
||||||
lastKeysPressed = ReplayFrame.KEY_NONE;
|
lastKeysPressed = ReplayFrame.KEY_NONE;
|
||||||
replaySkipTime = -1;
|
replaySkipTime = -1;
|
||||||
replayFrames = new LinkedList<ReplayFrame>();
|
replayFrames = new LinkedList<ReplayFrame>();
|
||||||
|
@ -1173,7 +1164,6 @@ public class Game extends BasicGameState {
|
||||||
// replays
|
// replays
|
||||||
if (isReplay) {
|
if (isReplay) {
|
||||||
GameMod.loadModState(previousMods);
|
GameMod.loadModState(previousMods);
|
||||||
killReplayThread();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1318,10 +1308,9 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
MusicController.setPosition(firstObjectTime - SKIP_OFFSET);
|
MusicController.setPosition(firstObjectTime - SKIP_OFFSET);
|
||||||
replaySkipTime = (isReplay) ? -1 : trackPosition;
|
replaySkipTime = (isReplay) ? -1 : trackPosition;
|
||||||
if (replayThread != null && replayThread.isAlive()) {
|
if (isReplay) {
|
||||||
replayX = (int) skipButton.getX();
|
replayX = (int) skipButton.getX();
|
||||||
replayY = (int) skipButton.getY();
|
replayY = (int) skipButton.getY();
|
||||||
replayThread.interrupt();
|
|
||||||
}
|
}
|
||||||
SoundController.playSound(SoundEffect.MENUHIT);
|
SoundController.playSound(SoundEffect.MENUHIT);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1451,16 +1440,6 @@ public class Game extends BasicGameState {
|
||||||
*/
|
*/
|
||||||
public float getTimingPointMultiplier() { return beatLength / beatLengthBase; }
|
public float getTimingPointMultiplier() { return beatLength / beatLengthBase; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Kills the running replay updating thread, if any.
|
|
||||||
*/
|
|
||||||
private void killReplayThread() {
|
|
||||||
if (replayThread != null && replayThread.isAlive()) {
|
|
||||||
replayThreadRunning = false;
|
|
||||||
replayThread.interrupt();
|
|
||||||
}
|
|
||||||
replayThread = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a replay to view, or resets the replay if null.
|
* Sets a replay to view, or resets the replay if null.
|
||||||
|
@ -1481,19 +1460,81 @@ public class Game extends BasicGameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a replay frame to the list.
|
* Adds a replay frame to the list if able and runs it.
|
||||||
* @param x the cursor x coordinate
|
* @param x the cursor x coordinate
|
||||||
* @param y the cursor y coordinate
|
* @param y the cursor y coordinate
|
||||||
* @param keys the keys pressed
|
* @param keys the keys pressed
|
||||||
|
* @param time the time of the replay Frame
|
||||||
*/
|
*/
|
||||||
private void addReplayFrame(int x, int y, int keys) {
|
public synchronized void addReplayFrameAndRun(int x, int y, int keys, int time){
|
||||||
int time = MusicController.getPosition();
|
if (GameMod.AUTO.isActive() || GameMod.AUTOPILOT.isActive()) {
|
||||||
|
x = autoMouseX;
|
||||||
|
y = autoMouseY;
|
||||||
|
}
|
||||||
|
ReplayFrame frame = addReplayFrame(x, y, keys, time);
|
||||||
|
if(frame != null)
|
||||||
|
runReplayFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a replay Frame
|
||||||
|
* @param frame the frame to run
|
||||||
|
*/
|
||||||
|
private void runReplayFrame(ReplayFrame frame){
|
||||||
|
int keys = frame.getKeys();
|
||||||
|
int replayX = frame.getScaledX();
|
||||||
|
int replayY = frame.getScaledY();
|
||||||
|
int deltaKeys = (keys & ~lastReplayKeys ); //keys that turned on
|
||||||
|
if (deltaKeys > 0) { // send a key press
|
||||||
|
updateGameKeyPress(deltaKeys, replayX, replayY, frame.getTime());
|
||||||
|
} else if(keys != lastReplayKeys){
|
||||||
|
} else {
|
||||||
|
updateGame(replayX, replayY, frame.getTimeDiff(), frame.getTime(), keys);
|
||||||
|
}
|
||||||
|
lastReplayKeys = keys;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the games mouse pressed
|
||||||
|
* @param mouseX the mouse x position
|
||||||
|
* @param mouseY
|
||||||
|
* @param trackPosition the track position
|
||||||
|
* @param keysPressed the keys that are pressed
|
||||||
|
*/
|
||||||
|
private void updateGameKeyPress(int keys, int x, int y, int trackPosition) {
|
||||||
|
if (objectIndex >= hitObjects.length) // nothing left to do here
|
||||||
|
return;
|
||||||
|
|
||||||
|
OsuHitObject hitObject = osu.objects[objectIndex];
|
||||||
|
|
||||||
|
// circles
|
||||||
|
if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(x, y, trackPosition))
|
||||||
|
objectIndex++; // circle hit
|
||||||
|
|
||||||
|
// sliders
|
||||||
|
else if (hitObject.isSlider())
|
||||||
|
hitObjects[objectIndex].mousePressed(x, y, trackPosition);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a replay frame to the list if able.
|
||||||
|
* @param x the cursor x coordinate
|
||||||
|
* @param y the cursor y coordinate
|
||||||
|
* @param keys the keys pressed
|
||||||
|
* @param time the time of the replay Frame
|
||||||
|
* @return a Replay Frame representing the data
|
||||||
|
*/
|
||||||
|
private ReplayFrame addReplayFrame(int x, int y, int keys, int time) {
|
||||||
int timeDiff = time - lastReplayTime;
|
int timeDiff = time - lastReplayTime;
|
||||||
lastReplayTime = time;
|
lastReplayTime = time;
|
||||||
lastKeysPressed = keys;
|
|
||||||
int cx = (int) ((x - OsuHitObject.getXOffset()) / OsuHitObject.getXMultiplier());
|
int cx = (int) ((x - OsuHitObject.getXOffset()) / OsuHitObject.getXMultiplier());
|
||||||
int cy = (int) ((y - OsuHitObject.getYOffset()) / OsuHitObject.getYMultiplier());
|
int cy = (int) ((y - OsuHitObject.getYOffset()) / OsuHitObject.getYMultiplier());
|
||||||
replayFrames.add(new ReplayFrame(timeDiff, time, cx, cy, lastKeysPressed));
|
ReplayFrame tFrame = new ReplayFrame(timeDiff, time, cx, cy, keys);
|
||||||
|
if(replayFrames != null)
|
||||||
|
replayFrames.add(tFrame);
|
||||||
|
return tFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -170,7 +170,7 @@ public class GameRanking extends BasicGameState {
|
||||||
Game gameState = (Game) game.getState(Opsu.STATE_GAME);
|
Game gameState = (Game) game.getState(Opsu.STATE_GAME);
|
||||||
boolean returnToGame = false;
|
boolean returnToGame = false;
|
||||||
if (replayButton.contains(x, y)) {
|
if (replayButton.contains(x, y)) {
|
||||||
Replay r = data.getReplay(null);
|
Replay r = data.getReplay(null, null);
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
try {
|
try {
|
||||||
r.load();
|
r.load();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user