ReplayTest

Seems to work
but still buggy
lots of flickering during replay
This commit is contained in:
fd 2015-03-15 14:15:34 -04:00
parent f7c627e8a2
commit 60f2a9f142
5 changed files with 146 additions and 58 deletions

View File

@ -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;
} }

View File

@ -38,15 +38,17 @@ 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 TODO
* @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 TODO
* @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);
} }

View File

@ -267,14 +267,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();
@ -297,7 +296,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
@ -318,7 +317,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();
@ -346,7 +344,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

View File

@ -191,11 +191,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()) {

View File

@ -46,6 +46,8 @@ import itdelatrisu.opsu.replay.Replay;
import itdelatrisu.opsu.replay.ReplayFrame; import itdelatrisu.opsu.replay.ReplayFrame;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Stack; import java.util.Stack;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -199,6 +201,8 @@ public class Game extends BasicGameState {
private Input input; private Input input;
private int state; private int state;
private PrintWriter replayLog;
public Game(int state) { public Game(int state) {
this.state = state; this.state = state;
} }
@ -425,22 +429,43 @@ public class Game extends BasicGameState {
public void update(GameContainer container, StateBasedGame game, int delta) public void update(GameContainer container, StateBasedGame game, int delta)
throws SlickException { throws SlickException {
UI.update(delta); UI.update(delta);
int mouseX, mouseY; int mouseX, mouseY;
if (!isReplay) {
mouseX = input.getMouseX();
mouseY = input.getMouseY();
} else {
mouseX = replayX;
mouseY = replayY;
}
skipButton.hoverUpdate(delta, mouseX, mouseY);
if (isLeadIn()) { // stop updating during song lead-in if (isLeadIn()) { // stop updating during song lead-in
leadInTime -= delta; leadInTime -= delta;
if (!isLeadIn()) if (!isLeadIn())
MusicController.resume(); MusicController.resume();
return; return;
} }
int trackPosition = MusicController.getPosition();
if (!isReplay) {
mouseX = input.getMouseX();
mouseY = input.getMouseY();
frameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
} else {
//if(trackPosition<5000)
// MusicController.setPosition(85000);
while (replayIndex < replay.frames.length && trackPosition >= replay.frames[replayIndex].getTime()) {
ReplayFrame frame = replay.frames[replayIndex];
runFrame(frame);
replayX = frame.getScaledX();
replayY = frame.getScaledY();
replayIndex++;
}
System.out.println("MCP "+MusicController.getPosition());
mouseX = replayX;
mouseY = replayY;
if (replayIndex >= replay.frames.length){
updateGame(replayX, replayY, delta, MusicController.getPosition(), lastKeysPressed);
}
}
}
public void updateGame(int mouseX, int mouseY, int delta, int trackPosition, int keysPressed){
//if (!isReplay)
// addReplayFrame(mouseX, mouseY, keysPressed, trackPosition);
skipButton.hoverUpdate(delta, mouseX, mouseY);
// returning from pause screen: must click previous mouse position // returning from pause screen: must click previous mouse position
if (pauseTime > -1) { if (pauseTime > -1) {
@ -483,7 +508,7 @@ public class Game extends BasicGameState {
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)
@ -515,8 +540,6 @@ public class Game extends BasicGameState {
return; return;
} }
int trackPosition = MusicController.getPosition();
// timing points // timing points
if (timingPointIndex < osu.timingPoints.size()) { if (timingPointIndex < osu.timingPoints.size()) {
OsuTimingPoint timingPoint = osu.timingPoints.get(timingPointIndex); OsuTimingPoint timingPoint = osu.timingPoints.get(timingPointIndex);
@ -597,14 +620,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;//(isReplay) ? replayKeyPressed : Utils.isGameKeyPressed();
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;
@ -619,11 +642,17 @@ public class Game extends BasicGameState {
int trackPosition = MusicController.getPosition(); int trackPosition = MusicController.getPosition();
// game keys // game keys
int mouseX = input.getMouseX();
int mouseY = input.getMouseY();
if (!Keyboard.isRepeatEvent() && !isReplay) { if (!Keyboard.isRepeatEvent() && !isReplay) {
if (key == Options.getGameKeyLeft()) if (key == Options.getGameKeyLeft()){
gameKeyPressed(ReplayFrame.KEY_K1, input.getMouseX(), input.getMouseY()); lastKeysPressed |= ReplayFrame.KEY_K1;
else if (key == Options.getGameKeyRight()) frameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
gameKeyPressed(ReplayFrame.KEY_K2, input.getMouseX(), input.getMouseY()); }
else if (key == Options.getGameKeyRight()){
lastKeysPressed |= ReplayFrame.KEY_K2;
frameAndRun(mouseX, mouseY, lastKeysPressed, trackPosition);
}
} }
switch (key) { switch (key) {
@ -636,8 +665,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())
@ -749,7 +778,8 @@ public class Game extends BasicGameState {
return; return;
} }
gameKeyPressed((button == Input.MOUSE_LEFT_BUTTON) ? ReplayFrame.KEY_M1 : ReplayFrame.KEY_M2, x, y); lastKeysPressed |= (button == Input.MOUSE_LEFT_BUTTON) ? ReplayFrame.KEY_M1 : ReplayFrame.KEY_M2;
frameAndRun(x, y, lastKeysPressed, MusicController.getPosition());
} }
/** /**
@ -757,8 +787,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 TODO
*/ */
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);
@ -789,16 +820,13 @@ public class Game extends BasicGameState {
if (GameMod.AUTO.isActive() || GameMod.RELAX.isActive()) if (GameMod.AUTO.isActive() || GameMod.RELAX.isActive())
return; return;
if (!isReplay)
addReplayFrame(x, y, lastKeysPressed | keys);
// circles // circles
if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(x, y)) if (hitObject.isCircle() && hitObjects[objectIndex].mousePressed(x, y, trackPosition))
objectIndex++; // circle hit objectIndex++; // circle hit
// sliders // sliders
else if (hitObject.isSlider()) else if (hitObject.isSlider())
hitObjects[objectIndex].mousePressed(x, y); hitObjects[objectIndex].mousePressed(x, y, trackPosition);
} }
@Override @Override
@ -809,26 +837,37 @@ 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) if (!isReplay) {
addReplayFrame(x, y, ReplayFrame.KEY_NONE); if (button == Input.MOUSE_LEFT_BUTTON)
lastKeysPressed &= ~ReplayFrame.KEY_M1;
else if (button == Input.MOUSE_RIGHT_BUTTON)
lastKeysPressed &= ~ReplayFrame.KEY_M2;
frameAndRun(x, y, lastKeysPressed, 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())) if (!isReplay && (key == Options.getGameKeyLeft() || key == Options.getGameKeyRight())) {
addReplayFrame(input.getMouseX(), input.getMouseY(), ReplayFrame.KEY_NONE); if (key == Options.getGameKeyLeft())
lastKeysPressed &= ~ReplayFrame.KEY_K1;
else if (key == Options.getGameKeyRight())
lastKeysPressed &= ~ReplayFrame.KEY_K2;
int mouseX = scaleX(unscaleX(input.getMouseX()));
int mouseY = scaleY(unscaleY(input.getMouseY()));
int trackPosition = MusicController.getPosition();
frameAndRun(mouseX, mouseY, 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
@ -844,6 +883,13 @@ public class Game extends BasicGameState {
throws SlickException { throws SlickException {
UI.enter(); UI.enter();
try {
replayLog = new PrintWriter("replayLog.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (osu == null || osu.objects == null) if (osu == null || osu.objects == null)
throw new RuntimeException("Running game with no OsuFile loaded."); throw new RuntimeException("Running game with no OsuFile loaded.");
@ -910,6 +956,7 @@ public class Game extends BasicGameState {
GameMod.loadModState(replay.mods); GameMod.loadModState(replay.mods);
// load initial data // load initial data
lastReplayTime = 0;
replayX = container.getWidth() / 2; replayX = container.getWidth() / 2;
replayY = container.getHeight() / 2; replayY = container.getHeight() / 2;
replayKeys = ReplayFrame.KEY_NONE; replayKeys = ReplayFrame.KEY_NONE;
@ -928,8 +975,10 @@ public class Game extends BasicGameState {
} else } else
break; break;
} }
// run frame updates in another thread // run frame updates in another thread
/*
killReplayThread(); killReplayThread();
replayThread = new Thread() { replayThread = new Thread() {
@Override @Override
@ -943,8 +992,11 @@ public class Game extends BasicGameState {
replayY = frame.getScaledY(); replayY = frame.getScaledY();
replayKeyPressed = frame.isKeyPressed(); replayKeyPressed = frame.isKeyPressed();
int keys = frame.getKeys(); int keys = frame.getKeys();
if (replayKeyPressed && keys != replayKeys) // send a key press if (replayKeyPressed && keys != replayKeys) { // send a key press
gameKeyPressed(frame.getKeys(), replayX, replayY); System.out.println("Replay Pos:"+trackPosition+" "+replay.frames[replayIndex].getTime());
gameKeyPressed(frame.getKeys(), replayX, replayY, replay.frames[replayIndex].getTime());
}
replayKeys = keys; replayKeys = keys;
replayIndex++; replayIndex++;
} }
@ -955,6 +1007,7 @@ public class Game extends BasicGameState {
// sleep execution // sleep execution
try { try {
//Thread.sleep(1);//, 256000);
int diff = replay.frames[replayIndex].getTime() - trackPosition - 1; int diff = replay.frames[replayIndex].getTime() - trackPosition - 1;
if (diff < 1) if (diff < 1)
Thread.sleep(0, 256000); Thread.sleep(0, 256000);
@ -966,6 +1019,7 @@ public class Game extends BasicGameState {
}; };
replayThreadRunning = true; replayThreadRunning = true;
replayThread.start(); replayThread.start();
*/
} }
// initialize replay-recording structures // initialize replay-recording structures
@ -989,6 +1043,7 @@ public class Game extends BasicGameState {
throws SlickException { throws SlickException {
// container.setMouseGrabbed(false); // container.setMouseGrabbed(false);
replayLog.close();
// replays // replays
if (isReplay) { if (isReplay) {
GameMod.loadModState(previousMods); GameMod.loadModState(previousMods);
@ -1213,20 +1268,56 @@ public class Game extends BasicGameState {
this.replay = replay; this.replay = replay;
} }
} }
public synchronized void frameAndRun(int x, int y, int keys, int time){
ReplayFrame frame = addReplayFrame(x, y, keys, time);
if(frame != null)
runFrame(frame);
}
int prevRunKeys = 0;
private void runFrame(ReplayFrame frame){
int keys = frame.getKeys();
int replayX = frame.getScaledX();
int replayY = frame.getScaledY();
int deltaKeys = (keys & ~prevRunKeys );
replayLog.println("run frame:"+" "+replayX+" "+replayY+" "+(frame.getTimeDiff())+" "+keys+" "+frame.getTime());
if (deltaKeys > 0) { // send a key press
gameKeyPressed(deltaKeys, replayX, replayY, frame.getTime());
//} else if(keys != prevRunKeys){
} else {
updateGame(replayX, replayY, frame.getTimeDiff(), frame.getTime(), keys);
}
prevRunKeys = keys;
}
/** /**
* Adds a replay frame to the list. * Adds a replay frame to the list.
* @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 trackPosition TODO
*/ */
private void addReplayFrame(int x, int y, int keys) { private ReplayFrame addReplayFrame(int x, int y, int keys, int time) {
int time = MusicController.getPosition();
int timeDiff = time - lastReplayTime; int timeDiff = time - lastReplayTime;
lastReplayTime = time; lastReplayTime = time;
lastKeysPressed = keys; //lastKeysPressed = keys;
int cx = (int) ((x - OsuHitObject.getXOffset()) / OsuHitObject.getXMultiplier()); int cx = unscaleX(x);
int cy = (int) ((y - OsuHitObject.getYOffset()) / OsuHitObject.getYMultiplier()); int cy = unscaleY(y);
replayFrames.add(new ReplayFrame(timeDiff, time, cx, cy, lastKeysPressed)); ReplayFrame tFrame = new ReplayFrame(timeDiff, time, cx, cy, keys);
replayFrames.add(tFrame);
return tFrame;
}
public int unscaleX(int x){
return (int) ((x - OsuHitObject.getXOffset()) / OsuHitObject.getXMultiplier());
}
public int unscaleY(int y){
return (int) ((y - OsuHitObject.getYOffset()) / OsuHitObject.getYMultiplier());
}
public int scaleX(int x){
return (int) (x * OsuHitObject.getXMultiplier() + OsuHitObject.getXOffset());
}
public int scaleY(int y){
return (int) (y * OsuHitObject.getYMultiplier() + OsuHitObject.getYOffset());
} }
} }