diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json new file mode 100644 index 0000000000..9357d3b75c --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -0,0 +1,957 @@ +{ + "Mappings": [{ + "StartTime": 500.0, + "Objects": [{ + "StartTime": 500.0, + "Position": 96.0 + }, { + "StartTime": 562.0, + "Position": 100.84 + }, { + "StartTime": 625.0, + "Position": 125.0 + }, { + "StartTime": 687.0, + "Position": 152.84 + }, { + "StartTime": 750.0, + "Position": 191.0 + }, { + "StartTime": 812.0, + "Position": 212.84 + }, { + "StartTime": 875.0, + "Position": 217.0 + }, { + "StartTime": 937.0, + "Position": 234.84 + }, { + "StartTime": 1000.0, + "Position": 256.0 + }, { + "StartTime": 1062.0, + "Position": 267.84 + }, { + "StartTime": 1125.0, + "Position": 284.0 + }, { + "StartTime": 1187.0, + "Position": 311.84 + }, { + "StartTime": 1250.0, + "Position": 350.0 + }, { + "StartTime": 1312.0, + "Position": 359.84 + }, { + "StartTime": 1375.0, + "Position": 367.0 + }, { + "StartTime": 1437.0, + "Position": 400.84 + }, { + "StartTime": 1500.0, + "Position": 416.0 + }, { + "StartTime": 1562.0, + "Position": 377.159973 + }, { + "StartTime": 1625.0, + "Position": 367.0 + }, { + "StartTime": 1687.0, + "Position": 374.159973 + }, { + "StartTime": 1750.0, + "Position": 353.0 + }, { + "StartTime": 1812.0, + "Position": 329.159973 + }, { + "StartTime": 1875.0, + "Position": 288.0 + }, { + "StartTime": 1937.0, + "Position": 259.159973 + }, { + "StartTime": 2000.0, + "Position": 256.0 + }, { + "StartTime": 2058.0, + "Position": 232.44 + }, { + "StartTime": 2116.0, + "Position": 222.879974 + }, { + "StartTime": 2174.0, + "Position": 185.319992 + }, { + "StartTime": 2232.0, + "Position": 177.76001 + }, { + "StartTime": 2290.0, + "Position": 162.200012 + }, { + "StartTime": 2348.0, + "Position": 158.639984 + }, { + "StartTime": 2406.0, + "Position": 111.079994 + }, { + "StartTime": 2500.0, + "Position": 96.0 + }] + }, { + "StartTime": 3000.0, + "Objects": [{ + "StartTime": 3000.0, + "Position": 18.0 + }, { + "StartTime": 3062.0, + "Position": 482.0 + }, { + "StartTime": 3125.0, + "Position": 243.0 + }, { + "StartTime": 3187.0, + "Position": 332.0 + }, { + "StartTime": 3250.0, + "Position": 477.0 + }, { + "StartTime": 3312.0, + "Position": 376.0 + }, { + "StartTime": 3375.0, + "Position": 104.0 + }, { + "StartTime": 3437.0, + "Position": 156.0 + }, { + "StartTime": 3500.0, + "Position": 135.0 + }, { + "StartTime": 3562.0, + "Position": 256.0 + }, { + "StartTime": 3625.0, + "Position": 360.0 + }, { + "StartTime": 3687.0, + "Position": 199.0 + }, { + "StartTime": 3750.0, + "Position": 239.0 + }, { + "StartTime": 3812.0, + "Position": 326.0 + }, { + "StartTime": 3875.0, + "Position": 393.0 + }, { + "StartTime": 3937.0, + "Position": 470.0 + }, { + "StartTime": 4000.0, + "Position": 136.0 + }] + }, { + "StartTime": 4500.0, + "Objects": [{ + "StartTime": 4500.0, + "Position": 317.0 + }, { + "StartTime": 4562.0, + "Position": 354.0 + }, { + "StartTime": 4625.0, + "Position": 414.0 + }, { + "StartTime": 4687.0, + "Position": 39.0 + }, { + "StartTime": 4750.0, + "Position": 172.0 + }, { + "StartTime": 4812.0, + "Position": 479.0 + }, { + "StartTime": 4875.0, + "Position": 18.0 + }, { + "StartTime": 4937.0, + "Position": 151.0 + }, { + "StartTime": 5000.0, + "Position": 342.0 + }, { + "StartTime": 5062.0, + "Position": 400.0 + }, { + "StartTime": 5125.0, + "Position": 420.0 + }, { + "StartTime": 5187.0, + "Position": 90.0 + }, { + "StartTime": 5250.0, + "Position": 220.0 + }, { + "StartTime": 5312.0, + "Position": 80.0 + }, { + "StartTime": 5375.0, + "Position": 421.0 + }, { + "StartTime": 5437.0, + "Position": 473.0 + }, { + "StartTime": 5500.0, + "Position": 97.0 + }] + }, { + "StartTime": 6000.0, + "Objects": [{ + "StartTime": 6000.0, + "Position": 105.0 + }, { + "StartTime": 6062.0, + "Position": 249.0 + }, { + "StartTime": 6125.0, + "Position": 163.0 + }, { + "StartTime": 6187.0, + "Position": 194.0 + }, { + "StartTime": 6250.0, + "Position": 106.0 + }, { + "StartTime": 6312.0, + "Position": 212.0 + }, { + "StartTime": 6375.0, + "Position": 257.0 + }, { + "StartTime": 6437.0, + "Position": 461.0 + }, { + "StartTime": 6500.0, + "Position": 79.0 + }] + }, { + "StartTime": 7000.0, + "Objects": [{ + "StartTime": 7000.0, + "Position": 256.0 + }, { + "StartTime": 7062.0, + "Position": 294.84 + }, { + "StartTime": 7125.0, + "Position": 279.0 + }, { + "StartTime": 7187.0, + "Position": 309.84 + }, { + "StartTime": 7250.0, + "Position": 336.0 + }, { + "StartTime": 7312.0, + "Position": 322.16 + }, { + "StartTime": 7375.0, + "Position": 308.0 + }, { + "StartTime": 7437.0, + "Position": 263.16 + }, { + "StartTime": 7500.0, + "Position": 256.0 + }, { + "StartTime": 7562.0, + "Position": 261.84 + }, { + "StartTime": 7625.0, + "Position": 277.0 + }, { + "StartTime": 7687.0, + "Position": 318.84 + }, { + "StartTime": 7750.0, + "Position": 336.0 + }, { + "StartTime": 7803.0, + "Position": 305.04 + }, { + "StartTime": 7857.0, + "Position": 307.76 + }, { + "StartTime": 7910.0, + "Position": 297.8 + }, { + "StartTime": 8000.0, + "Position": 256.0 + }] + }, { + "StartTime": 8500.0, + "Objects": [{ + "StartTime": 8500.0, + "Position": 32.0 + }, { + "StartTime": 8562.0, + "Position": 22.8515015 + }, { + "StartTime": 8625.0, + "Position": 28.5659637 + }, { + "StartTime": 8687.0, + "Position": 50.3433228 + }, { + "StartTime": 8750.0, + "Position": 56.58974 + }, { + "StartTime": 8812.0, + "Position": 64.23422 + }, { + "StartTime": 8875.0, + "Position": 67.7117844 + }, { + "StartTime": 8937.0, + "Position": 90.52607 + }, { + "StartTime": 9000.0, + "Position": 101.81015 + }, { + "StartTime": 9062.0, + "Position": 113.478188 + }, { + "StartTime": 9125.0, + "Position": 159.414444 + }, { + "StartTime": 9187.0, + "Position": 155.1861 + }, { + "StartTime": 9250.0, + "Position": 179.600418 + }, { + "StartTime": 9312.0, + "Position": 212.293015 + }, { + "StartTime": 9375.0, + "Position": 197.2076 + }, { + "StartTime": 9437.0, + "Position": 243.438324 + }, { + "StartTime": 9500.0, + "Position": 237.2304 + }, { + "StartTime": 9562.0, + "Position": 241.253983 + }, { + "StartTime": 9625.0, + "Position": 258.950623 + }, { + "StartTime": 9687.0, + "Position": 253.3786 + }, { + "StartTime": 9750.0, + "Position": 270.8865 + }, { + "StartTime": 9812.0, + "Position": 244.38974 + }, { + "StartTime": 9875.0, + "Position": 242.701874 + }, { + "StartTime": 9937.0, + "Position": 256.2331 + }, { + "StartTime": 10000.0, + "Position": 270.339874 + }, { + "StartTime": 10062.0, + "Position": 275.9349 + }, { + "StartTime": 10125.0, + "Position": 297.2969 + }, { + "StartTime": 10187.0, + "Position": 307.834137 + }, { + "StartTime": 10250.0, + "Position": 321.6449 + }, { + "StartTime": 10312.0, + "Position": 357.746338 + }, { + "StartTime": 10375.0, + "Position": 358.21875 + }, { + "StartTime": 10437.0, + "Position": 394.943 + }, { + "StartTime": 10500.0, + "Position": 401.0588 + }, { + "StartTime": 10558.0, + "Position": 418.21347 + }, { + "StartTime": 10616.0, + "Position": 424.6034 + }, { + "StartTime": 10674.0, + "Position": 455.835754 + }, { + "StartTime": 10732.0, + "Position": 477.5042 + }, { + "StartTime": 10790.0, + "Position": 476.290955 + }, { + "StartTime": 10848.0, + "Position": 470.943237 + }, { + "StartTime": 10906.0, + "Position": 503.3372 + }, { + "StartTime": 10999.0, + "Position": 508.166229 + }] + }, { + "StartTime": 11500.0, + "Objects": [{ + "StartTime": 11500.0, + "Position": 321.0 + }, { + "StartTime": 11562.0, + "Position": 17.0 + }, { + "StartTime": 11625.0, + "Position": 173.0 + }, { + "StartTime": 11687.0, + "Position": 170.0 + }, { + "StartTime": 11750.0, + "Position": 447.0 + }, { + "StartTime": 11812.0, + "Position": 218.0 + }, { + "StartTime": 11875.0, + "Position": 394.0 + }, { + "StartTime": 11937.0, + "Position": 46.0 + }, { + "StartTime": 12000.0, + "Position": 480.0 + }] + }, { + "StartTime": 12500.0, + "Objects": [{ + "StartTime": 12500.0, + "Position": 512.0 + }, { + "StartTime": 12562.0, + "Position": 491.3132 + }, { + "StartTime": 12625.0, + "Position": 484.3089 + }, { + "StartTime": 12687.0, + "Position": 454.6221 + }, { + "StartTime": 12750.0, + "Position": 433.617767 + }, { + "StartTime": 12812.0, + "Position": 399.930969 + }, { + "StartTime": 12875.0, + "Position": 395.926666 + }, { + "StartTime": 12937.0, + "Position": 361.239868 + }, { + "StartTime": 13000.0, + "Position": 353.235535 + }, { + "StartTime": 13062.0, + "Position": 314.548767 + }, { + "StartTime": 13125.0, + "Position": 315.544434 + }, { + "StartTime": 13187.0, + "Position": 288.857635 + }, { + "StartTime": 13250.0, + "Position": 254.853333 + }, { + "StartTime": 13312.0, + "Position": 239.166534 + }, { + "StartTime": 13375.0, + "Position": 240.1622 + }, { + "StartTime": 13437.0, + "Position": 212.4754 + }, { + "StartTime": 13500.0, + "Position": 194.471069 + }, { + "StartTime": 13562.0, + "Position": 161.784271 + }, { + "StartTime": 13625.0, + "Position": 145.779968 + }, { + "StartTime": 13687.0, + "Position": 129.09314 + }, { + "StartTime": 13750.0, + "Position": 104.088837 + }, { + "StartTime": 13812.0, + "Position": 95.40204 + }, { + "StartTime": 13875.0, + "Position": 61.3977356 + }, { + "StartTime": 13937.0, + "Position": 56.710907 + }, { + "StartTime": 14000.0, + "Position": 35.7066345 + }, { + "StartTime": 14062.0, + "Position": 5.019806 + }, { + "StartTime": 14125.0, + "Position": 0.0 + }, { + "StartTime": 14187.0, + "Position": 39.7696266 + }, { + "StartTime": 14250.0, + "Position": 23.0119171 + }, { + "StartTime": 14312.0, + "Position": 75.94882 + }, { + "StartTime": 14375.0, + "Position": 98.19112 + }, { + "StartTime": 14437.0, + "Position": 82.12803 + }, { + "StartTime": 14500.0, + "Position": 118.370323 + }, { + "StartTime": 14562.0, + "Position": 149.307236 + }, { + "StartTime": 14625.0, + "Position": 168.549515 + }, { + "StartTime": 14687.0, + "Position": 190.486435 + }, { + "StartTime": 14750.0, + "Position": 186.728714 + }, { + "StartTime": 14812.0, + "Position": 199.665634 + }, { + "StartTime": 14875.0, + "Position": 228.907928 + }, { + "StartTime": 14937.0, + "Position": 264.844849 + }, { + "StartTime": 15000.0, + "Position": 271.087128 + }, { + "StartTime": 15062.0, + "Position": 290.024017 + }, { + "StartTime": 15125.0, + "Position": 302.266327 + }, { + "StartTime": 15187.0, + "Position": 344.203247 + }, { + "StartTime": 15250.0, + "Position": 356.445526 + }, { + "StartTime": 15312.0, + "Position": 359.382446 + }, { + "StartTime": 15375.0, + "Position": 401.624725 + }, { + "StartTime": 15437.0, + "Position": 388.561646 + }, { + "StartTime": 15500.0, + "Position": 423.803925 + }, { + "StartTime": 15562.0, + "Position": 425.740845 + }, { + "StartTime": 15625.0, + "Position": 449.983124 + }, { + "StartTime": 15687.0, + "Position": 468.920044 + }, { + "StartTime": 15750.0, + "Position": 492.162323 + }, { + "StartTime": 15812.0, + "Position": 506.784332 + }, { + "StartTime": 15875.0, + "Position": 474.226227 + }, { + "StartTime": 15937.0, + "Position": 482.978638 + }, { + "StartTime": 16000.0, + "Position": 446.420532 + }, { + "StartTime": 16058.0, + "Position": 418.4146 + }, { + "StartTime": 16116.0, + "Position": 425.408844 + }, { + "StartTime": 16174.0, + "Position": 383.402924 + }, { + "StartTime": 16232.0, + "Position": 363.397156 + }, { + "StartTime": 16290.0, + "Position": 343.391235 + }, { + "StartTime": 16348.0, + "Position": 328.385468 + }, { + "StartTime": 16406.0, + "Position": 322.3797 + }, { + "StartTime": 16500.0, + "Position": 291.1977 + }] + }, { + "StartTime": 17000.0, + "Objects": [{ + "StartTime": 17000.0, + "Position": 256.0 + }, { + "StartTime": 17062.0, + "Position": 228.16 + }, { + "StartTime": 17125.0, + "Position": 234.0 + }, { + "StartTime": 17187.0, + "Position": 202.16 + }, { + "StartTime": 17250.0, + "Position": 176.0 + }, { + "StartTime": 17312.0, + "Position": 210.84 + }, { + "StartTime": 17375.0, + "Position": 221.0 + }, { + "StartTime": 17437.0, + "Position": 219.84 + }, { + "StartTime": 17500.0, + "Position": 256.0 + }, { + "StartTime": 17562.0, + "Position": 219.16 + }, { + "StartTime": 17625.0, + "Position": 228.0 + }, { + "StartTime": 17687.0, + "Position": 203.16 + }, { + "StartTime": 17750.0, + "Position": 176.0 + }, { + "StartTime": 17803.0, + "Position": 174.959991 + }, { + "StartTime": 17857.0, + "Position": 214.23999 + }, { + "StartTime": 17910.0, + "Position": 228.200012 + }, { + "StartTime": 18000.0, + "Position": 256.0 + }] + }, { + "StartTime": 18500.0, + "Objects": [{ + "StartTime": 18500.0, + "Position": 362.0 + }, { + "StartTime": 18559.0, + "Position": 249.0 + }, { + "StartTime": 18618.0, + "Position": 357.0 + }, { + "StartTime": 18678.0, + "Position": 167.0 + }, { + "StartTime": 18737.0, + "Position": 477.0 + }, { + "StartTime": 18796.0, + "Position": 411.0 + }, { + "StartTime": 18856.0, + "Position": 254.0 + }, { + "StartTime": 18915.0, + "Position": 308.0 + }, { + "StartTime": 18975.0, + "Position": 399.0 + }, { + "StartTime": 19034.0, + "Position": 176.0 + }, { + "StartTime": 19093.0, + "Position": 14.0 + }, { + "StartTime": 19153.0, + "Position": 258.0 + }, { + "StartTime": 19212.0, + "Position": 221.0 + }, { + "StartTime": 19271.0, + "Position": 481.0 + }, { + "StartTime": 19331.0, + "Position": 92.0 + }, { + "StartTime": 19390.0, + "Position": 211.0 + }, { + "StartTime": 19450.0, + "Position": 135.0 + }] + }, { + "StartTime": 19875.0, + "Objects": [{ + "StartTime": 19875.0, + "Position": 216.0 + }, { + "StartTime": 19937.0, + "Position": 215.307053 + }, { + "StartTime": 20000.0, + "Position": 236.036865 + }, { + "StartTime": 20062.0, + "Position": 236.312088 + }, { + "StartTime": 20125.0, + "Position": 235.838928 + }, { + "StartTime": 20187.0, + "Position": 269.9743 + }, { + "StartTime": 20250.0, + "Position": 285.999146 + }, { + "StartTime": 20312.0, + "Position": 283.669067 + }, { + "StartTime": 20375.0, + "Position": 317.446747 + }, { + "StartTime": 20437.0, + "Position": 330.750275 + }, { + "StartTime": 20500.0, + "Position": 344.0156 + }, { + "StartTime": 20562.0, + "Position": 318.472168 + }, { + "StartTime": 20625.0, + "Position": 309.165466 + }, { + "StartTime": 20687.0, + "Position": 317.044617 + }, { + "StartTime": 20750.0, + "Position": 280.457367 + }, { + "StartTime": 20812.0, + "Position": 272.220581 + }, { + "StartTime": 20875.0, + "Position": 270.3294 + }, { + "StartTime": 20937.0, + "Position": 262.57605 + }, { + "StartTime": 21000.0, + "Position": 244.803329 + }, { + "StartTime": 21062.0, + "Position": 215.958359 + }, { + "StartTime": 21125.0, + "Position": 177.79332 + }, { + "StartTime": 21187.0, + "Position": 190.948349 + }, { + "StartTime": 21250.0, + "Position": 158.78334 + }, { + "StartTime": 21312.0, + "Position": 136.93837 + }, { + "StartTime": 21375.0, + "Position": 119.121056 + }, { + "StartTime": 21437.0, + "Position": 132.387573 + }, { + "StartTime": 21500.0, + "Position": 124.503014 + }, { + "StartTime": 21562.0, + "Position": 118.749374 + }, { + "StartTime": 21625.0, + "Position": 123.165535 + }, { + "StartTime": 21687.0, + "Position": 96.02999 + }, { + "StartTime": 21750.0, + "Position": 118.547928 + }, { + "StartTime": 21812.0, + "Position": 128.856232 + }, { + "StartTime": 21875.0, + "Position": 124.28746 + }, { + "StartTime": 21937.0, + "Position": 150.754929 + }, { + "StartTime": 22000.0, + "Position": 149.528732 + }, { + "StartTime": 22062.0, + "Position": 145.1691 + }, { + "StartTime": 22125.0, + "Position": 182.802155 + }, { + "StartTime": 22187.0, + "Position": 178.6452 + }, { + "StartTime": 22250.0, + "Position": 213.892181 + }, { + "StartTime": 22312.0, + "Position": 218.713028 + }, { + "StartTime": 22375.0, + "Position": 240.4715 + }, { + "StartTime": 22437.0, + "Position": 239.371887 + }, { + "StartTime": 22500.0, + "Position": 261.907257 + }, { + "StartTime": 22562.0, + "Position": 314.353119 + }, { + "StartTime": 22625.0, + "Position": 299.273376 + }, { + "StartTime": 22687.0, + "Position": 356.98288 + }, { + "StartTime": 22750.0, + "Position": 339.078552 + }, { + "StartTime": 22812.0, + "Position": 377.8958 + }, { + "StartTime": 22875.0, + "Position": 398.054047 + }, { + "StartTime": 22937.0, + "Position": 398.739441 + }, { + "StartTime": 23000.0, + "Position": 407.178467 + }, { + "StartTime": 23062.0, + "Position": 444.8687 + }, { + "StartTime": 23125.0, + "Position": 417.069977 + }, { + "StartTime": 23187.0, + "Position": 454.688477 + }, { + "StartTime": 23250.0, + "Position": 428.9612 + }, { + "StartTime": 23312.0, + "Position": 441.92807 + }, { + "StartTime": 23375.0, + "Position": 439.749878 + }, { + "StartTime": 23433.0, + "Position": 455.644684 + }, { + "StartTime": 23491.0, + "Position": 440.7359 + }, { + "StartTime": 23549.0, + "Position": 430.0944 + }, { + "StartTime": 23607.0, + "Position": 420.796173 + }, { + "StartTime": 23665.0, + "Position": 435.897461 + }, { + "StartTime": 23723.0, + "Position": 418.462555 + }, { + "StartTime": 23781.0, + "Position": 405.53775 + }, { + "StartTime": 23874.0, + "Position": 408.720825 + }] + }] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic.osu new file mode 100644 index 0000000000..40b4409760 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/basic.osu @@ -0,0 +1,27 @@ +osu file format v14 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8.3 +SliderMultiplier:1.6 +SliderTickRate:1 + +[TimingPoints] +500,500,4,2,1,50,1,0 +13426,-100,4,3,1,45,0,0 +14884,-100,4,2,1,50,0,0 + +[HitObjects] +96,192,500,6,0,L|416:192,2,320 +256,192,3000,12,0,4000,0:0:0:0: +256,192,4500,12,0,5500,0:0:0:0: +256,192,6000,12,0,6500,0:0:0:0: +256,128,7000,6,0,L|352:128,4,80 +32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800 +256,192,11500,12,0,12000,0:0:0:0: +512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280 +256,256,17000,6,0,L|160:256,4,80 +256,192,18500,12,0,19450,0:0:0:0: +216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280 diff --git a/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs new file mode 100644 index 0000000000..826c900140 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Tests/CatchBeatmapConversionTest.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Catch.Beatmaps; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Objects; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Rulesets.Catch.Tests +{ + public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue> + { + protected override string ResourceAssembly => "osu.Game.Rulesets.Catch"; + + [TestCase("basic"), Ignore("See: https://github.com/ppy/osu/issues/2149")] + public new void Test(string name) + { + base.Test(name); + } + + protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject) + { + if (hitObject is JuiceStream stream) + { + foreach (var nested in stream.NestedHitObjects) + { + yield return new ConvertValue + { + StartTime = nested.StartTime, + Position = ((CatchHitObject)nested).X * CatchPlayfield.BASE_WIDTH + }; + } + } + else + { + yield return new ConvertValue + { + StartTime = hitObject.StartTime, + Position = ((CatchHitObject)hitObject).X * CatchPlayfield.BASE_WIDTH + }; + } + } + + protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new CatchBeatmapConverter(); + } + + public struct ConvertValue : IEquatable<ConvertValue> + { + /// <summary> + /// A sane value to account for osu!stable using ints everwhere. + /// </summary> + private const float conversion_lenience = 2; + + public double StartTime; + public float Position; + + public bool Equals(ConvertValue other) + => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience) + && Precision.AlmostEquals(Position, other.Position, conversion_lenience); + } +} diff --git a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj index 894fdc9b45..4e2cdd24c3 100644 --- a/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj +++ b/osu.Game.Rulesets.Catch/osu.Game.Rulesets.Catch.csproj @@ -95,6 +95,7 @@ <Compile Include="Objects\Fruit.cs" /> <Compile Include="Objects\TinyDroplet.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Tests\CatchBeatmapConversionTest.cs" /> <Compile Include="Tests\TestCaseBananaShower.cs" /> <Compile Include="Tests\TestCaseCatcherArea.cs" /> <Compile Include="Tests\TestCaseCatchStacker.cs" /> @@ -128,6 +129,10 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" /> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/basic-expected-conversion.json new file mode 100644 index 0000000000..d593b2b052 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -0,0 +1,103 @@ +{ + "Mappings": [{ + "StartTime": 500, + "Objects": [{ + "StartTime": 500, + "EndTime": 2500, + "Column": 0 + }, + { + "StartTime": 1500, + "EndTime": 2500, + "Column": 1 + } + ] + }, + { + "StartTime": 3000, + "Objects": [{ + "StartTime": 3000, + "EndTime": 4000, + "Column": 2 + }] + }, + { + "StartTime": 4500, + "Objects": [{ + "StartTime": 4500, + "EndTime": 5500, + "Column": 4 + }] + }, + { + "StartTime": 6000, + "Objects": [{ + "StartTime": 6000, + "EndTime": 6500, + "Column": 2 + }] + }, + { + "StartTime": 7000, + "Objects": [{ + "StartTime": 7000, + "EndTime": 8000, + "Column": 2 + }] + }, + { + "StartTime": 8500, + "Objects": [{ + "StartTime": 8500, + "EndTime": 11000, + "Column": 0 + }] + }, + { + "StartTime": 11500, + "Objects": [{ + "StartTime": 11500, + "EndTime": 12000, + "Column": 1 + }] + }, + { + "StartTime": 12500, + "Objects": [{ + "StartTime": 12500, + "EndTime": 16500, + "Column": 4 + }] + }, + { + "StartTime": 17000, + "Objects": [{ + "StartTime": 17000, + "EndTime": 18000, + "Column": 2 + }] + }, + { + "StartTime": 18500, + "Objects": [{ + "StartTime": 18500, + "EndTime": 19450, + "Column": 0 + }] + }, + { + "StartTime": 19875, + "Objects": [{ + "StartTime": 19875, + "EndTime": 23875, + "Column": 1 + }, + { + "StartTime": 19875, + "EndTime": 23875, + "Column": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/basic.osu b/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/basic.osu new file mode 100644 index 0000000000..40b4409760 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Resources/Testing/Beatmaps/basic.osu @@ -0,0 +1,27 @@ +osu file format v14 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8.3 +SliderMultiplier:1.6 +SliderTickRate:1 + +[TimingPoints] +500,500,4,2,1,50,1,0 +13426,-100,4,3,1,45,0,0 +14884,-100,4,2,1,50,0,0 + +[HitObjects] +96,192,500,6,0,L|416:192,2,320 +256,192,3000,12,0,4000,0:0:0:0: +256,192,4500,12,0,5500,0:0:0:0: +256,192,6000,12,0,6500,0:0:0:0: +256,128,7000,6,0,L|352:128,4,80 +32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800 +256,192,11500,12,0,12000,0:0:0:0: +512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280 +256,256,17000,6,0,L|160:256,4,80 +256,192,18500,12,0,19450,0:0:0:0: +216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280 diff --git a/osu.Game.Rulesets.Mania/Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania/Tests/ManiaBeatmapConversionTest.cs new file mode 100644 index 0000000000..2095addc72 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Tests/ManiaBeatmapConversionTest.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Rulesets.Mania.Tests +{ + public class ManiaBeatmapConversionTest : BeatmapConversionTest<ConvertValue> + { + protected override string ResourceAssembly => "osu.Game.Rulesets.Mania"; + + private bool isForCurrentRuleset; + + [NonParallelizable] + [TestCase("basic", false), Ignore("See: https://github.com/ppy/osu/issues/2150")] + public void Test(string name, bool isForCurrentRuleset) + { + this.isForCurrentRuleset = isForCurrentRuleset; + base.Test(name); + } + + protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject) + { + yield return new ConvertValue + { + StartTime = hitObject.StartTime, + EndTime = (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime, + Column = ((ManiaHitObject)hitObject).Column + }; + } + + protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new ManiaBeatmapConverter(isForCurrentRuleset, beatmap); + } + + public struct ConvertValue : IEquatable<ConvertValue> + { + /// <summary> + /// A sane value to account for osu!stable using ints everwhere. + /// </summary> + private const float conversion_lenience = 2; + + public double StartTime; + public double EndTime; + public int Column; + + public bool Equals(ConvertValue other) + => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience) + && Precision.AlmostEquals(EndTime, other.EndTime, conversion_lenience) + && Column == other.Column; + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index a2e21e2053..a09b3e93a7 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -126,6 +126,7 @@ <Compile Include="Objects\Note.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="ManiaInputManager.cs" /> + <Compile Include="Tests\ManiaBeatmapConversionTest.cs" /> <Compile Include="Tests\TestCaseAutoGeneration.cs" /> <Compile Include="Tests\TestCaseManiaHitObjects.cs" /> <Compile Include="Tests\TestCaseManiaPlayfield.cs" /> @@ -159,6 +160,10 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" /> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json new file mode 100644 index 0000000000..b82fddbe79 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -0,0 +1,124 @@ +{ + "Mappings": [{ + "StartTime": 500, + "Objects": [{ + "StartTime": 500, + "EndTime": 2500, + "StartX": 96, + "StartY": 192, + "EndX": 96, + "EndY": 192 + }] + }, + { + "StartTime": 3000, + "Objects": [{ + "StartTime": 3000, + "EndTime": 4000, + "StartX": 256, + "StartY": 192, + "EndX": 256, + "EndY": 192 + }] + }, + { + "StartTime": 4500, + "Objects": [{ + "StartTime": 4500, + "EndTime": 5500, + "StartX": 256, + "StartY": 192, + "EndX": 256, + "EndY": 192 + }] + }, + { + "StartTime": 6000, + "Objects": [{ + "StartTime": 6000, + "EndTime": 6500, + "StartX": 256, + "StartY": 192, + "EndX": 256, + "EndY": 192 + }] + }, + { + "StartTime": 7000, + "Objects": [{ + "StartTime": 7000, + "EndTime": 8000, + "StartX": 256, + "StartY": 128, + "EndX": 256, + "EndY": 128 + }] + }, + { + "StartTime": 8500, + "Objects": [{ + "StartTime": 8500, + "EndTime": 10999, + "StartX": 32, + "StartY": 192, + "EndX": 508.166229, + "EndY": 153.299271 + }] + }, + { + "StartTime": 11500, + "Objects": [{ + "StartTime": 11500, + "EndTime": 12000, + "StartX": 256, + "StartY": 192, + "EndX": 256, + "EndY": 192 + }] + }, + { + "StartTime": 12500, + "Objects": [{ + "StartTime": 12500, + "EndTime": 16500, + "StartX": 512, + "StartY": 320, + "EndX": 291.1977, + "EndY": 40.799427 + }] + }, + { + "StartTime": 17000, + "Objects": [{ + "StartTime": 17000, + "EndTime": 18000, + "StartX": 256, + "StartY": 256, + "EndX": 256, + "EndY": 256 + }] + }, + { + "StartTime": 18500, + "Objects": [{ + "StartTime": 18500, + "EndTime": 19450, + "StartX": 256, + "StartY": 192, + "EndX": 256, + "EndY": 192 + }] + }, + { + "StartTime": 19875, + "Objects": [{ + "StartTime": 19875, + "EndTime": 23874, + "StartX": 216, + "StartY": 231, + "EndX": 408.720825, + "EndY": 339.810455 + }] + } + ] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic.osu b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic.osu new file mode 100644 index 0000000000..40b4409760 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Resources/Testing/Beatmaps/basic.osu @@ -0,0 +1,27 @@ +osu file format v14 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8.3 +SliderMultiplier:1.6 +SliderTickRate:1 + +[TimingPoints] +500,500,4,2,1,50,1,0 +13426,-100,4,3,1,45,0,0 +14884,-100,4,2,1,50,0,0 + +[HitObjects] +96,192,500,6,0,L|416:192,2,320 +256,192,3000,12,0,4000,0:0:0:0: +256,192,4500,12,0,5500,0:0:0:0: +256,192,6000,12,0,6500,0:0:0:0: +256,128,7000,6,0,L|352:128,4,80 +32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800 +256,192,11500,12,0,12000,0:0:0:0: +512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280 +256,256,17000,6,0,L|160:256,4,80 +256,192,18500,12,0,19450,0:0:0:0: +216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280 diff --git a/osu.Game.Rulesets.Osu/Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu/Tests/OsuBeatmapConversionTest.cs new file mode 100644 index 0000000000..a98f002a4b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Tests/OsuBeatmapConversionTest.cs @@ -0,0 +1,69 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Tests.Beatmaps; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class OsuBeatmapConversionTest : BeatmapConversionTest<ConvertValue> + { + protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; + + [TestCase("basic")] + public new void Test(string name) + { + base.Test(name); + } + + protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject) + { + var startPosition = (hitObject as IHasPosition)?.Position ?? new Vector2(256, 192); + var endPosition = (hitObject as Slider)?.EndPosition ?? startPosition; + + yield return new ConvertValue + { + StartTime = hitObject.StartTime, + EndTime = (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime, + StartX = startPosition.X, + StartY = startPosition.Y, + EndX = endPosition.X, + EndY = endPosition.Y + }; + } + + protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new OsuBeatmapConverter(); + } + + public struct ConvertValue : IEquatable<ConvertValue> + { + /// <summary> + /// A sane value to account for osu!stable using ints everwhere. + /// </summary> + private const double conversion_lenience = 2; + + public double StartTime; + public double EndTime; + public float StartX; + public float StartY; + public float EndX; + public float EndY; + + public bool Equals(ConvertValue other) + => Precision.AlmostEquals(StartTime, other.StartTime) + && Precision.AlmostEquals(EndTime, other.EndTime, conversion_lenience) + && Precision.AlmostEquals(StartX, other.StartX) + && Precision.AlmostEquals(StartY, other.StartY, conversion_lenience) + && Precision.AlmostEquals(EndX, other.EndX, conversion_lenience) + && Precision.AlmostEquals(EndY, other.EndY, conversion_lenience); + } +} diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 1407c05425..01dda307bc 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -127,6 +127,7 @@ <Compile Include="OsuDifficulty\Utils\History.cs" /> <Compile Include="OsuInputManager.cs" /> <Compile Include="Replays\OsuReplayInputHandler.cs" /> + <Compile Include="Tests\OsuBeatmapConversionTest.cs" /> <Compile Include="Tests\TestCaseHitCircle.cs" /> <Compile Include="Tests\TestCaseHitCircleHidden.cs" /> <Compile Include="Tests\TestCasePerformancePoints.cs" /> @@ -172,6 +173,10 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" /> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/basic-expected-conversion.json b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/basic-expected-conversion.json new file mode 100644 index 0000000000..5c9310fec7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/basic-expected-conversion.json @@ -0,0 +1,209 @@ +{ + "Mappings": [{ + "StartTime": 500, + "Objects": [{ + "StartTime": 500, + "EndTime": 2499, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": true, + "IsSwell": false, + "IsStrong": false + }] + }, + { + "StartTime": 3000, + "Objects": [{ + "StartTime": 3000, + "EndTime": 4000, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": false, + "IsSwell": true, + "IsStrong": false + }] + }, + { + "StartTime": 4500, + "Objects": [{ + "StartTime": 4500, + "EndTime": 5500, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": false, + "IsSwell": true, + "IsStrong": false + }] + }, + { + "StartTime": 6000, + "Objects": [{ + "StartTime": 6000, + "EndTime": 6500, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": false, + "IsSwell": true, + "IsStrong": false + }] + }, + { + "StartTime": 7000, + "Objects": [{ + "StartTime": 7000, + "EndTime": 7000, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 7249, + "EndTime": 7249, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 7499, + "EndTime": 7499, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 7749, + "EndTime": 7749, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 7999, + "EndTime": 7999, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + } + ] + }, + { + "StartTime": 8500, + "Objects": [{ + "StartTime": 8500, + "EndTime": 10999, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": true, + "IsSwell": false, + "IsStrong": false + }] + }, + { + "StartTime": 11500, + "Objects": [{ + "StartTime": 11500, + "EndTime": 12000, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": false, + "IsSwell": true, + "IsStrong": false + }] + }, + { + "StartTime": 12500, + "Objects": [{ + "StartTime": 12500, + "EndTime": 16499, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": true, + "IsSwell": false, + "IsStrong": false + }] + }, + { + "StartTime": 17000, + "Objects": [{ + "StartTime": 17000, + "EndTime": 17000, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 17249, + "EndTime": 17249, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 17499, + "EndTime": 17499, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 17749, + "EndTime": 17749, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + }, + { + "StartTime": 17999, + "EndTime": 17999, + "IsRim": false, + "IsCentre": true, + "IsDrumRoll": false, + "IsSwell": false, + "IsStrong": false + } + ] + }, + { + "StartTime": 18500, + "Objects": [{ + "StartTime": 18500, + "EndTime": 19450, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": false, + "IsSwell": true, + "IsStrong": false + }] + }, + { + "StartTime": 19875, + "Objects": [{ + "StartTime": 19875, + "EndTime": 23874, + "IsRim": false, + "IsCentre": false, + "IsDrumRoll": true, + "IsSwell": false, + "IsStrong": false + }] + } + ] +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/basic.osu b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/basic.osu new file mode 100644 index 0000000000..40b4409760 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Resources/Testing/Beatmaps/basic.osu @@ -0,0 +1,27 @@ +osu file format v14 + +[Difficulty] +HPDrainRate:6 +CircleSize:4 +OverallDifficulty:7 +ApproachRate:8.3 +SliderMultiplier:1.6 +SliderTickRate:1 + +[TimingPoints] +500,500,4,2,1,50,1,0 +13426,-100,4,3,1,45,0,0 +14884,-100,4,2,1,50,0,0 + +[HitObjects] +96,192,500,6,0,L|416:192,2,320 +256,192,3000,12,0,4000,0:0:0:0: +256,192,4500,12,0,5500,0:0:0:0: +256,192,6000,12,0,6500,0:0:0:0: +256,128,7000,6,0,L|352:128,4,80 +32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800 +256,192,11500,12,0,12000,0:0:0:0: +512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280 +256,256,17000,6,0,L|160:256,4,80 +256,192,18500,12,0,19450,0:0:0:0: +216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280 diff --git a/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs new file mode 100644 index 0000000000..64f728a018 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Tests/TaikoBeatmapConversionTest.cs @@ -0,0 +1,72 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.MathUtils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Taiko.Beatmaps; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TaikoBeatmapConversionTest : BeatmapConversionTest<ConvertValue> + { + protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; + + private bool isForCurrentRuleset; + + [NonParallelizable] + [TestCase("basic", false), Ignore("See: https://github.com/ppy/osu/issues/2152")] + public void Test(string name, bool isForCurrentRuleset) + { + this.isForCurrentRuleset = isForCurrentRuleset; + base.Test(name); + } + + protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject) + { + yield return new ConvertValue + { + StartTime = hitObject.StartTime, + EndTime = (hitObject as IHasEndTime)?.EndTime ?? hitObject.StartTime, + IsRim = hitObject is RimHit, + IsCentre = hitObject is CentreHit, + IsDrumRoll = hitObject is DrumRoll, + IsSwell = hitObject is Swell, + IsStrong = ((TaikoHitObject)hitObject).IsStrong + }; + } + + protected override IBeatmapConverter CreateConverter(Beatmap beatmap) => new TaikoBeatmapConverter(isForCurrentRuleset); + } + + public struct ConvertValue : IEquatable<ConvertValue> + { + /// <summary> + /// A sane value to account for osu!stable using ints everwhere. + /// </summary> + private const float conversion_lenience = 2; + + public double StartTime; + public double EndTime; + public bool IsRim; + public bool IsCentre; + public bool IsDrumRoll; + public bool IsSwell; + public bool IsStrong; + + public bool Equals(ConvertValue other) + => Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience) + && Precision.AlmostEquals(EndTime, other.EndTime, conversion_lenience) + && IsRim == other.IsRim + && IsCentre == other.IsCentre + && IsDrumRoll == other.IsDrumRoll + && IsSwell == other.IsSwell + && IsStrong == other.IsStrong; + } +} diff --git a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj index db2db9fff1..07d27455b8 100644 --- a/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj +++ b/osu.Game.Rulesets.Taiko/osu.Game.Rulesets.Taiko.csproj @@ -112,6 +112,7 @@ <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Scoring\TaikoScoreProcessor.cs" /> <Compile Include="TaikoInputManager.cs" /> + <Compile Include="Tests\TaikoBeatmapConversionTest.cs" /> <Compile Include="Tests\TestCaseInputDrum.cs" /> <Compile Include="Tests\TestCasePerformancePoints.cs" /> <Compile Include="Tests\TestCaseTaikoPlayfield.cs" /> @@ -145,6 +146,10 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic-expected-conversion.json" /> + <EmbeddedResource Include="Resources\Testing\Beatmaps\basic.osu" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" /> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index 20de4e9680..711e220b88 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -12,8 +12,16 @@ namespace osu.Game.Beatmaps /// Converts a Beatmap for another mode. /// </summary> /// <typeparam name="T">The type of HitObject stored in the Beatmap.</typeparam> - public abstract class BeatmapConverter<T> where T : HitObject + public abstract class BeatmapConverter<T> : IBeatmapConverter + where T : HitObject { + private event Action<HitObject, IEnumerable<HitObject>> ObjectConverted; + event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted + { + add => ObjectConverted += value; + remove => ObjectConverted -= value; + } + /// <summary> /// Checks if a Beatmap can be converted using this Beatmap Converter. /// </summary> @@ -32,6 +40,8 @@ namespace osu.Game.Beatmaps return ConvertBeatmap(new Beatmap(original)); } + void IBeatmapConverter.Convert(Beatmap original) => Convert(original); + /// <summary> /// Performs the conversion of a Beatmap using this Beatmap Converter. /// </summary> @@ -63,8 +73,11 @@ namespace osu.Game.Beatmaps yield break; } + var converted = ConvertHitObject(original, beatmap).ToList(); + ObjectConverted?.Invoke(original, converted); + // Convert the hit object - foreach (var obj in ConvertHitObject(original, beatmap)) + foreach (var obj in converted) { if (obj == null) continue; diff --git a/osu.Game/Beatmaps/IBeatmapConverter.cs b/osu.Game/Beatmaps/IBeatmapConverter.cs new file mode 100644 index 0000000000..ebd900b97e --- /dev/null +++ b/osu.Game/Beatmaps/IBeatmapConverter.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Beatmaps +{ + public interface IBeatmapConverter + { + /// <summary> + /// Invoked when a <see cref="HitObject"/> has been converted. + /// The first argument contains the <see cref="HitObject"/> that was converted. + /// The second argument contains the <see cref="HitObject"/>s that were output from the conversion process. + /// </summary> + event Action<HitObject, IEnumerable<HitObject>> ObjectConverted; + + /// <summary> + /// Converts a Beatmap using this Beatmap Converter. + /// </summary> + /// <param name="original">The un-converted Beatmap.</param> + void Convert(Beatmap beatmap); + } +} diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs new file mode 100644 index 0000000000..596dbe84ba --- /dev/null +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -0,0 +1,141 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Newtonsoft.Json; +using NUnit.Framework; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Formats; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Tests.Beatmaps +{ + [TestFixture] + public abstract class BeatmapConversionTest<TConvertValue> + where TConvertValue : IEquatable<TConvertValue> + { + private const string resource_namespace = "Testing.Beatmaps"; + private const string expected_conversion_suffix = "-expected-conversion"; + + protected abstract string ResourceAssembly { get; } + + protected void Test(string name) + { + var ourResult = convert(name); + var expectedResult = read(name); + + Assert.Multiple(() => + { + int mappingCounter = 0; + while (true) + { + if (mappingCounter >= ourResult.Mappings.Count && mappingCounter >= expectedResult.Mappings.Count) + break; + if (mappingCounter >= ourResult.Mappings.Count) + Assert.Fail($"A conversion did not generate any hitobjects, but should have, for hitobject at time: {expectedResult.Mappings[mappingCounter].StartTime}\n"); + else if (mappingCounter >= expectedResult.Mappings.Count) + Assert.Fail($"A conversion generated hitobjects, but should not have, for hitobject at time: {ourResult.Mappings[mappingCounter].StartTime}\n"); + else + { + var counter = mappingCounter; + Assert.Multiple(() => + { + var ourMapping = ourResult.Mappings[counter]; + var expectedMapping = expectedResult.Mappings[counter]; + + int objectCounter = 0; + while (true) + { + if (objectCounter >= ourMapping.Objects.Count && objectCounter >= expectedMapping.Objects.Count) + break; + if (objectCounter >= ourMapping.Objects.Count) + Assert.Fail($"The conversion did not generate a hitobject, but should have, for hitobject at time: {expectedMapping.StartTime}:\n" + + $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n"); + else if (objectCounter >= expectedMapping.Objects.Count) + Assert.Fail($"The conversion generated a hitobject, but should not have, for hitobject at time: {ourMapping.StartTime}:\n" + + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); + else if (!EqualityComparer<TConvertValue>.Default.Equals(expectedMapping.Objects[objectCounter], ourMapping.Objects[objectCounter])) + { + Assert.Fail($"The conversion generated differing hitobjects for object at time: {expectedMapping.StartTime}\n" + + $"Expected: {JsonConvert.SerializeObject(expectedMapping.Objects[objectCounter])}\n" + + $"Received: {JsonConvert.SerializeObject(ourMapping.Objects[objectCounter])}\n"); + } + + objectCounter++; + } + }); + } + + mappingCounter++; + } + }); + } + + private ConvertResult convert(string name) + { + var beatmap = getBeatmap(name); + + var result = new ConvertResult(); + + var converter = CreateConverter(beatmap); + converter.ObjectConverted += (orig, converted) => + { + converted.ForEach(h => h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty)); + + var mapping = new ConvertMapping { StartTime = orig.StartTime }; + foreach (var obj in converted) + mapping.Objects.AddRange(CreateConvertValue(obj)); + result.Mappings.Add(mapping); + }; + + converter.Convert(beatmap); + + return result; + } + + private ConvertResult read(string name) + { + using (var resStream = openResource($"{resource_namespace}.{name}{expected_conversion_suffix}.json")) + using (var reader = new StreamReader(resStream)) + { + var contents = reader.ReadToEnd(); + return JsonConvert.DeserializeObject<ConvertResult>(contents); + } + } + + private Beatmap getBeatmap(string name) + { + var decoder = new LegacyBeatmapDecoder(); + using (var resStream = openResource($"{resource_namespace}.{name}.osu")) + using (var stream = new StreamReader(resStream)) + return decoder.DecodeBeatmap(stream); + } + + private Stream openResource(string name) + { + var localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)); + return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}"); + } + + protected abstract IEnumerable<TConvertValue> CreateConvertValue(HitObject hitObject); + protected abstract IBeatmapConverter CreateConverter(Beatmap beatmap); + + private class ConvertMapping + { + [JsonProperty] + public double StartTime; + [JsonProperty] + public List<TConvertValue> Objects = new List<TConvertValue>(); + } + + private class ConvertResult + { + [JsonProperty] + public List<ConvertMapping> Mappings = new List<ConvertMapping>(); + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d3c4dd9c92..ff365ad93e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -270,6 +270,7 @@ <Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" /> <Compile Include="Beatmaps\Formats\LegacyDecoder.cs" /> <Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" /> + <Compile Include="Beatmaps\IBeatmapConverter.cs" /> <Compile Include="Configuration\DatabasedSetting.cs" /> <Compile Include="Configuration\SettingsStore.cs" /> <Compile Include="Configuration\DatabasedConfigManager.cs" /> @@ -883,6 +884,7 @@ <Compile Include="Storyboards\StoryboardLayer.cs" /> <Compile Include="Storyboards\StoryboardSample.cs" /> <Compile Include="Storyboards\StoryboardSprite.cs" /> + <Compile Include="Tests\Beatmaps\BeatmapConversionTest.cs" /> <Compile Include="Tests\Beatmaps\TestWorkingBeatmap.cs" /> <Compile Include="Tests\CleanRunHeadlessGameHost.cs" /> <Compile Include="Tests\Platform\TestStorage.cs" />