1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-14 15:17:27 +08:00

Merge branch 'master' into mania-convert-song-select-keycount

This commit is contained in:
Dan Balasescu 2023-12-13 13:53:50 +09:00
commit 6ed5613c22
No known key found for this signature in database
15 changed files with 495 additions and 45 deletions

View File

@ -74,6 +74,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
simulateHit(obj, ref attributes);
attributes.BonusScoreRatio = legacyBonusScore == 0 ? 0 : (double)standardisedBonusScore / legacyBonusScore;
attributes.BonusScore = legacyBonusScore;
return attributes;
}

View File

@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Mania.Tests
[TestCase("zero-length-slider")]
[TestCase("20544")]
[TestCase("100374")]
[TestCase("1450162")]
public void Test(string name) => base.Test(name);
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)

View File

@ -0,0 +1,42 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests.Mods
{
public partial class TestSceneManiaModAutoplay : ModTestScene
{
protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset();
[Test]
public void TestPerfectScoreOnShortHoldNote()
{
CreateModTest(new ModTestData
{
Autoplay = true,
Beatmap = new ManiaBeatmap(new StageDefinition(1))
{
HitObjects = new List<ManiaHitObject>
{
new HoldNote
{
StartTime = 100,
EndTime = 100,
},
new HoldNote
{
StartTime = 100.1,
EndTime = 150,
},
}
},
PassCondition = () => Player.ScoreProcessor.Combo.Value == 4
});
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,297 @@
osu file format v14
[General]
StackLeniency: 0.7
Mode: 0
[Difficulty]
HPDrainRate:5
CircleSize:4
OverallDifficulty:7
ApproachRate:7.5
SliderMultiplier:1.4
SliderTickRate:1
[Events]
//Background and Video events
//Break Periods
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Sound Samples
[TimingPoints]
1107,365.853658536585,4,2,1,50,1,0
1107,-166.666666666667,4,2,1,50,0,0
6960,-111.111111111111,4,2,1,50,0,0
8424,-100,4,2,1,50,0,0
48119,-125,4,2,1,50,0,0
52143,-100,4,2,1,50,0,0
62570,-100,4,2,1,60,0,1
85985,-100,4,2,1,50,0,0
97692,-100,4,2,1,30,0,0
99155,-100,4,2,1,20,0,0
100619,-100,4,2,1,5,0,0
[HitObjects]
38,247,1107,6,0,P|96:269|170:192,1,167.999994873047,2|0,0:0|0:0,0:0:0:0:
201,128,2570,6,0,L|205:221,1,83.9999974365235,2|0,0:0|0:0,0:0:0:0:
242,230,3302,2,0,L|234:324,1,83.9999974365235,2|0,0:0|0:0,0:0:0:0:
205,343,4033,6,0,P|246:296|351:314,1,167.999994873047,2|0,0:0|0:0,0:0:0:0:
400,368,5497,6,0,L|412:269,1,83.9999974365235,6|0,0:0|0:0,0:0:0:0:
436,251,6228,2,0,P|425:203|408:153,1,83.9999974365235,2|0,0:0|0:0,0:0:0:0:
304,200,6960,6,0,P|262:186|234:181,1,62.9999980773926,6|0,0:0|0:0,0:0:0:0:
202,179,7326,1,8,0:0:0:0:
276,94,7509,2,0,P|313:92|353:87,1,62.9999980773926,2|0,0:0|0:0,0:0:0:0:
398,31,7875,1,2,0:0:0:0:
464,81,8058,2,0,L|450:150,1,62.9999980773926,2|0,0:0|0:0,0:0:0:0:
449,230,8424,6,0,P|347:206|306:217,1,140,2|8,0:0|0:0,0:0:0:0:
229,273,8972,2,0,P|225:339|235:361,1,70,2|0,0:0|0:0,0:0:0:0:
304,313,9338,1,8,0:0:0:0:
224,190,9521,1,2,0:0:0:0:
296,45,9887,6,0,P|297:97|288:125,1,70,6|0,0:0|0:0,0:0:0:0:
224,190,10253,1,8,0:0:0:0:
167,118,10436,1,8,0:0:0:0:
76,126,10619,1,8,0:0:0:0:
39,209,10802,1,8,0:0:0:0:
93,282,10985,1,10,0:0:0:0:
184,280,11167,1,10,0:0:0:0:
102,136,12814,5,2,0:0:0:0:
102,136,13180,2,0,L|199:130,1,70,8|0,0:0|0:0,0:0:0:0:
256,167,13546,2,0,L|339:161,1,70,8|2,0:0|0:0,0:0:0:0:
408,201,13911,2,0,P|454:176|471:143,1,70,8|2,0:0|0:0,0:0:0:0:
373,54,14277,6,0,L|396:137,2,70,6|0|8,0:0|0:0|0:0,0:0:0:0:
305,111,14826,2,0,L|287:274,1,140,0|2,0:0|0:0,0:0:0:0:
262,337,15375,2,0,L|349:327,1,70,8|2,0:0|0:0,0:0:0:0:
419,354,15741,1,8,0:0:0:0:
477,197,16106,6,0,P|423:197|385:209,1,70,8|0,0:0|0:0,0:0:0:0:
321,170,16472,2,0,P|278:190|253:219,1,70,8|2,0:0|0:0,0:0:0:0:
171,213,16838,2,0,P|152:259|158:304,1,70,8|2,0:0|0:0,0:0:0:0:
305,294,17204,6,0,L|224:278,2,70,6|0|8,0:0|0:0|0:0,0:0:0:0:
310,202,17753,2,0,L|149:214,1,140,0|2,0:0|0:0,0:0:0:0:
84,244,18302,2,0,L|92:152,1,70,8|2,0:0|0:0,0:0:0:0:
47,93,18667,6,0,P|78:53|176:80,1,140,6|8,0:0|0:0,0:0:0:0:
218,130,19216,1,0,0:0:0:0:
299,88,19399,2,0,L|387:91,1,70,8|0,0:0|0:0,0:0:0:0:
458,106,19765,2,0,P|447:139|444:205,1,70,8|0,0:0|0:0,0:0:0:0:
455,274,20131,5,2,0:0:0:0:
366,292,20314,2,0,L|353:211,1,70,0|8,0:0|0:0,0:0:0:0:
277,173,20680,2,0,L|253:342,1,140,0|2,0:0|0:0,0:0:0:0:
322,376,21228,2,0,P|368:368|416:370,1,70,8|2,0:0|0:0,0:0:0:0:
500,287,21594,6,0,P|427:273|362:293,2,140,6|8|8,0:0|0:0|0:0,0:0:0:0:
496,111,22509,1,8,0:0:0:0:
499,189,22692,2,0,L|418:191,1,70,8|2,0:0|0:0,0:0:0:0:
344,164,23058,5,6,0:0:0:0:
344,164,23241,1,12,0:0:0:0:
261,326,23606,2,0,L|246:178,1,140,8|2,0:0|0:0,0:0:0:0:
277,100,24155,2,0,P|225:99|196:109,1,70,8|2,0:0|0:0,0:0:0:0:
165,273,24521,5,6,0:0:0:0:
83,235,24704,2,0,L|93:81,1,140,0|0,0:0|0:0,0:0:0:0:
21,37,25253,2,0,L|1:120,2,70,2|0|8,0:0|0:0|0:0,0:0:0:0:
110,17,25802,1,0,0:0:0:0:
172,83,25985,5,2,0:0:0:0:
236,19,26167,2,0,P|223:70|227:170,1,140,0|0,0:0|0:0,0:0:0:0:
293,216,26716,2,0,P|316:165|314:134,2,70,2|0|8,0:0|0:0|0:0,0:0:0:0:
206,245,27265,1,0,0:0:0:0:
274,305,27448,5,2,0:0:0:0:
194,348,27631,2,0,L|363:332,1,140,0|0,0:0|0:0,0:0:0:0:
424,336,28180,1,2,0:0:0:0:
431,245,28363,2,0,P|381:252|354:276,2,70,0|8|0,0:0|0:0|0:0,0:0:0:0:
509,291,28911,6,0,L|496:128,1,140,2|8,0:0|0:0,0:0:0:0:
504,60,29460,1,0,0:0:0:0:
417,34,29643,2,0,L|402:183,1,140,2|8,0:0|0:0,0:0:0:0:
365,262,30192,1,0,0:0:0:0:
295,202,30375,5,2,0:0:0:0:
309,112,30558,2,0,P|282:172|196:176,1,140,0|0,0:0|0:0,0:0:0:0:
148,120,31106,2,0,P|189:99|225:99,2,70,2|0|8,0:0|0:0|0:0,0:0:0:0:
129,209,31655,1,0,0:0:0:0:
63,146,31838,5,2,0:0:0:0:
16,67,32021,2,0,L|27:220,1,140,0|0,0:0|0:0,0:0:0:0:
23,297,32570,2,0,P|81:286|111:290,1,70,2|0,0:0|0:0,0:0:0:0:
173,327,32936,1,8,0:0:0:0:
338,251,33302,6,0,P|268:254|227:199,1,140,2|8,0:0|0:0,0:0:0:0:
203,114,33850,2,0,L|185:262,1,140,0|0,0:0|0:0,0:0:0:0:
244,323,34399,1,8,0:0:0:0:
334,335,34582,1,0,0:0:0:0:
419,219,34765,6,0,L|410:304,1,70,2|0,0:0|0:0,0:0:0:0:
338,251,35131,1,8,0:0:0:0:
301,111,35314,2,0,L|301:190,1,70,6|0,0:0|0:0,0:0:0:0:
383,141,35680,1,8,0:0:0:0:
462,97,35863,2,0,P|427:64|393:54,1,70,2|0,0:0|0:0,0:0:0:0:
321,23,36228,5,2,0:0:0:0:
237,60,36411,1,0,0:0:0:0:
148,38,36594,2,0,P|107:33|56:43,1,70,8|0,0:0|0:0,0:0:0:0:
86,125,36960,2,0,P|51:125|17:117,2,70,2|0|8,0:0|0:0|0:0,0:0:0:0:
175,123,37509,1,0,0:0:0:0:
129,201,37692,5,2,0:0:0:0:
198,259,37875,1,0,0:0:0:0:
205,349,38058,2,0,P|251:330|284:326,1,70,8|0,0:0|0:0,0:0:0:0:
352,285,38424,2,0,P|361:318|357:353,2,70,2|0|8,0:0|0:0|0:0,0:0:0:0:
282,239,38972,1,0,0:0:0:0:
362,195,39155,5,2,0:0:0:0:
436,142,39338,2,0,P|398:115|354:112,1,70,0|8,0:0|0:0,0:0:0:0:
286,92,39704,2,0,L|451:74,1,140,0|0,0:0|0:0,0:0:0:0:
512,118,40253,2,0,L|494:198,1,70,8|0,0:0|0:0,0:0:0:0:
430,297,40619,6,0,P|423:236|336:195,1,140,2|8,0:0|0:0,0:0:0:0:
282,239,41167,1,0,0:0:0:0:
209,184,41350,2,0,L|222:112,1,70,2|2,0:0|0:0,0:0:0:0:
177,34,41716,2,0,P|230:26|269:38,1,70,8|0,0:0|0:0,0:0:0:0:
307,95,42082,5,2,0:0:0:0:
363,23,42265,2,0,L|359:114,1,70,0|8,0:0|0:0,0:0:0:0:
360,184,42631,1,0,0:0:0:0:
450,191,42814,2,0,P|443:145|424:119,2,70,2|0|8,0:0|0:0|0:0,0:0:0:0:
393,263,43363,1,0,0:0:0:0:
304,242,43546,5,2,0:0:0:0:
241,308,43728,1,0,0:0:0:0:
167,256,43911,2,0,P|205:228|245:226,1,70,8|0,0:0|0:0,0:0:0:0:
166,341,44277,2,0,P|118:325|90:289,1,70,2|0,0:0|0:0,0:0:0:0:
125,177,44643,2,0,P|168:152|201:153,1,70,8|0,0:0|0:0,0:0:0:0:
276,132,45009,6,0,L|119:105,1,140,2|8,0:0|0:0,0:0:0:0:
52,74,45558,2,0,L|210:57,1,140,2|0,0:0|0:0,0:0:0:0:
277,28,46106,1,8,0:0:0:0:
349,82,46289,1,0,0:0:0:0:
425,32,46472,6,0,L|451:110,2,70,6|2|8,0:0|0:0|0:0,0:0:0:0:
349,82,47021,2,0,L|344:235,1,140,2|8,0:0|0:0,0:0:0:0:
372,308,47570,1,2,0:0:0:0:
170,324,47936,5,2,0:0:0:0:
99,286,48119,2,0,L|112:112,1,168,2|2,0:0|0:0,0:0:0:0:
64,48,48850,2,0,P|125:36|195:111,1,168,2|2,0:0|0:0,0:0:0:0:
199,189,49582,6,0,L|369:166,1,168,2|2,0:0|0:0,0:0:0:0:
413,97,50314,2,0,P|390:180|377:274,1,168,2|2,0:0|0:0,0:0:0:0:
347,339,51046,6,0,P|424:333|463:251,1,168,2|2,0:0|0:0,0:0:0:0:
473,175,51777,2,0,L|477:105,1,56,2|2,0:0|0:0,0:0:0:0:
446,24,52143,6,0,P|363:22|308:82,1,140,12|2,0:0|0:0,0:0:0:0:
282,138,52692,1,8,0:0:0:0:
193,118,52875,2,0,L|213:281,1,140,2|8,0:0|0:0,0:0:0:0:
225,347,53424,2,0,P|268:328|286:301,1,70,2|0,0:0|0:0,0:0:0:0:
304,222,53789,5,2,0:0:0:0:
385,263,53972,1,0,0:0:0:0:
462,214,54155,2,0,P|421:185|383:179,1,70,8|0,0:0|0:0,0:0:0:0:
322,136,54521,2,0,P|360:105|400:93,1,70,2|0,0:0|0:0,0:0:0:0:
469,107,54887,2,0,L|483:24,1,70,8|0,0:0|0:0,0:0:0:0:
390,22,55253,6,0,L|223:30,1,140,2|8,0:0|0:0,0:0:0:0:
180,87,55802,1,0,0:0:0:0:
230,162,55985,2,0,L|391:154,1,140,2|8,0:0|0:0,0:0:0:0:
430,223,56533,1,0,0:0:0:0:
407,311,56716,6,0,P|356:347|285:307,1,140,2|8,0:0|0:0,0:0:0:0:
236,245,57265,1,0,0:0:0:0:
145,237,57448,2,0,L|162:316,1,70,2|0,0:0|0:0,0:0:0:0:
233,360,57814,6,0,P|185:349|142:350,1,70,8|0,0:0|0:0,0:0:0:0:
11,311,58180,2,0,P|64:302|104:306,1,70,2|0,0:0|0:0,0:0:0:0:
213,248,58546,2,0,P|162:237|130:237,1,70,8|0,0:0|0:0,0:0:0:0:
1,194,58911,2,0,P|47:183|74:185,1,70,2|0,0:0|0:0,0:0:0:0:
234,142,59277,2,0,P|175:129|152:128,1,70,8|0,0:0|0:0,0:0:0:0:
12,26,59643,6,0,P|66:38|71:140,1,140,2|8,0:0|0:0,0:0:0:0:
1,194,60192,1,0,0:0:0:0:
84,230,60375,1,2,0:0:0:0:
173,216,60558,1,8,0:0:0:0:
173,216,60649,1,8,0:0:0:0:
173,216,60741,1,8,0:0:0:0:
263,213,60924,1,2,0:0:0:0:
345,174,61106,6,0,P|320:144|286:130,1,70,2|0,0:0|0:0,0:0:0:0:
200,134,61472,1,8,0:0:0:0:
249,57,61655,2,0,L|263:12,2,35,12|8|8,0:0|0:0|0:0,0:0:0:0:
157,64,62021,2,0,L|153:13,2,35,12|8|8,0:0|0:0|0:0,0:0:0:0:
118,150,62387,1,2,0:0:0:0:
101,260,62570,6,0,P|207:236|257:243,1,140,2|8,0:0|0:0,0:0:0:0:
328,304,63119,1,0,0:0:0:0:
434,156,63302,2,0,P|373:157|329:217,1,140,2|8,0:0|0:0,0:0:0:0:
408,230,63850,1,2,0:0:0:0:
483,215,64033,5,6,0:0:0:0:
508,142,64216,1,0,0:0:0:0:
482,69,64399,1,8,0:0:0:0:
413,34,64582,2,0,P|336:30|256:49,1,140,0|2,0:0|0:0,0:0:0:0:
150,97,65131,2,0,P|190:97|243:107,1,70,8|2,0:0|0:0,0:0:0:0:
257,168,65497,6,0,L|225:323,1,140,2|8,0:0|0:0,0:0:0:0:
155,329,66046,1,0,0:0:0:0:
20,204,66228,2,0,P|92:202|133:271,1,140,8|8,0:0|0:0,0:0:0:0:
56,274,66777,1,2,0:0:0:0:
18,125,66960,6,0,L|93:119,1,70,6|0,0:0|0:0,0:0:0:0:
162,156,67326,1,8,0:0:0:0:
223,52,67509,2,0,L|227:219,1,140,0|2,0:0|0:0,0:0:0:0:
266,263,68058,2,0,P|300:229|308:199,1,70,8|2,0:0|0:0,0:0:0:0:
298,95,68424,6,0,L|458:75,1,140,6|8,0:0|0:0,0:0:0:0:
512,164,68972,2,0,L|358:154,1,140,0|2,0:0|0:0,0:0:0:0:
306,209,69521,1,8,0:0:0:0:
342,334,69704,6,0,P|361:289|369:244,1,70,2|6,0:0|0:0,0:0:0:0:
250,277,70070,2,0,P|223:228|219:186,1,70,0|8,0:0|0:0,0:0:0:0:
272,128,70436,1,0,0:0:0:0:
172,111,70619,2,0,L|343:97,1,140,8|8,0:0|0:0,0:0:0:0:
385,128,71167,1,2,0:0:0:0:
494,63,71350,6,0,L|413:54,1,70,6|0,0:0|0:0,0:0:0:0:
385,128,71716,2,0,L|475:140,1,70,8|0,0:0|0:0,0:0:0:0:
467,217,72082,2,0,L|386:208,1,70,8|2,0:0|0:0,0:0:0:0:
358,282,72448,2,0,L|448:294,1,70,8|2,0:0|0:0,0:0:0:0:
498,339,72814,5,12,0:0:0:0:
498,339,72997,1,12,0:0:0:0:
301,343,73363,1,8,0:0:0:0:
211,173,73728,2,0,L|221:216,2,35,2|2|8,0:0|0:0|0:0,0:0:0:0:
250,100,74094,1,2,0:0:0:0:
123,92,74277,6,0,P|129:156|129:236,1,140,2|8,0:0|0:0,0:0:0:0:
109,321,74826,1,0,0:0:0:0:
211,173,75009,2,0,P|266:165|333:237,1,140,8|8,0:0|0:0,0:0:0:0:
341,302,75558,1,2,0:0:0:0:
418,272,75741,5,6,0:0:0:0:
484,322,75924,1,0,0:0:0:0:
407,352,76106,1,8,0:0:0:0:
341,302,76289,2,0,L|364:147,1,140,0|2,0:0|0:0,0:0:0:0:
269,60,76838,2,0,P|315:69|349:94,1,70,8|0,0:0|0:0,0:0:0:0:
269,150,77204,6,0,P|228:160|114:139,1,140,2|8,0:0|0:0,0:0:0:0:
49,80,77753,1,0,0:0:0:0:
39,235,77936,2,0,P|103:222|160:277,1,140,8|8,0:0|0:0,0:0:0:0:
82,297,78485,1,2,0:0:0:0:
227,326,78667,6,0,L|233:241,1,70,4|0,0:0|0:0,0:0:0:0:
269,150,79033,1,8,0:0:0:0:
408,194,79216,2,0,P|359:172|271:187,1,140,0|2,0:0|0:0,0:0:0:0:
409,281,79765,2,0,P|447:272|478:250,1,70,8|2,0:0|0:0,0:0:0:0:
497,168,80131,6,0,L|481:332,1,140,6|8,0:0|0:0,0:0:0:0:
389,365,80680,2,0,L|376:198,1,140,0|2,0:0|0:0,0:0:0:0:
414,157,81228,1,8,0:0:0:0:
229,89,81411,6,0,P|304:91|338:167,1,140,2|0,0:0|0:0,0:0:0:0:
290,222,81960,1,8,0:0:0:0:
211,214,82143,1,8,0:0:0:0:
93,155,82326,2,0,P|137:143|172:150,1,70,2|2,0:0|0:0,0:0:0:0:
235,301,82692,2,0,P|177:296|141:279,1,70,8|2,0:0|0:0,0:0:0:0:
68,244,83058,6,0,L|72:328,1,70,6|0,0:0|0:0,0:0:0:0:
166,292,83424,2,0,L|157:372,1,70,8|0,0:0|0:0,0:0:0:0:
254,227,83789,2,0,L|258:310,1,70,8|2,0:0|0:0,0:0:0:0:
345,265,84155,2,0,L|336:349,1,70,8|0,0:0|0:0,0:0:0:0:
331,175,84521,5,2,0:0:0:0:
416,205,84704,1,2,0:0:0:0:
481,141,84887,1,8,0:0:0:0:
431,64,85070,2,0,L|444:26,2,35,8|8|2,0:0|0:0|0:0,0:0:0:0:
339,79,85436,2,0,L|341:39,2,35,8|8|8,0:0|0:0|0:0,0:0:0:0:
256,109,85802,1,2,0:0:0:0:
165,97,85985,6,0,P|167:150|164:187,1,70,2|0,0:0|0:0,0:0:0:0:
117,244,86350,2,0,P|163:241|204:235,1,70,8|0,0:0|0:0,0:0:0:0:
229,317,86716,2,0,P|273:305|300:294,1,70,8|2,0:0|0:0,0:0:0:0:
365,354,87082,2,0,P|404:334|430:310,1,70,8|0,0:0|0:0,0:0:0:0:
352,230,87448,6,0,L|271:216,2,70,6|0|8,0:0|0:0|0:0,0:0:0:0:
378,142,87997,2,0,L|222:144,1,140,0|2,0:0|0:0,0:0:0:0:
152,112,88546,2,0,L|166:214,1,70,8|2,0:0|0:0,0:0:0:0:
139,270,88911,5,8,0:0:0:0:
12,138,89277,2,0,L|29:55,1,70,8|0,0:0|0:0,0:0:0:0:
91,5,89643,2,0,L|104:97,1,70,8|2,0:0|0:0,0:0:0:0:
153,149,90009,2,0,L|175:78,1,70,8|0,0:0|0:0,0:0:0:0:
279,36,90375,6,0,L|357:27,2,70,6|0|8,0:0|0:0|0:0,0:0:0:0:
248,122,90924,2,0,L|398:125,1,140,0|2,0:0|0:0,0:0:0:0:
479,123,91472,2,0,P|468:170|445:195,1,70,8|2,0:0|0:0,0:0:0:0:
365,204,91838,6,0,P|414:220|409:320,1,140,6|8,0:0|0:0,0:0:0:0:
354,354,92387,1,0,0:0:0:0:
262,353,92570,2,0,L|271:273,1,70,8|2,0:0|0:0,0:0:0:0:
297,196,92936,2,0,P|243:198|216:215,1,70,8|0,0:0|0:0,0:0:0:0:
172,276,93302,5,6,0:0:0:0:
137,360,93485,2,0,L|127:265,1,70,0|8,0:0|0:0,0:0:0:0:
81,212,93850,2,0,P|93:138|118:67,1,140,0|2,0:0|0:0,0:0:0:0:
170,4,94399,2,0,P|195:37|204:74,1,70,8|2,0:0|0:0,0:0:0:0:
186,153,94765,6,0,L|340:139,1,140,6|8,0:0|0:0,0:0:0:0:
408,101,95314,1,2,0:0:0:0:
443,184,95497,1,6,0:0:0:0:
369,237,95680,2,0,L|300:224,2,70,8|8|2,0:0|0:0|0:0,0:0:0:0:
448,282,96228,5,12,0:0:0:0:
448,282,96411,1,12,0:0:0:0:
270,320,96777,1,8,0:0:0:0:
313,143,97143,1,8,0:0:0:0:
377,314,97509,1,8,0:0:0:0:
256,192,97692,12,0,100619,0:0:0:0:

View File

@ -65,7 +65,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
double roundedOverallDifficulty = Math.Round(difficulty.OverallDifficulty);
int countSliderOrSpinner = difficulty.EndTimeObjectCount;
float percentSpecialObjects = (float)countSliderOrSpinner / difficulty.TotalObjectCount;
// In osu!stable, this division appears as if it happens on floats, but due to release-mode
// optimisations, it actually ends up happening on doubles.
double percentSpecialObjects = (double)countSliderOrSpinner / difficulty.TotalObjectCount;
if (percentSpecialObjects < 0.2)
return 7;

View File

@ -87,15 +87,22 @@ namespace osu.Game.Rulesets.Mania.Replays
private double calculateReleaseTime(HitObject currentObject, HitObject? nextObject)
{
double endTime = currentObject.GetEndTime();
double releaseDelay = RELEASE_DELAY;
if (currentObject is HoldNote)
// hold note releases must be timed exactly.
return endTime;
if (currentObject is HoldNote hold)
{
if (hold.Duration > 0)
// hold note releases must be timed exactly.
return endTime;
// Special case for super short hold notes
releaseDelay = 1;
}
bool canDelayKeyUpFully = nextObject == null ||
nextObject.StartTime > endTime + RELEASE_DELAY;
nextObject.StartTime > endTime + releaseDelay;
return endTime + (canDelayKeyUpFully ? RELEASE_DELAY : (nextObject.AsNonNull().StartTime - endTime) * 0.9);
return endTime + (canDelayKeyUpFully ? releaseDelay : (nextObject.AsNonNull().StartTime - endTime) * 0.9);
}
protected override HitObject? GetNextObject(int currentIndex)

View File

@ -74,6 +74,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
simulateHit(obj, ref attributes);
attributes.BonusScoreRatio = legacyBonusScore == 0 ? 0 : (double)standardisedBonusScore / legacyBonusScore;
attributes.BonusScore = legacyBonusScore;
attributes.MaxCombo = combo;
return attributes;
}

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
@ -17,12 +16,5 @@ namespace osu.Game.Rulesets.Osu.Scoring
protected override HitEvent CreateHitEvent(JudgementResult result)
=> base.CreateHitEvent(result).With((result as OsuHitCircleJudgementResult)?.CursorPositionAtHit);
protected override double ComputeTotalScore(double comboProgress, double accuracyProgress, double bonusPortion)
{
return 700000 * comboProgress
+ 300000 * Math.Pow(Accuracy.Value, 10) * accuracyProgress
+ bonusPortion;
}
}
}

