Skip to content

Commit

Permalink
Fixed remaining issues involving missed game objects due to overlap.
Browse files Browse the repository at this point in the history
- 2B maps are now playable. Note that "Auto" mode will still count "perfect" circles/sliders/spinners even though it obviously misses them.
- Combo counts for normal (non-2B) maps now finally match osu!, from what I can tell. (Turns out this wasn't the slider issue I had initially thought.)

Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
  • Loading branch information
itdelatrisu committed Feb 4, 2017
1 parent ce473dc commit 0ae010e
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/itdelatrisu/opsu/objects/Circle.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public boolean mousePressed(int x, int y, int trackPosition) {
}

@Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
public boolean update(int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
int time = hitObject.getTime();

int[] hitResultOffset = game.getHitResultOffsets();
Expand Down
2 changes: 1 addition & 1 deletion src/itdelatrisu/opsu/objects/DummyObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public DummyObject(HitObject hitObject) {
public void draw(Graphics g, int trackPosition) {}

@Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
public boolean update(int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
return (trackPosition > hitObject.getTime());
}

Expand Down
3 changes: 1 addition & 2 deletions src/itdelatrisu/opsu/objects/GameObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ public interface GameObject {

/**
* Updates the hit object.
* @param overlap true if the next object's start time has already passed
* @param delta the delta interval since the last call
* @param mouseX the x coordinate of the mouse
* @param mouseY the y coordinate of the mouse
* @param keyPressed whether or not a game key is currently pressed
* @param trackPosition the track position
* @return true if object ended
*/
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition);
public boolean update(int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition);

/**
* Processes a mouse click.
Expand Down
7 changes: 4 additions & 3 deletions src/itdelatrisu/opsu/objects/Slider.java
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ public boolean mousePressed(int x, int y, int trackPosition) {
}

@Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
public boolean update(int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
int repeatCount = hitObject.getRepeatCount();
int[] hitResultOffset = game.getHitResultOffsets();
boolean isAutoMod = GameMod.AUTO.isActive();
Expand Down Expand Up @@ -582,8 +582,9 @@ else if (GameMod.RELAX.isActive() && trackPosition >= time)
initialExpand.update(delta);
releaseExpand.update(delta);

// TODO: Some ticks/repeats get missed if delta updates skip past them.
// The code tries to catch this, but doesn't completely work...
// NOTE:
// The loops below are used to catch any missed ticks/repeats if slower
// delta updates skip past them.

// repeats
int newRepeats = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/itdelatrisu/opsu/objects/Spinner.java
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,9 @@ public boolean mousePressed(int x, int y, int trackPosition) {
}

@Override
public boolean update(boolean overlap, int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
public boolean update(int delta, int mouseX, int mouseY, boolean keyPressed, int trackPosition) {
// end of spinner
if (overlap || trackPosition > hitObject.getEndTime()) {
if (trackPosition > hitObject.getEndTime()) {
hitResult();
return true;
}
Expand Down
72 changes: 59 additions & 13 deletions src/itdelatrisu/opsu/states/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
import java.io.File;
import java.io.IOException;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import org.lwjgl.input.Keyboard;
Expand Down Expand Up @@ -140,6 +142,9 @@ public enum Restart {
/** The map's game objects, indexed by objectIndex. */
private GameObject[] gameObjects;

/** Any passed, unfinished hit object indices before objectIndex. */
private List<Integer> passedObjects;

/** Delay time, in milliseconds, before song starts. */
private int leadInTime;

Expand Down Expand Up @@ -578,7 +583,7 @@ else if (breakIndex > 1) {
skipButton.draw();

// show retries
if (retries >= 2 && timeDiff >= -1000) {
if (objectIndex == 0 && retries >= 2 && timeDiff >= -1000) {
int retryHeight = Math.max(
GameImage.SCOREBAR_BG.getImage().getHeight(),
GameImage.SCOREBAR_KI.getImage().getHeight()
Expand Down Expand Up @@ -905,10 +910,16 @@ else if (!gameFinished) {
*/
private void updateGame(int mouseX, int mouseY, int delta, int trackPosition, int keys) {
// map complete!
if (objectIndex >= gameObjects.length || (MusicController.trackEnded() && objectIndex > 0)) {
// track ended before last object was processed: force a hit result
if (MusicController.trackEnded() && objectIndex < gameObjects.length)
gameObjects[objectIndex].update(true, delta, mouseX, mouseY, false, trackPosition);
if (!hasMoreObjects() || (MusicController.trackEnded() && objectIndex > 0)) {
// track ended before last object(s) was processed: force a hit result
if (MusicController.trackEnded() && hasMoreObjects()) {
for (int index : passedObjects)
gameObjects[index].update(delta, mouseX, mouseY, false, trackPosition);
passedObjects.clear();
for (int i = objectIndex; i < gameObjects.length; i++)
gameObjects[i].update(delta, mouseX, mouseY, false, trackPosition);
objectIndex = gameObjects.length;
}

// save score and replay
if (!checkpointLoaded) {
Expand Down Expand Up @@ -1035,17 +1046,32 @@ else if (replayFrames != null) {

// don't process hit results when already lost
if (restart != Restart.LOSE) {
// update objects (loop over any skipped indexes)
boolean keyPressed = keys != ReplayFrame.KEY_NONE;

// update passed objects
Iterator<Integer> iter = passedObjects.iterator();
while (iter.hasNext()) {
int index = iter.next();
if (gameObjects[index].update(delta, mouseX, mouseY, keyPressed, trackPosition))
iter.remove();
}

// update objects (loop over any skipped indexes)
while (objectIndex < gameObjects.length && trackPosition > beatmap.objects[objectIndex].getTime()) {
// check if we've already passed the next object's start time
boolean overlap = (objectIndex + 1 < gameObjects.length &&
trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]);
boolean overlap =
(objectIndex + 1 < gameObjects.length &&
trackPosition > beatmap.objects[objectIndex + 1].getTime() - hitResultOffset[GameData.HIT_50]);

// update hit object and check completion status
if (gameObjects[objectIndex].update(overlap, delta, mouseX, mouseY, keyPressed, trackPosition))
objectIndex++; // done, so increment object index
else
if (gameObjects[objectIndex].update(delta, mouseX, mouseY, keyPressed, trackPosition)) {
// done, so increment object index
objectIndex++;
} else if (overlap) {
// overlap, so save the current object and increment object index
passedObjects.add(objectIndex);
objectIndex++;
} else
break;
}
}
Expand Down Expand Up @@ -1585,13 +1611,27 @@ private void drawHitObjects(Graphics g, int trackPosition) {

// get hit objects in reverse order, or else overlapping objects are unreadable
Stack<Integer> stack = new Stack<Integer>();
int spinnerIndex = -1; // draw spinner first (assume there can only be 1...)
for (int index : passedObjects) {
if (beatmap.objects[index].isSpinner()) {
if (spinnerIndex == -1)
spinnerIndex = index;
} else
stack.add(index);
}
for (int index = objectIndex; index < gameObjects.length && beatmap.objects[index].getTime() < trackPosition + approachTime; index++) {
stack.add(index);
if (beatmap.objects[index].isSpinner()) {
if (spinnerIndex == -1)
spinnerIndex = index;
} else
stack.add(index);

// draw follow points
if (Options.isFollowPointEnabled() && !loseState)
lastObjectIndex = drawFollowPointsBetween(objectIndex, lastObjectIndex, trackPosition);
}
if (spinnerIndex != -1)
stack.add(spinnerIndex);

// draw hit objects
while (!stack.isEmpty()){
Expand Down Expand Up @@ -1722,6 +1762,7 @@ public void loadBeatmap(Beatmap beatmap) {
public void resetGameData() {
data.clear();
objectIndex = 0;
passedObjects = new LinkedList<Integer>();
breakIndex = 0;
breakTime = 0;
breakSound = false;
Expand Down Expand Up @@ -2038,7 +2079,7 @@ else if (keys != lastReplayKeys)
* @param keys the keys that are pressed
*/
private void sendGameKeyPress(int keys, int x, int y, int trackPosition) {
if (objectIndex >= gameObjects.length) // nothing to do here
if (!hasMoreObjects()) // nothing to do here
return;

HitObject hitObject = beatmap.objects[objectIndex];
Expand Down Expand Up @@ -2217,6 +2258,11 @@ private void calculateStacks() {
}
}

/** Returns whether there are any more objects remaining in the map. */
private boolean hasMoreObjects() {
return objectIndex < gameObjects.length || !passedObjects.isEmpty();
}

/**
* Returns true if the coordinates are within the music position bar bounds.
* @param cx the x coordinate
Expand Down

0 comments on commit 0ae010e

Please sign in to comment.