| 
33 | 33 | import itdelatrisu.opsu.replay.ReplayFrame;  | 
34 | 34 | import itdelatrisu.opsu.ui.Colors;  | 
35 | 35 | import itdelatrisu.opsu.ui.Fonts;  | 
 | 36 | +import itdelatrisu.opsu.ui.UI;  | 
36 | 37 | import itdelatrisu.opsu.ui.animations.AnimationEquation;  | 
37 | 38 | import itdelatrisu.opsu.user.UserList;  | 
38 | 39 | 
 
  | 
39 | 40 | import java.io.File;  | 
 | 41 | +import java.util.ArrayList;  | 
40 | 42 | import java.util.Date;  | 
41 | 43 | import java.util.HashMap;  | 
42 | 44 | import java.util.Iterator;  | 
 | 45 | +import java.util.List;  | 
43 | 46 | import java.util.Random;  | 
44 | 47 | import java.util.concurrent.LinkedBlockingDeque;  | 
45 | 48 | 
 
  | 
@@ -239,6 +242,12 @@ public HitErrorInfo(int time, int x, int y, int timeDiff) {  | 
239 | 242 | 	/** List containing recent hit error information. */  | 
240 | 243 | 	private LinkedBlockingDeque<HitErrorInfo> hitErrorList;  | 
241 | 244 | 
 
  | 
 | 245 | +	/** List containing all hit error time differences. */  | 
 | 246 | +	private List<Integer> hitErrors;  | 
 | 247 | + | 
 | 248 | +	/** Performance string containing hit error averages and unstable rate. */  | 
 | 249 | +	private String performanceString = null;  | 
 | 250 | + | 
242 | 251 | 	/** Hit object types, used for drawing results. */  | 
243 | 252 | 	public enum HitObjectType { CIRCLE, SLIDERTICK, SLIDER_FIRST, SLIDER_LAST, SPINNER }  | 
244 | 253 | 
 
  | 
@@ -394,6 +403,8 @@ public void clear() {  | 
394 | 403 | 		}  | 
395 | 404 | 		hitResultList = new LinkedBlockingDeque<HitObjectResult>();  | 
396 | 405 | 		hitErrorList = new LinkedBlockingDeque<HitErrorInfo>();  | 
 | 406 | +		hitErrors = new ArrayList<Integer>();  | 
 | 407 | +		performanceString = null;  | 
397 | 408 | 		fullObjectCount = 0;  | 
398 | 409 | 		combo = 0;  | 
399 | 410 | 		comboMax = 0;  | 
@@ -1321,6 +1332,26 @@ public void updateDisplays(int delta) {  | 
1321 | 1332 | 		}  | 
1322 | 1333 | 	}  | 
1323 | 1334 | 
 
  | 
 | 1335 | +	/**  | 
 | 1336 | +	 * Updates displayed ranking elements based on a delta value.  | 
 | 1337 | +	 * @param delta the delta interval since the last call  | 
 | 1338 | +	 * @param mouseX the mouse x coordinate  | 
 | 1339 | +	 * @param mouseY the mouse y coordinate  | 
 | 1340 | +	 */  | 
 | 1341 | +	public void updateRankingDisplays(int delta, int mouseX, int mouseY) {  | 
 | 1342 | +		// graph tooltip  | 
 | 1343 | +		Image graphImg = GameImage.RANKING_GRAPH.getImage();  | 
 | 1344 | +		float graphX = 416 * GameImage.getUIscale();  | 
 | 1345 | +		float graphY = 688 * GameImage.getUIscale();  | 
 | 1346 | +		if (isGameplay &&  | 
 | 1347 | +		    mouseX >= graphX - graphImg.getWidth() / 2f && mouseX <= graphX + graphImg.getWidth() / 2f &&  | 
 | 1348 | +		    mouseY >= graphY - graphImg.getHeight() / 2f && mouseY <= graphY + graphImg.getHeight() / 2f) {  | 
 | 1349 | +			if (performanceString == null)  | 
 | 1350 | +				performanceString = getPerformanceString(hitErrors);  | 
 | 1351 | +			UI.updateTooltip(delta, performanceString, true);  | 
 | 1352 | +		}  | 
 | 1353 | +	}  | 
 | 1354 | + | 
1324 | 1355 | 	/**  | 
1325 | 1356 | 	 * Returns the current combo streak.  | 
1326 | 1357 | 	 */  | 
@@ -1728,5 +1759,31 @@ public Replay getReplay(ReplayFrame[] frames, LifeFrame[] lifeFrames, Beatmap be  | 
1728 | 1759 | 	 */  | 
1729 | 1760 | 	public void addHitError(int time, int x, int y, int timeDiff) {  | 
1730 | 1761 | 		hitErrorList.addFirst(new HitErrorInfo(time, x, y, timeDiff));  | 
 | 1762 | +		hitErrors.add(timeDiff);  | 
 | 1763 | +	}  | 
 | 1764 | + | 
 | 1765 | +	/**  | 
 | 1766 | +	 * Computes the error values and unstable rate for the map.  | 
 | 1767 | +	 * @see <a href="https://osu.ppy.sh/wiki/Accuracy#Performance_Graph">https://osu.ppy.sh/wiki/Accuracy#Performance_Graph</a>  | 
 | 1768 | +	 */  | 
 | 1769 | +	private String getPerformanceString(List<Integer> errors) {  | 
 | 1770 | +		int earlyCount = 0, lateCount = 0;  | 
 | 1771 | +		int earlySum = 0, lateSum = 0;  | 
 | 1772 | +		for (int diff : errors) {  | 
 | 1773 | +			if (diff < 0) {  | 
 | 1774 | +				earlyCount++;  | 
 | 1775 | +				earlySum += diff;  | 
 | 1776 | +			} else if (diff > 0) {  | 
 | 1777 | +				lateCount++;  | 
 | 1778 | +				lateSum += diff;  | 
 | 1779 | +			}  | 
 | 1780 | +		}  | 
 | 1781 | +		float hitErrorEarly = (earlyCount > 0) ? (float) earlySum / earlyCount : 0f;  | 
 | 1782 | +		float hitErrorLate = (lateCount > 0) ? (float) lateSum / lateCount : 0f;  | 
 | 1783 | +		float unstableRate = (!errors.isEmpty()) ? (float) (Utils.standardDeviation(errors) * 10) : 0f;  | 
 | 1784 | +		return String.format(  | 
 | 1785 | +			"Accuracy:\nError: %.2fms - %.2fms avg\nUnstable Rate: %.2f",  | 
 | 1786 | +			hitErrorEarly, hitErrorLate, unstableRate  | 
 | 1787 | +		);  | 
1731 | 1788 | 	}  | 
1732 | 1789 | }  | 
0 commit comments