View File

@ -75,6 +75,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
simulateHit(obj, ref attributes);
attributes.BonusScoreRatio = legacyBonusScore == 0 ? 0 : (double)standardisedBonusScore / legacyBonusScore;
attributes.BonusScore = legacyBonusScore;
return attributes;
}

View File

@ -45,11 +45,11 @@ namespace osu.Game.Tests.Rulesets.Scoring
};
}
[TestCase(ScoringMode.Standardised, HitResult.Meh, 116_667)]
[TestCase(ScoringMode.Standardised, HitResult.Ok, 233_338)]
[TestCase(ScoringMode.Standardised, HitResult.Meh, 83_398)]
[TestCase(ScoringMode.Standardised, HitResult.Ok, 168_724)]
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
[TestCase(ScoringMode.Classic, HitResult.Meh, 11_670)]
[TestCase(ScoringMode.Classic, HitResult.Ok, 23_341)]
[TestCase(ScoringMode.Classic, HitResult.Meh, 8_343)]
[TestCase(ScoringMode.Classic, HitResult.Ok, 16_878)]
[TestCase(ScoringMode.Classic, HitResult.Great, 100_033)]
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
{
@ -75,27 +75,27 @@ namespace osu.Game.Tests.Rulesets.Scoring
/// This test intentionally misses the 3rd hitobject to achieve lower than 75% accuracy and 50% max combo.
/// </remarks>
[TestCase(ScoringMode.Standardised, HitResult.Miss, HitResult.Great, 0)]
[TestCase(ScoringMode.Standardised, HitResult.Meh, HitResult.Great, 79_333)]
[TestCase(ScoringMode.Standardised, HitResult.Ok, HitResult.Great, 158_667)]
[TestCase(ScoringMode.Standardised, HitResult.Good, HitResult.Perfect, 317_626)]
[TestCase(ScoringMode.Standardised, HitResult.Great, HitResult.Great, 492_894)]
[TestCase(ScoringMode.Standardised, HitResult.Perfect, HitResult.Perfect, 492_894)]
[TestCase(ScoringMode.Standardised, HitResult.Meh, HitResult.Great, 34_734)]
[TestCase(ScoringMode.Standardised, HitResult.Ok, HitResult.Great, 69_925)]
[TestCase(ScoringMode.Standardised, HitResult.Good, HitResult.Perfect, 154_499)]
[TestCase(ScoringMode.Standardised, HitResult.Great, HitResult.Great, 326_963)]
[TestCase(ScoringMode.Standardised, HitResult.Perfect, HitResult.Perfect, 326_963)]
[TestCase(ScoringMode.Standardised, HitResult.SmallTickMiss, HitResult.SmallTickHit, 0)]
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, HitResult.SmallTickHit, 541_894)]
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, HitResult.SmallTickHit, 493_652)]
[TestCase(ScoringMode.Standardised, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 492_894)]
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 326_963)]
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)]
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)]
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)]
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 7_975)]
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 15_949)]
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 31_928)]
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 49_546)]
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 49_546)]
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 3_492)]
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 7_029)]
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 15_530)]
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 32_867)]
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 32_867)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 0)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 54_189)]
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 49_365)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 49_289)]
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 32_696)]
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 100_003)]
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 100_015)]
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)

View File

@ -26,7 +26,7 @@ namespace osu.Game.Database
if (score.IsLegacyScore)
return false;
if (score.TotalScoreVersion > 30000002)
if (score.TotalScoreVersion > 30000004)
return false;
// Recalculate the old-style standardised score to see if this was an old lazer score.
@ -249,14 +249,15 @@ namespace osu.Game.Database
int maximumLegacyAccuracyScore = attributes.AccuracyScore;
long maximumLegacyComboScore = (long)Math.Round(attributes.ComboScore * legacyModMultiplier);
double maximumLegacyBonusRatio = attributes.BonusScoreRatio;
long maximumLegacyBonusScore = attributes.BonusScore;
// The part of total score that doesn't include bonus.
double legacyAccScore = maximumLegacyAccuracyScore * score.Accuracy;
// We can not separate the ComboScore from the BonusScore, so we keep the bonus in the ratio.
double comboProportion =
((double)score.LegacyTotalScore - legacyAccScore) / (maximumLegacyComboScore + maximumLegacyBonusScore);
// We assume the bonus proportion only makes up the rest of the score that exceeds maximumLegacyBaseScore.
long maximumLegacyBaseScore = maximumLegacyAccuracyScore + maximumLegacyComboScore;
// The combo proportion is calculated as a proportion of maximumLegacyBaseScore.
double comboProportion = Math.Min(1, (double)score.LegacyTotalScore / maximumLegacyBaseScore);
// The bonus proportion makes up the rest of the score that exceeds maximumLegacyBaseScore.
double bonusProportion = Math.Max(0, ((long)score.LegacyTotalScore - maximumLegacyBaseScore) * maximumLegacyBonusRatio);
double modMultiplier = score.Mods.Select(m => m.ScoreMultiplier).Aggregate(1.0, (c, n) => c * n);
@ -264,9 +265,92 @@ namespace osu.Game.Database
switch (score.Ruleset.OnlineID)
{
case 0:
if (score.MaxCombo == 0 || score.Accuracy == 0)
{
return (long)Math.Round((
0
+ 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier);
}
// Assumptions:
// - sliders and slider ticks are uniformly distributed in the beatmap, and thus can be ignored without losing much precision.
// We thus consider a map of hit-circles only, which gives objectCount == maximumCombo.
// - the Ok/Meh hit results are uniformly spread in the score, and thus can be ignored without losing much precision.
// We simplify and consider each hit result to have the same hit value of `300 * score.Accuracy`
// (which represents the average hit value over the entire play),
// which allows us to isolate the accuracy multiplier.
// This is a very ballpark estimate of the maximum magnitude of the combo portion in score V1.
// It is derived by assuming a full combo play and summing up the contribution to combo portion from each individual object.
// Because each object's combo contribution is proportional to the current combo at the time of judgement,
// this can be roughly represented by summing / integrating f(combo) = combo.
// All mod- and beatmap-dependent multipliers and constants are not included here,
// as we will only be using the magnitude of this to compute ratios.
int maximumLegacyCombo = attributes.MaxCombo;
double maximumAchievableComboPortionInScoreV1 = Math.Pow(maximumLegacyCombo, 2);
// Similarly, estimate the maximum magnitude of the combo portion in standardised score.
// Roughly corresponds to integrating f(combo) = combo ^ COMBO_EXPONENT (omitting constants)
double maximumAchievableComboPortionInStandardisedScore = Math.Pow(maximumLegacyCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
double comboPortionInScoreV1 = maximumAchievableComboPortionInScoreV1 * comboProportion / score.Accuracy;
// This is - roughly - how much score, in the combo portion, the longest combo on this particular play would gain in score V1.
double comboPortionFromLongestComboInScoreV1 = Math.Pow(score.MaxCombo, 2);
// Same for standardised score.
double comboPortionFromLongestComboInStandardisedScore = Math.Pow(score.MaxCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
// Calculate how many times the longest combo the user has achieved in the play can repeat
// without exceeding the combo portion in score V1 as achieved by the player.
// This is a pessimistic estimate; it intentionally does not operate on object count and uses only score instead.
double maximumOccurrencesOfLongestCombo = Math.Floor(comboPortionInScoreV1 / comboPortionFromLongestComboInScoreV1);
double comboPortionFromRepeatedLongestCombosInScoreV1 = maximumOccurrencesOfLongestCombo * comboPortionFromLongestComboInScoreV1;
double remainingComboPortionInScoreV1 = comboPortionInScoreV1 - comboPortionFromRepeatedLongestCombosInScoreV1;
// `remainingComboPortionInScoreV1` is in the "score ballpark" realm, which means it's proportional to combo squared.
// To convert that back to a raw combo length, we need to take the square root...
double remainingCombo = Math.Sqrt(remainingComboPortionInScoreV1);
// ...and then based on that raw combo length, we calculate how much this last combo is worth in standardised score.
double remainingComboPortionInStandardisedScore = Math.Pow(remainingCombo, 1 + ScoreProcessor.COMBO_EXPONENT);
double lowerEstimateOfComboPortionInStandardisedScore
= maximumOccurrencesOfLongestCombo * comboPortionFromLongestComboInStandardisedScore
+ remainingComboPortionInStandardisedScore;
// Compute approximate upper estimate new score for that play.
// This time, divide the remaining combo among remaining objects equally to achieve longest possible combo lengths.
// There is no rigorous proof that doing this will yield a correct upper bound, but it seems to work out in practice.
remainingComboPortionInScoreV1 = comboPortionInScoreV1 - comboPortionFromLongestComboInScoreV1;
double remainingCountOfObjectsGivingCombo = maximumLegacyCombo - score.MaxCombo - score.Statistics.GetValueOrDefault(HitResult.Miss);
// Because we assumed all combos were equal, `remainingComboPortionInScoreV1`
// can be approximated by n * x^2, wherein n is the assumed number of equal combos,
// and x is the assumed length of every one of those combos.
// The remaining count of objects giving combo is, using those terms, equal to n * x.
// Therefore, dividing the two will result in x, i.e. the assumed length of the remaining combos.
double lengthOfRemainingCombos = remainingCountOfObjectsGivingCombo > 0
? remainingComboPortionInScoreV1 / remainingCountOfObjectsGivingCombo
: 0;
// In standardised scoring, each combo yields a score proportional to combo length to the power 1 + COMBO_EXPONENT.
// Using the symbols introduced above, that would be x ^ 1.5 per combo, n times (because there are n assumed equal-length combos).
// However, because `remainingCountOfObjectsGivingCombo` - using the symbols introduced above - is assumed to be equal to n * x,
// we can skip adding the 1 and just multiply by x ^ 0.5.
remainingComboPortionInStandardisedScore = remainingCountOfObjectsGivingCombo * Math.Pow(lengthOfRemainingCombos, ScoreProcessor.COMBO_EXPONENT);
double upperEstimateOfComboPortionInStandardisedScore = comboPortionFromLongestComboInStandardisedScore + remainingComboPortionInStandardisedScore;
// Approximate by combining lower and upper estimates.
// As the lower-estimate is very pessimistic, we use a 30/70 ratio
// and cap it with 1.2 times the middle-point to avoid overestimates.
double estimatedComboPortionInStandardisedScore = Math.Min(
0.3 * lowerEstimateOfComboPortionInStandardisedScore + 0.7 * upperEstimateOfComboPortionInStandardisedScore,
1.2 * (lowerEstimateOfComboPortionInStandardisedScore + upperEstimateOfComboPortionInStandardisedScore) / 2
);
double newComboScoreProportion = estimatedComboPortionInStandardisedScore / maximumAchievableComboPortionInStandardisedScore;
return (long)Math.Round((
700000 * comboProportion
+ 300000 * Math.Pow(score.Accuracy, 10)
500000 * newComboScoreProportion * score.Accuracy
+ 500000 * Math.Pow(score.Accuracy, 5)
+ bonusProportion) * modMultiplier);
case 1:

View File

@ -19,5 +19,15 @@ namespace osu.Game.Rulesets.Scoring.Legacy
/// A ratio of standardised score to legacy score for the bonus part of total score.
/// </summary>
public double BonusScoreRatio;
/// <summary>
/// The bonus portion of the legacy (ScoreV1) total score.
/// </summary>
public int BonusScore;
/// <summary>
/// The max combo of the legacy (ScoreV1) total score.
/// </summary>
public int MaxCombo;
}
}

View File

@ -21,6 +21,14 @@ namespace osu.Game.Rulesets.Scoring
{
public partial class ScoreProcessor : JudgementProcessor
{
/// <summary>
/// The exponent applied to combo in the default implementation of <see cref="GetComboScoreChange"/>.
/// </summary>
/// <remarks>
/// If a custom implementation overrides <see cref="GetComboScoreChange"/> this may not be relevant.
/// </remarks>
public const double COMBO_EXPONENT = 0.5;
public const double MAX_SCORE = 1000000;
private const double accuracy_cutoff_x = 1;
@ -293,7 +301,7 @@ namespace osu.Game.Rulesets.Scoring
protected virtual double GetBonusScoreChange(JudgementResult result) => Judgement.ToNumericResult(result.Type);
protected virtual double GetComboScoreChange(JudgementResult result) => Judgement.ToNumericResult(result.Type) * (1 + result.ComboAfterJudgement / 10d);
protected virtual double GetComboScoreChange(JudgementResult result) => Judgement.ToNumericResult(result.Judgement.MaxResult) * Math.Pow(result.ComboAfterJudgement, COMBO_EXPONENT);
protected virtual void ApplyScoreChange(JudgementResult result)
{
@ -317,8 +325,8 @@ namespace osu.Game.Rulesets.Scoring
protected virtual double ComputeTotalScore(double comboProgress, double accuracyProgress, double bonusPortion)
{
return 700000 * comboProgress +
300000 * Math.Pow(Accuracy.Value, 10) * accuracyProgress +
return 500000 * Accuracy.Value * comboProgress +
500000 * Math.Pow(Accuracy.Value, 5) * accuracyProgress +
bonusPortion;
}

View File

@ -31,9 +31,10 @@ namespace osu.Game.Scoring.Legacy
/// <item><description>30000002: Score stored to replay calculated using the Score V2 algorithm. Legacy scores on this version are candidate to Score V1 -> V2 conversion.</description></item>
/// <item><description>30000003: First version after converting legacy total score to standardised.</description></item>
/// <item><description>30000004: Fixed mod multipliers during legacy score conversion. Reconvert all scores.</description></item>
/// <item><description>30000005: Introduce combo exponent in the osu! gamemode. Reconvert all scores.</description></item>
/// </list>
/// </remarks>
public const int LATEST_VERSION = 30000004;
public const int LATEST_VERSION = 30000005;
/// <summary>
/// The first stable-compatible YYYYMMDD format version given to lazer usage of replays.