mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:17:26 +08:00
Merge branch 'master' into fix-autopilot-touch-devices
This commit is contained in:
commit
6bffeb6a24
@ -27,10 +27,10 @@
|
||||
]
|
||||
},
|
||||
"ppy.localisationanalyser.tools": {
|
||||
"version": "2021.725.0",
|
||||
"version": "2021.1210.0",
|
||||
"commands": [
|
||||
"localisation"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1203.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1210.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -70,7 +70,9 @@ namespace osu.Desktop
|
||||
if (!string.IsNullOrEmpty(stableInstallPath) && checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
}
|
||||
catch { }
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
|
||||
@ -113,7 +115,7 @@ namespace osu.Desktop
|
||||
base.LoadComplete();
|
||||
|
||||
if (!noVersionOverlay)
|
||||
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, Add);
|
||||
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, ScreenContainer.Add);
|
||||
|
||||
LoadComponentAsync(new DiscordRichPresence(), Add);
|
||||
|
||||
|
@ -55,73 +55,75 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
|
||||
|
||||
bool firstDeltaSwitch = false;
|
||||
|
||||
for (int i = Previous.Count - 2; i > 0; i--)
|
||||
int rhythmStart = 0;
|
||||
|
||||
while (rhythmStart < Previous.Count - 2 && current.StartTime - Previous[rhythmStart].StartTime < history_time_max)
|
||||
rhythmStart++;
|
||||
|
||||
for (int i = rhythmStart; i > 0; i--)
|
||||
{
|
||||
OsuDifficultyHitObject currObj = (OsuDifficultyHitObject)Previous[i - 1];
|
||||
OsuDifficultyHitObject prevObj = (OsuDifficultyHitObject)Previous[i];
|
||||
OsuDifficultyHitObject lastObj = (OsuDifficultyHitObject)Previous[i + 1];
|
||||
|
||||
double currHistoricalDecay = Math.Max(0, (history_time_max - (current.StartTime - currObj.StartTime))) / history_time_max; // scales note 0 to 1 from history to now
|
||||
double currHistoricalDecay = (history_time_max - (current.StartTime - currObj.StartTime)) / history_time_max; // scales note 0 to 1 from history to now
|
||||
|
||||
if (currHistoricalDecay != 0)
|
||||
currHistoricalDecay = Math.Min((double)(Previous.Count - i) / Previous.Count, currHistoricalDecay); // either we're limited by time or limited by object count.
|
||||
|
||||
double currDelta = currObj.StrainTime;
|
||||
double prevDelta = prevObj.StrainTime;
|
||||
double lastDelta = lastObj.StrainTime;
|
||||
double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses.
|
||||
|
||||
double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - greatWindow * 0.6) / (greatWindow * 0.6));
|
||||
|
||||
windowPenalty = Math.Min(1, windowPenalty);
|
||||
|
||||
double effectiveRatio = windowPenalty * currRatio;
|
||||
|
||||
if (firstDeltaSwitch)
|
||||
{
|
||||
currHistoricalDecay = Math.Min((double)(Previous.Count - i) / Previous.Count, currHistoricalDecay); // either we're limited by time or limited by object count.
|
||||
|
||||
double currDelta = currObj.StrainTime;
|
||||
double prevDelta = prevObj.StrainTime;
|
||||
double lastDelta = lastObj.StrainTime;
|
||||
double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses.
|
||||
|
||||
double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - greatWindow * 0.6) / (greatWindow * 0.6));
|
||||
|
||||
windowPenalty = Math.Min(1, windowPenalty);
|
||||
|
||||
double effectiveRatio = windowPenalty * currRatio;
|
||||
|
||||
if (firstDeltaSwitch)
|
||||
if (!(prevDelta > 1.25 * currDelta || prevDelta * 1.25 < currDelta))
|
||||
{
|
||||
if (!(prevDelta > 1.25 * currDelta || prevDelta * 1.25 < currDelta))
|
||||
{
|
||||
if (islandSize < 7)
|
||||
islandSize++; // island is still progressing, count size.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Previous[i - 1].BaseObject is Slider) // bpm change is into slider, this is easy acc window
|
||||
effectiveRatio *= 0.125;
|
||||
|
||||
if (Previous[i].BaseObject is Slider) // bpm change was from a slider, this is easier typically than circle -> circle
|
||||
effectiveRatio *= 0.25;
|
||||
|
||||
if (previousIslandSize == islandSize) // repeated island size (ex: triplet -> triplet)
|
||||
effectiveRatio *= 0.25;
|
||||
|
||||
if (previousIslandSize % 2 == islandSize % 2) // repeated island polartiy (2 -> 4, 3 -> 5)
|
||||
effectiveRatio *= 0.50;
|
||||
|
||||
if (lastDelta > prevDelta + 10 && prevDelta > currDelta + 10) // previous increase happened a note ago, 1/1->1/2-1/4, dont want to buff this.
|
||||
effectiveRatio *= 0.125;
|
||||
|
||||
rhythmComplexitySum += Math.Sqrt(effectiveRatio * startRatio) * currHistoricalDecay * Math.Sqrt(4 + islandSize) / 2 * Math.Sqrt(4 + previousIslandSize) / 2;
|
||||
|
||||
startRatio = effectiveRatio;
|
||||
|
||||
previousIslandSize = islandSize; // log the last island size.
|
||||
|
||||
if (prevDelta * 1.25 < currDelta) // we're slowing down, stop counting
|
||||
firstDeltaSwitch = false; // if we're speeding up, this stays true and we keep counting island size.
|
||||
|
||||
islandSize = 1;
|
||||
}
|
||||
if (islandSize < 7)
|
||||
islandSize++; // island is still progressing, count size.
|
||||
}
|
||||
else if (prevDelta > 1.25 * currDelta) // we want to be speeding up.
|
||||
else
|
||||
{
|
||||
// Begin counting island until we change speed again.
|
||||
firstDeltaSwitch = true;
|
||||
if (Previous[i - 1].BaseObject is Slider) // bpm change is into slider, this is easy acc window
|
||||
effectiveRatio *= 0.125;
|
||||
|
||||
if (Previous[i].BaseObject is Slider) // bpm change was from a slider, this is easier typically than circle -> circle
|
||||
effectiveRatio *= 0.25;
|
||||
|
||||
if (previousIslandSize == islandSize) // repeated island size (ex: triplet -> triplet)
|
||||
effectiveRatio *= 0.25;
|
||||
|
||||
if (previousIslandSize % 2 == islandSize % 2) // repeated island polartiy (2 -> 4, 3 -> 5)
|
||||
effectiveRatio *= 0.50;
|
||||
|
||||
if (lastDelta > prevDelta + 10 && prevDelta > currDelta + 10) // previous increase happened a note ago, 1/1->1/2-1/4, dont want to buff this.
|
||||
effectiveRatio *= 0.125;
|
||||
|
||||
rhythmComplexitySum += Math.Sqrt(effectiveRatio * startRatio) * currHistoricalDecay * Math.Sqrt(4 + islandSize) / 2 * Math.Sqrt(4 + previousIslandSize) / 2;
|
||||
|
||||
startRatio = effectiveRatio;
|
||||
|
||||
previousIslandSize = islandSize; // log the last island size.
|
||||
|
||||
if (prevDelta * 1.25 < currDelta) // we're slowing down, stop counting
|
||||
firstDeltaSwitch = false; // if we're speeding up, this stays true and we keep counting island size.
|
||||
|
||||
islandSize = 1;
|
||||
}
|
||||
}
|
||||
else if (prevDelta > 1.25 * currDelta) // we want to be speeding up.
|
||||
{
|
||||
// Begin counting island until we change speed again.
|
||||
firstDeltaSwitch = true;
|
||||
startRatio = effectiveRatio;
|
||||
islandSize = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Sqrt(4 + rhythmComplexitySum * rhythm_multiplier) / 2; //produces multiplier that can be applied to strain. range [1, infinity) (not really though)
|
||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
public void TestCultureInvariance()
|
||||
{
|
||||
var ruleset = new OsuRuleset().RulesetInfo;
|
||||
var scoreInfo = new TestScoreInfo(ruleset);
|
||||
var scoreInfo = TestResources.CreateTestScoreInfo(ruleset);
|
||||
var beatmap = new TestBeatmap(ruleset);
|
||||
var score = new Score
|
||||
{
|
||||
|
@ -1022,7 +1022,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
{
|
||||
return ImportScoreTest.LoadScoreIntoOsu(osu, new ScoreInfo
|
||||
{
|
||||
OnlineScoreID = 2,
|
||||
OnlineID = 2,
|
||||
BeatmapInfo = beatmapInfo,
|
||||
BeatmapInfoID = beatmapInfo.ID
|
||||
}, new ImportScoreTest.TestArchiveReader());
|
||||
|
@ -809,7 +809,7 @@ namespace osu.Game.Tests.Database
|
||||
// TODO: reimplement when we have score support in realm.
|
||||
// return ImportScoreTest.LoadScoreIntoOsu(osu, new ScoreInfo
|
||||
// {
|
||||
// OnlineScoreID = 2,
|
||||
// OnlineID = 2,
|
||||
// Beatmap = beatmap,
|
||||
// BeatmapInfoID = beatmap.ID
|
||||
// }, new ImportScoreTest.TestArchiveReader());
|
||||
|
@ -52,6 +52,45 @@ namespace osu.Game.Tests.Database
|
||||
Assert.That(queryCount(GlobalAction.Select), Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDefaultsPopulationRemovesExcess()
|
||||
{
|
||||
Assert.That(queryCount(), Is.EqualTo(0));
|
||||
|
||||
KeyBindingContainer testContainer = new TestKeyBindingContainer();
|
||||
|
||||
// Add some excess bindings for an action which only supports 1.
|
||||
using (var realm = realmContextFactory.CreateContext())
|
||||
using (var transaction = realm.BeginWrite())
|
||||
{
|
||||
realm.Add(new RealmKeyBinding
|
||||
{
|
||||
Action = GlobalAction.Back,
|
||||
KeyCombination = new KeyCombination(InputKey.A)
|
||||
});
|
||||
|
||||
realm.Add(new RealmKeyBinding
|
||||
{
|
||||
Action = GlobalAction.Back,
|
||||
KeyCombination = new KeyCombination(InputKey.S)
|
||||
});
|
||||
|
||||
realm.Add(new RealmKeyBinding
|
||||
{
|
||||
Action = GlobalAction.Back,
|
||||
KeyCombination = new KeyCombination(InputKey.D)
|
||||
});
|
||||
|
||||
transaction.Commit();
|
||||
}
|
||||
|
||||
Assert.That(queryCount(GlobalAction.Back), Is.EqualTo(3));
|
||||
|
||||
keyBindingStore.Register(testContainer, Enumerable.Empty<RulesetInfo>());
|
||||
|
||||
Assert.That(queryCount(GlobalAction.Back), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
private int queryCount(GlobalAction? match = null)
|
||||
{
|
||||
using (var realm = realmContextFactory.CreateContext())
|
||||
|
@ -45,8 +45,6 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
||||
AddRepeatStep("add some users", () => Client.AddUser(new APIUser { Id = id++ }), 5);
|
||||
checkPlayingUserCount(0);
|
||||
|
||||
AddAssert("playlist item is available", () => Client.CurrentMatchPlayingItem.Value != null);
|
||||
|
||||
changeState(3, MultiplayerUserState.WaitingForLoad);
|
||||
checkPlayingUserCount(3);
|
||||
|
||||
@ -64,8 +62,6 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
|
||||
|
||||
AddStep("leave room", () => Client.LeaveRoom());
|
||||
checkPlayingUserCount(0);
|
||||
|
||||
AddAssert("playlist item is null", () => Client.CurrentMatchPlayingItem.Value == null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
90
osu.Game.Tests/Online/Chat/MessageNotifierTest.cs
Normal file
90
osu.Game.Tests/Online/Chat/MessageNotifierTest.cs
Normal file
@ -0,0 +1,90 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Online.Chat;
|
||||
|
||||
namespace osu.Game.Tests.Online.Chat
|
||||
{
|
||||
[TestFixture]
|
||||
public class MessageNotifierTest
|
||||
{
|
||||
[Test]
|
||||
public void TestContainsUsernameMidlinePositive()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("This is a test message", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameStartOfLinePositive()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("Test message", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameEndOfLinePositive()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("This is a test", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameMidlineNegative()
|
||||
{
|
||||
Assert.IsFalse(MessageNotifier.CheckContainsUsername("This is a testmessage for notifications", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameStartOfLineNegative()
|
||||
{
|
||||
Assert.IsFalse(MessageNotifier.CheckContainsUsername("Testmessage", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameEndOfLineNegative()
|
||||
{
|
||||
Assert.IsFalse(MessageNotifier.CheckContainsUsername("This is a notificationtest", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameBetweenInterpunction()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("Hello 'test'-message", "Test"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameUnicode()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("Test \u0460\u0460 message", "\u0460\u0460"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameUnicodeNegative()
|
||||
{
|
||||
Assert.IsFalse(MessageNotifier.CheckContainsUsername("Test ha\u0460\u0460o message", "\u0460\u0460"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameSpecialCharactersPositive()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("Test [#^-^#] message", "[#^-^#]"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameSpecialCharactersNegative()
|
||||
{
|
||||
Assert.IsFalse(MessageNotifier.CheckContainsUsername("Test pad[#^-^#]oru message", "[#^-^#]"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameAtSign()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("@username hi", "username"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestContainsUsernameColon()
|
||||
{
|
||||
Assert.IsTrue(MessageNotifier.CheckContainsUsername("username: hi", "username"));
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ using osu.Game.Online.Solo;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Scoring;
|
||||
@ -94,7 +93,7 @@ namespace osu.Game.Tests.Online
|
||||
[Test]
|
||||
public void TestDeserialiseSubmittableScoreWithEmptyMods()
|
||||
{
|
||||
var score = new SubmittableScore(new ScoreInfo { Ruleset = new OsuRuleset().RulesetInfo });
|
||||
var score = new SubmittableScore(new ScoreInfo());
|
||||
|
||||
var deserialised = JsonConvert.DeserializeObject<SubmittableScore>(JsonConvert.SerializeObject(score));
|
||||
|
||||
@ -106,7 +105,6 @@ namespace osu.Game.Tests.Online
|
||||
{
|
||||
var score = new SubmittableScore(new ScoreInfo
|
||||
{
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
Mods = new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 2 } } }
|
||||
});
|
||||
|
||||
|
@ -114,18 +114,23 @@ namespace osu.Game.Tests.Online
|
||||
public void TestTrackerRespectsChecksum()
|
||||
{
|
||||
AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true));
|
||||
AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).Wait());
|
||||
addAvailabilityCheckStep("initially locally available", BeatmapAvailability.LocallyAvailable);
|
||||
|
||||
AddStep("import altered beatmap", () =>
|
||||
{
|
||||
beatmaps.Import(TestResources.GetTestBeatmapForImport(true)).Wait();
|
||||
});
|
||||
addAvailabilityCheckStep("state still not downloaded", BeatmapAvailability.NotDownloaded);
|
||||
addAvailabilityCheckStep("state not downloaded", BeatmapAvailability.NotDownloaded);
|
||||
|
||||
AddStep("recreate tracker", () => Child = availabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||
{
|
||||
SelectedItem = { BindTarget = selectedItem }
|
||||
});
|
||||
addAvailabilityCheckStep("state not downloaded as well", BeatmapAvailability.NotDownloaded);
|
||||
|
||||
AddStep("reimport original beatmap", () => beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait());
|
||||
addAvailabilityCheckStep("locally available after re-import", BeatmapAvailability.LocallyAvailable);
|
||||
}
|
||||
|
||||
private void addAvailabilityCheckStep(string description, Func<BeatmapAvailability> expected)
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
@ -12,8 +13,12 @@ using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Tests.Resources
|
||||
{
|
||||
@ -137,5 +142,63 @@ namespace osu.Game.Tests.Resources
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a test score model.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The ruleset for which the score was set against.</param>
|
||||
/// <returns></returns>
|
||||
public static ScoreInfo CreateTestScoreInfo(RulesetInfo ruleset = null) =>
|
||||
CreateTestScoreInfo(CreateTestBeatmapSetInfo(1, new[] { ruleset ?? new OsuRuleset().RulesetInfo }).Beatmaps.First());
|
||||
|
||||
/// <summary>
|
||||
/// Create a test score model.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap for which the score was set against.</param>
|
||||
/// <returns></returns>
|
||||
public static ScoreInfo CreateTestScoreInfo(BeatmapInfo beatmap) => new ScoreInfo
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||
},
|
||||
BeatmapInfo = beatmap,
|
||||
Ruleset = beatmap.Ruleset,
|
||||
RulesetID = beatmap.Ruleset.ID ?? 0,
|
||||
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() },
|
||||
TotalScore = 2845370,
|
||||
Accuracy = 0.95,
|
||||
MaxCombo = 999,
|
||||
Position = 1,
|
||||
Rank = ScoreRank.S,
|
||||
Date = DateTimeOffset.Now,
|
||||
Statistics = new Dictionary<HitResult, int>
|
||||
{
|
||||
[HitResult.Miss] = 1,
|
||||
[HitResult.Meh] = 50,
|
||||
[HitResult.Ok] = 100,
|
||||
[HitResult.Good] = 200,
|
||||
[HitResult.Great] = 300,
|
||||
[HitResult.Perfect] = 320,
|
||||
[HitResult.SmallTickHit] = 50,
|
||||
[HitResult.SmallTickMiss] = 25,
|
||||
[HitResult.LargeTickHit] = 100,
|
||||
[HitResult.LargeTickMiss] = 50,
|
||||
[HitResult.SmallBonus] = 10,
|
||||
[HitResult.SmallBonus] = 50
|
||||
},
|
||||
};
|
||||
|
||||
private class TestModHardRock : ModHardRock
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
||||
private class TestModDoubleTime : ModDoubleTime
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Tests.Scores.IO
|
||||
Combo = 250,
|
||||
User = new APIUser { Username = "Test user" },
|
||||
Date = DateTimeOffset.Now,
|
||||
OnlineScoreID = 12345,
|
||||
OnlineID = 12345,
|
||||
};
|
||||
|
||||
var imported = await LoadScoreIntoOsu(osu, toImport);
|
||||
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Scores.IO
|
||||
Assert.AreEqual(toImport.Combo, imported.Combo);
|
||||
Assert.AreEqual(toImport.User.Username, imported.User.Username);
|
||||
Assert.AreEqual(toImport.Date, imported.Date);
|
||||
Assert.AreEqual(toImport.OnlineScoreID, imported.OnlineScoreID);
|
||||
Assert.AreEqual(toImport.OnlineID, imported.OnlineID);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -163,12 +163,12 @@ namespace osu.Game.Tests.Scores.IO
|
||||
{
|
||||
var osu = LoadOsuIntoHost(host, true);
|
||||
|
||||
await LoadScoreIntoOsu(osu, new ScoreInfo { OnlineScoreID = 2 }, new TestArchiveReader());
|
||||
await LoadScoreIntoOsu(osu, new ScoreInfo { OnlineID = 2 }, new TestArchiveReader());
|
||||
|
||||
var scoreManager = osu.Dependencies.Get<ScoreManager>();
|
||||
|
||||
// Note: A new score reference is used here since the import process mutates the original object to set an ID
|
||||
Assert.That(scoreManager.IsAvailableLocally(new ScoreInfo { OnlineScoreID = 2 }));
|
||||
Assert.That(scoreManager.IsAvailableLocally(new ScoreInfo { OnlineID = 2 }));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -44,24 +44,6 @@ namespace osu.Game.Tests.Scores.IO
|
||||
Assert.That(score1, Is.EqualTo(score2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNonMatchingByHash()
|
||||
{
|
||||
ScoreInfo score1 = new ScoreInfo { Hash = "a" };
|
||||
ScoreInfo score2 = new ScoreInfo { Hash = "b" };
|
||||
|
||||
Assert.That(score1, Is.Not.EqualTo(score2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMatchingByHash()
|
||||
{
|
||||
ScoreInfo score1 = new ScoreInfo { Hash = "a" };
|
||||
ScoreInfo score2 = new ScoreInfo { Hash = "a" };
|
||||
|
||||
Assert.That(score1, Is.EqualTo(score2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNonMatchingByNull()
|
||||
{
|
||||
|
@ -5,8 +5,11 @@ using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
@ -15,6 +18,7 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
@ -22,8 +26,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public class TestSceneBackgroundScreenDefault : OsuTestScene
|
||||
{
|
||||
private BackgroundScreenStack stack;
|
||||
private BackgroundScreenDefault screen;
|
||||
|
||||
private TestBackgroundScreenDefault screen;
|
||||
private Graphics.Backgrounds.Background getCurrentBackground() => screen.ChildrenOfType<Graphics.Backgrounds.Background>().FirstOrDefault();
|
||||
|
||||
[Resolved]
|
||||
@ -36,10 +39,95 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("create background stack", () => Child = stack = new BackgroundScreenStack());
|
||||
AddStep("push default screen", () => stack.Push(screen = new BackgroundScreenDefault(false)));
|
||||
AddStep("push default screen", () => stack.Push(screen = new TestBackgroundScreenDefault()));
|
||||
AddUntilStep("wait for screen to load", () => screen.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapBackgroundTracksBeatmap()
|
||||
{
|
||||
setSupporter(true);
|
||||
setSourceMode(BackgroundSource.Beatmap);
|
||||
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
AddAssert("background changed", () => screen.CheckLastLoadChange() == true);
|
||||
|
||||
Graphics.Backgrounds.Background last = null;
|
||||
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => getCurrentBackground()?.GetType() == typeof(BeatmapBackground));
|
||||
AddStep("store background", () => last = getCurrentBackground());
|
||||
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
|
||||
AddUntilStep("wait for beatmap background to change", () => screen.CheckLastLoadChange() == true);
|
||||
|
||||
AddUntilStep("background is new beatmap background", () => last != getCurrentBackground());
|
||||
AddStep("store background", () => last = getCurrentBackground());
|
||||
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
|
||||
AddUntilStep("wait for beatmap background to change", () => screen.CheckLastLoadChange() == true);
|
||||
AddUntilStep("background is new beatmap background", () => last != getCurrentBackground());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapBackgroundTracksBeatmapWhenSuspended()
|
||||
{
|
||||
setSupporter(true);
|
||||
setSourceMode(BackgroundSource.Beatmap);
|
||||
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
AddAssert("background changed", () => screen.CheckLastLoadChange() == true);
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => getCurrentBackground()?.GetType() == typeof(BeatmapBackground));
|
||||
|
||||
BackgroundScreenBeatmap nestedScreen = null;
|
||||
|
||||
// of note, this needs to be a type that doesn't match BackgroundScreenDefault else it is silently not pushed by the background stack.
|
||||
AddStep("push new background to stack", () => stack.Push(nestedScreen = new BackgroundScreenBeatmap(Beatmap.Value)));
|
||||
AddUntilStep("wait for screen to load", () => nestedScreen.IsLoaded && nestedScreen.IsCurrentScreen());
|
||||
|
||||
AddAssert("top level background hasn't changed yet", () => screen.CheckLastLoadChange() == null);
|
||||
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
|
||||
AddAssert("top level background hasn't changed yet", () => screen.CheckLastLoadChange() == null);
|
||||
|
||||
AddStep("pop screen back to top level", () => screen.MakeCurrent());
|
||||
|
||||
AddAssert("top level background changed", () => screen.CheckLastLoadChange() == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBeatmapBackgroundIgnoresNoChangeWhenSuspended()
|
||||
{
|
||||
BackgroundScreenBeatmap nestedScreen = null;
|
||||
WorkingBeatmap originalWorking = null;
|
||||
|
||||
setSupporter(true);
|
||||
setSourceMode(BackgroundSource.Beatmap);
|
||||
|
||||
AddStep("change beatmap", () => originalWorking = Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
AddAssert("background changed", () => screen.CheckLastLoadChange() == true);
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => getCurrentBackground()?.GetType() == typeof(BeatmapBackground));
|
||||
|
||||
// of note, this needs to be a type that doesn't match BackgroundScreenDefault else it is silently not pushed by the background stack.
|
||||
AddStep("push new background to stack", () => stack.Push(nestedScreen = new BackgroundScreenBeatmap(Beatmap.Value)));
|
||||
AddUntilStep("wait for screen to load", () => nestedScreen.IsLoaded && nestedScreen.IsCurrentScreen());
|
||||
|
||||
// we're testing a case where scheduling may be used to avoid issues, so ensure the scheduler is no longer running.
|
||||
AddUntilStep("wait for top level not alive", () => !screen.IsAlive);
|
||||
|
||||
AddStep("change beatmap", () => Beatmap.Value = createTestWorkingBeatmapWithUniqueBackground());
|
||||
AddStep("change beatmap back", () => Beatmap.Value = originalWorking);
|
||||
|
||||
AddAssert("top level background hasn't changed yet", () => screen.CheckLastLoadChange() == null);
|
||||
|
||||
AddStep("pop screen back to top level", () => screen.MakeCurrent());
|
||||
|
||||
AddStep("top level screen is current", () => screen.IsCurrentScreen());
|
||||
AddAssert("top level background reused existing", () => screen.CheckLastLoadChange() == false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBackgroundTypeSwitch()
|
||||
{
|
||||
@ -78,36 +166,24 @@ namespace osu.Game.Tests.Visual.Background
|
||||
[TestCase(BackgroundSource.Skin, typeof(SkinBackground))]
|
||||
public void TestBackgroundDoesntReloadOnNoChange(BackgroundSource source, Type backgroundType)
|
||||
{
|
||||
Graphics.Backgrounds.Background last = null;
|
||||
|
||||
setSourceMode(source);
|
||||
setSupporter(true);
|
||||
if (source == BackgroundSource.Skin)
|
||||
setCustomSkin();
|
||||
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == backgroundType);
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (getCurrentBackground())?.GetType() == backgroundType);
|
||||
AddAssert("next doesn't load new background", () => screen.Next() == false);
|
||||
|
||||
// doesn't really need to be checked but might as well.
|
||||
AddWaitStep("wait a bit", 5);
|
||||
AddUntilStep("ensure same background instance", () => last == getCurrentBackground());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBackgroundCyclingOnDefaultSkin([Values] bool supporter)
|
||||
{
|
||||
Graphics.Backgrounds.Background last = null;
|
||||
|
||||
setSourceMode(BackgroundSource.Skin);
|
||||
setSupporter(supporter);
|
||||
setDefaultSkin();
|
||||
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == typeof(Graphics.Backgrounds.Background));
|
||||
AddUntilStep("wait for beatmap background to be loaded", () => (getCurrentBackground())?.GetType() == typeof(Graphics.Backgrounds.Background));
|
||||
AddAssert("next cycles background", () => screen.Next());
|
||||
|
||||
// doesn't really need to be checked but might as well.
|
||||
AddWaitStep("wait a bit", 5);
|
||||
AddUntilStep("ensure different background instance", () => last != getCurrentBackground());
|
||||
}
|
||||
|
||||
private void setSourceMode(BackgroundSource source) =>
|
||||
@ -120,6 +196,42 @@ namespace osu.Game.Tests.Visual.Background
|
||||
Id = API.LocalUser.Value.Id + 1,
|
||||
});
|
||||
|
||||
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(Audio);
|
||||
|
||||
private class TestBackgroundScreenDefault : BackgroundScreenDefault
|
||||
{
|
||||
private bool? lastLoadTriggerCausedChange;
|
||||
|
||||
public TestBackgroundScreenDefault()
|
||||
: base(false)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Next()
|
||||
{
|
||||
bool didChange = base.Next();
|
||||
lastLoadTriggerCausedChange = didChange;
|
||||
return didChange;
|
||||
}
|
||||
|
||||
public bool? CheckLastLoadChange()
|
||||
{
|
||||
bool? lastChange = lastLoadTriggerCausedChange;
|
||||
lastLoadTriggerCausedChange = null;
|
||||
return lastChange;
|
||||
}
|
||||
}
|
||||
|
||||
private class UniqueBackgroundTestWorkingBeatmap : TestWorkingBeatmap
|
||||
{
|
||||
public UniqueBackgroundTestWorkingBeatmap(AudioManager audioManager)
|
||||
: base(new Beatmap(), null, audioManager)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Texture GetBackground() => new Texture(1, 1);
|
||||
}
|
||||
|
||||
private void setCustomSkin()
|
||||
{
|
||||
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.
|
||||
|
@ -18,7 +18,6 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Scoring;
|
||||
@ -28,7 +27,6 @@ using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Select;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -229,12 +227,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
FadeAccessibleResults results = null;
|
||||
|
||||
AddStep("Transition to Results", () => player.Push(results = new FadeAccessibleResults(new ScoreInfo
|
||||
{
|
||||
User = new APIUser { Username = "osu!" },
|
||||
BeatmapInfo = new TestBeatmap(Ruleset.Value).BeatmapInfo,
|
||||
Ruleset = Ruleset.Value,
|
||||
})));
|
||||
AddStep("Transition to Results", () => player.Push(results = new FadeAccessibleResults(TestResources.CreateTestScoreInfo())));
|
||||
|
||||
AddUntilStep("Wait for results is current", () => results.IsCurrentScreen());
|
||||
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Edit;
|
||||
@ -44,6 +45,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
protected override void LoadEditor()
|
||||
{
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(b => b.RulesetID == 0));
|
||||
SelectedMods.Value = new[] { new ModCinema() };
|
||||
base.LoadEditor();
|
||||
}
|
||||
|
||||
@ -67,6 +69,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
var background = this.ChildrenOfType<BackgroundScreenBeatmap>().Single();
|
||||
return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0;
|
||||
});
|
||||
AddAssert("no mods selected", () => SelectedMods.Value.Count == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -26,6 +26,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("total number of results == 1", () =>
|
||||
{
|
||||
var score = new ScoreInfo();
|
||||
|
||||
((FailPlayer)Player).ScoreProcessor.PopulateScore(score);
|
||||
|
||||
return score.Statistics.Values.Sum() == 1;
|
||||
|
@ -85,11 +85,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
loopGroup.Scale.Add(Easing.None, -20000, -18000, 0, 1);
|
||||
|
||||
var target = addEventToLoop ? loopGroup : sprite.TimelineGroup;
|
||||
target.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1);
|
||||
double targetTime = addEventToLoop ? 20000 : 0;
|
||||
target.Alpha.Add(Easing.None, targetTime + firstStoryboardEvent, targetTime + firstStoryboardEvent + 500, 0, 1);
|
||||
|
||||
// these should be ignored due to being in the future.
|
||||
sprite.TimelineGroup.Alpha.Add(Easing.None, 18000, 20000, 0, 1);
|
||||
loopGroup.Alpha.Add(Easing.None, 18000, 20000, 0, 1);
|
||||
loopGroup.Alpha.Add(Easing.None, 38000, 40000, 0, 1);
|
||||
|
||||
storyboard.GetLayer("Background").Add(sprite);
|
||||
|
||||
|
@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
private ScoreInfo getScoreInfo(bool replayAvailable)
|
||||
{
|
||||
return new APIScoreInfo
|
||||
return new APIScore
|
||||
{
|
||||
OnlineID = 2553163309,
|
||||
RulesetID = 0,
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestFirstItemSelectedByDefault()
|
||||
{
|
||||
AddAssert("first item selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[0].ID);
|
||||
AddAssert("first item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -27,13 +27,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
addItem(() => OtherBeatmap);
|
||||
AddAssert("playlist has 2 items", () => Client.APIRoom?.Playlist.Count == 2);
|
||||
AddAssert("last playlist item is different", () => Client.APIRoom?.Playlist[1].Beatmap.Value.OnlineID == OtherBeatmap.OnlineID);
|
||||
|
||||
addItem(() => InitialBeatmap);
|
||||
AddAssert("playlist has 3 items", () => Client.APIRoom?.Playlist.Count == 3);
|
||||
AddAssert("last playlist item is different", () => Client.APIRoom?.Playlist[2].Beatmap.Value.OnlineID == InitialBeatmap.OnlineID);
|
||||
|
||||
AddAssert("first item still selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[0].ID);
|
||||
AddAssert("first item still selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -43,7 +41,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddAssert("playlist has only one item", () => Client.APIRoom?.Playlist.Count == 1);
|
||||
AddAssert("playlist item is expired", () => Client.APIRoom?.Playlist[0].Expired == true);
|
||||
AddAssert("last item selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[0].ID);
|
||||
AddAssert("last item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -55,12 +53,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
RunGameplay();
|
||||
|
||||
AddAssert("first item expired", () => Client.APIRoom?.Playlist[0].Expired == true);
|
||||
AddAssert("next item selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[1].ID);
|
||||
AddAssert("next item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[1].ID);
|
||||
|
||||
RunGameplay();
|
||||
|
||||
AddAssert("second item expired", () => Client.APIRoom?.Playlist[1].Expired == true);
|
||||
AddAssert("next item selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[2].ID);
|
||||
AddAssert("next item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[2].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -74,15 +72,15 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("change queue mode", () => Client.ChangeSettings(queueMode: QueueMode.HostOnly));
|
||||
AddAssert("playlist has 3 items", () => Client.APIRoom?.Playlist.Count == 3);
|
||||
AddAssert("playlist item is the other beatmap", () => Client.CurrentMatchPlayingItem.Value?.BeatmapID == OtherBeatmap.OnlineID);
|
||||
AddAssert("playlist item is not expired", () => Client.APIRoom?.Playlist[1].Expired == false);
|
||||
AddAssert("item 2 is not expired", () => Client.APIRoom?.Playlist[1].Expired == false);
|
||||
AddAssert("current item is the other beatmap", () => Client.Room?.Settings.PlaylistItemId == 2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCorrectItemSelectedAfterNewItemAdded()
|
||||
{
|
||||
addItem(() => OtherBeatmap);
|
||||
AddAssert("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
|
||||
AddUntilStep("selected beatmap is initial beatmap", () => Beatmap.Value.BeatmapInfo.OnlineID == InitialBeatmap.OnlineID);
|
||||
}
|
||||
|
||||
private void addItem(Func<BeatmapInfo> beatmap)
|
||||
|
@ -9,6 +9,7 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Screens.OnlinePlay;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
@ -20,7 +21,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestFirstItemSelectedByDefault()
|
||||
{
|
||||
AddAssert("first item selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[0].ID);
|
||||
AddAssert("first item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -28,7 +29,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
selectNewItem(() => InitialBeatmap);
|
||||
|
||||
AddAssert("playlist item still selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[0].ID);
|
||||
AddAssert("playlist item still selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -36,7 +37,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
selectNewItem(() => OtherBeatmap);
|
||||
|
||||
AddAssert("playlist item still selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[0].ID);
|
||||
AddAssert("playlist item still selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[0].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -47,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddAssert("playlist contains two items", () => Client.APIRoom?.Playlist.Count == 2);
|
||||
AddAssert("first playlist item expired", () => Client.APIRoom?.Playlist[0].Expired == true);
|
||||
AddAssert("second playlist item not expired", () => Client.APIRoom?.Playlist[1].Expired == false);
|
||||
AddAssert("second playlist item selected", () => Client.CurrentMatchPlayingItem.Value?.ID == Client.APIRoom?.Playlist[1].ID);
|
||||
AddAssert("second playlist item selected", () => Client.Room?.Settings.PlaylistItemId == Client.APIRoom?.Playlist[1].ID);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -85,6 +86,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
private void selectNewItem(Func<BeatmapInfo> beatmap)
|
||||
{
|
||||
AddUntilStep("wait for playlist panels to load", () =>
|
||||
{
|
||||
var queueList = this.ChildrenOfType<MultiplayerQueueList>().Single();
|
||||
return queueList.ChildrenOfType<DrawableRoomPlaylistItem>().Count() == queueList.Items.Count;
|
||||
});
|
||||
|
||||
AddStep("click edit button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(this.ChildrenOfType<DrawableRoomPlaylistItem.PlaylistEditButton>().First());
|
||||
@ -97,7 +104,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("select other beatmap", () => ((Screens.Select.SongSelect)CurrentSubScreen).FinaliseSelection(otherBeatmap = beatmap()));
|
||||
|
||||
AddUntilStep("wait for return to match", () => CurrentSubScreen is MultiplayerMatchSubScreen);
|
||||
AddUntilStep("selected item is new beatmap", () => Client.CurrentMatchPlayingItem.Value?.Beatmap.Value?.OnlineID == otherBeatmap.OnlineID);
|
||||
AddUntilStep("selected item is new beatmap", () => (CurrentSubScreen as MultiplayerMatchSubScreen)?.SelectedItem.Value?.BeatmapID == otherBeatmap.OnlineID);
|
||||
}
|
||||
|
||||
private void addItem(Func<BeatmapInfo> beatmap)
|
||||
|
@ -391,9 +391,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("set user ready", () => client.ChangeState(MultiplayerUserState.Ready));
|
||||
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
|
||||
pressReadyButton();
|
||||
|
||||
AddStep("delete beatmap", () => beatmaps.Delete(importedSet));
|
||||
AddUntilStep("user state is idle", () => client.LocalUser?.State == MultiplayerUserState.Idle);
|
||||
}
|
||||
|
||||
@ -413,10 +413,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
});
|
||||
|
||||
pressReadyButton();
|
||||
|
||||
AddStep("Enter song select", () =>
|
||||
{
|
||||
var currentSubScreen = ((Screens.OnlinePlay.Multiplayer.Multiplayer)multiplayerScreenStack.CurrentScreen).CurrentSubScreen;
|
||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.CurrentMatchPlayingItem.Value);
|
||||
((MultiplayerMatchSubScreen)currentSubScreen).OpenSongSelection(client.Room?.Settings.PlaylistItemId);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for song select", () => this.ChildrenOfType<MultiplayerMatchSongSelect>().FirstOrDefault()?.BeatmapSetsLoaded == true);
|
||||
@ -592,19 +594,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
});
|
||||
|
||||
AddUntilStep("wait for ready button to be enabled", () => readyButton.ChildrenOfType<OsuButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("click ready button", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(readyButton);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for player to be ready", () => client.Room?.Users[0].State == MultiplayerUserState.Ready);
|
||||
AddUntilStep("wait for ready button to be enabled", () => readyButton.ChildrenOfType<OsuButton>().Single().Enabled.Value);
|
||||
|
||||
AddStep("click start button", () => InputManager.Click(MouseButton.Left));
|
||||
|
||||
pressReadyButton();
|
||||
pressReadyButton();
|
||||
AddUntilStep("wait for player", () => multiplayerScreenStack.CurrentScreen is Player);
|
||||
|
||||
// Gameplay runs in real-time, so we need to incrementally check if gameplay has finished in order to not time out.
|
||||
@ -665,7 +656,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
});
|
||||
}
|
||||
|
||||
private MultiplayerReadyButton readyButton => this.ChildrenOfType<MultiplayerReadyButton>().Single();
|
||||
private ReadyButton readyButton => this.ChildrenOfType<ReadyButton>().Single();
|
||||
|
||||
private void pressReadyButton()
|
||||
{
|
||||
AddUntilStep("wait for ready button to be enabled", () => readyButton.Enabled.Value);
|
||||
|
||||
MultiplayerUserState lastState = MultiplayerUserState.Idle;
|
||||
|
||||
AddStep("click ready button", () =>
|
||||
{
|
||||
lastState = client.LocalUser?.State ?? MultiplayerUserState.Idle;
|
||||
|
||||
InputManager.MoveMouseTo(readyButton);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddUntilStep("wait for state change", () => client.LocalUser?.State != lastState);
|
||||
}
|
||||
|
||||
private void createRoom(Func<Room> room)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
|
||||
@ -27,7 +28,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("initialise gameplay", () =>
|
||||
{
|
||||
Stack.Push(player = new MultiplayerPlayer(Client.APIRoom, Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray()));
|
||||
Stack.Push(player = new MultiplayerPlayer(Client.APIRoom, new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = Beatmap.Value.BeatmapInfo },
|
||||
Ruleset = { Value = Beatmap.Value.BeatmapInfo.Ruleset }
|
||||
}, Client.Room?.Users.ToArray()));
|
||||
});
|
||||
|
||||
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen() && player.IsLoaded);
|
||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
@ -27,11 +28,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
public class TestSceneMultiplayerQueueList : MultiplayerTestScene
|
||||
{
|
||||
private MultiplayerQueueList playlist;
|
||||
private readonly Bindable<PlaylistItem> selectedItem = new Bindable<PlaylistItem>();
|
||||
|
||||
[Cached(typeof(UserLookupCache))]
|
||||
private readonly TestUserLookupCache userLookupCache = new TestUserLookupCache();
|
||||
|
||||
private MultiplayerQueueList playlist;
|
||||
private BeatmapManager beatmaps;
|
||||
private RulesetStore rulesets;
|
||||
private BeatmapSetInfo importedSet;
|
||||
@ -50,12 +52,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
AddStep("create playlist", () =>
|
||||
{
|
||||
selectedItem.Value = null;
|
||||
|
||||
Child = playlist = new MultiplayerQueueList
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(500, 300),
|
||||
SelectedItem = { BindTarget = Client.CurrentMatchPlayingItem },
|
||||
SelectedItem = { BindTarget = selectedItem },
|
||||
Items = { BindTarget = Client.APIRoom!.Playlist }
|
||||
};
|
||||
});
|
||||
@ -107,22 +111,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddStep("set all players queue mode", () => Client.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }));
|
||||
AddUntilStep("wait for queue mode change", () => Client.APIRoom?.QueueMode.Value == QueueMode.AllPlayers);
|
||||
|
||||
assertDeleteButtonVisibility(0, false);
|
||||
|
||||
addPlaylistItem(() => API.LocalUser.Value.OnlineID);
|
||||
|
||||
AddStep("select item 0", () => selectedItem.Value = playlist.ChildrenOfType<RearrangeableListItem<PlaylistItem>>().ElementAt(0).Model);
|
||||
assertDeleteButtonVisibility(0, false);
|
||||
assertDeleteButtonVisibility(1, true);
|
||||
|
||||
// Run through gameplay.
|
||||
AddStep("set state to ready", () => Client.ChangeUserState(API.LocalUser.Value.Id, MultiplayerUserState.Ready));
|
||||
AddUntilStep("local state is ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
|
||||
AddStep("start match", () => Client.StartMatch());
|
||||
AddUntilStep("match started", () => Client.LocalUser?.State == MultiplayerUserState.WaitingForLoad);
|
||||
AddStep("set state to loaded", () => Client.ChangeUserState(API.LocalUser.Value.Id, MultiplayerUserState.Loaded));
|
||||
AddUntilStep("local state is playing", () => Client.LocalUser?.State == MultiplayerUserState.Playing);
|
||||
AddStep("set state to finished play", () => Client.ChangeUserState(API.LocalUser.Value.Id, MultiplayerUserState.FinishedPlay));
|
||||
AddUntilStep("local state is results", () => Client.LocalUser?.State == MultiplayerUserState.Results);
|
||||
|
||||
AddStep("select item 1", () => selectedItem.Value = playlist.ChildrenOfType<RearrangeableListItem<PlaylistItem>>().ElementAt(1).Model);
|
||||
assertDeleteButtonVisibility(0, true);
|
||||
assertDeleteButtonVisibility(1, false);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
@ -22,20 +20,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
var rulesetInfo = new OsuRuleset().RulesetInfo;
|
||||
var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo;
|
||||
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
TotalScore = 987654,
|
||||
Accuracy = 0.8,
|
||||
MaxCombo = 500,
|
||||
Combo = 250,
|
||||
BeatmapInfo = beatmapInfo,
|
||||
User = new APIUser { Username = "Test user" },
|
||||
Date = DateTimeOffset.Now,
|
||||
OnlineScoreID = 12345,
|
||||
Ruleset = rulesetInfo,
|
||||
};
|
||||
var score = TestResources.CreateTestScoreInfo(beatmapInfo);
|
||||
|
||||
PlaylistItem playlistItem = new PlaylistItem
|
||||
{
|
||||
|
@ -1,15 +1,13 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
@ -26,20 +24,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
{
|
||||
var rulesetInfo = new OsuRuleset().RulesetInfo;
|
||||
var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo;
|
||||
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
TotalScore = 987654,
|
||||
Accuracy = 0.8,
|
||||
MaxCombo = 500,
|
||||
Combo = 250,
|
||||
BeatmapInfo = beatmapInfo,
|
||||
User = new APIUser { Username = "Test user" },
|
||||
Date = DateTimeOffset.Now,
|
||||
OnlineScoreID = 12345,
|
||||
Ruleset = rulesetInfo,
|
||||
};
|
||||
var score = TestResources.CreateTestScoreInfo(beatmapInfo);
|
||||
|
||||
PlaylistItem playlistItem = new PlaylistItem
|
||||
{
|
||||
|
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
imported = Game.ScoreManager.Import(new ScoreInfo
|
||||
{
|
||||
Hash = Guid.NewGuid().ToString(),
|
||||
OnlineScoreID = i,
|
||||
OnlineID = i,
|
||||
BeatmapInfo = beatmap.Beatmaps.First(),
|
||||
Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
|
||||
}).Result.Value;
|
||||
|
@ -47,9 +47,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
var allScores = new APIScoresCollection
|
||||
{
|
||||
Scores = new List<APIScoreInfo>
|
||||
Scores = new List<APIScore>
|
||||
{
|
||||
new APIScoreInfo
|
||||
new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
},
|
||||
new APIScoreInfo
|
||||
new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 1234789,
|
||||
Accuracy = 0.9997,
|
||||
},
|
||||
new APIScoreInfo
|
||||
new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 12345678,
|
||||
Accuracy = 0.9854,
|
||||
},
|
||||
new APIScoreInfo
|
||||
new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -143,7 +143,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 1234567,
|
||||
Accuracy = 0.8765,
|
||||
},
|
||||
new APIScoreInfo
|
||||
new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
var myBestScore = new APIScoreWithPosition
|
||||
{
|
||||
Score = new APIScoreInfo
|
||||
Score = new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
var myBestScoreWithNullPosition = new APIScoreWithPosition
|
||||
{
|
||||
Score = new APIScoreInfo
|
||||
Score = new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
@ -212,9 +212,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
var oneScore = new APIScoresCollection
|
||||
{
|
||||
Scores = new List<APIScoreInfo>
|
||||
Scores = new List<APIScore>
|
||||
{
|
||||
new APIScoreInfo
|
||||
new APIScore
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public TestSceneUserProfileScores()
|
||||
{
|
||||
var firstScore = new APIScoreInfo
|
||||
var firstScore = new APIScore
|
||||
{
|
||||
PP = 1047.21,
|
||||
Rank = ScoreRank.SH,
|
||||
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Accuracy = 0.9813
|
||||
};
|
||||
|
||||
var secondScore = new APIScoreInfo
|
||||
var secondScore = new APIScore
|
||||
{
|
||||
PP = 134.32,
|
||||
Rank = ScoreRank.A,
|
||||
@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Accuracy = 0.998546
|
||||
};
|
||||
|
||||
var thirdScore = new APIScoreInfo
|
||||
var thirdScore = new APIScore
|
||||
{
|
||||
PP = 96.83,
|
||||
Rank = ScoreRank.S,
|
||||
@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Accuracy = 0.9726
|
||||
};
|
||||
|
||||
var noPPScore = new APIScoreInfo
|
||||
var noPPScore = new APIScore
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
Beatmap = new APIBeatmap
|
||||
|
@ -22,14 +22,17 @@ using osu.Game.Scoring;
|
||||
using osu.Game.Screens.OnlinePlay.Playlists;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
public class TestScenePlaylistsResultsScreen : ScreenTestScene
|
||||
{
|
||||
private const int scores_per_result = 10;
|
||||
private const int real_user_position = 200;
|
||||
|
||||
private TestResultsScreen resultsScreen;
|
||||
|
||||
private int currentScoreId;
|
||||
private bool requestComplete;
|
||||
private int totalCount;
|
||||
@ -37,7 +40,7 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
{
|
||||
currentScoreId = 0;
|
||||
currentScoreId = 1;
|
||||
requestComplete = false;
|
||||
totalCount = 0;
|
||||
bindHandler();
|
||||
@ -50,13 +53,17 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
AddStep("bind user score info handler", () =>
|
||||
{
|
||||
userScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { OnlineScoreID = currentScoreId++ };
|
||||
userScore = TestResources.CreateTestScoreInfo();
|
||||
userScore.OnlineID = currentScoreId++;
|
||||
|
||||
bindHandler(userScore: userScore);
|
||||
});
|
||||
|
||||
createResults(() => userScore);
|
||||
|
||||
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineScoreID == userScore.OnlineScoreID).State == PanelState.Expanded);
|
||||
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).State == PanelState.Expanded);
|
||||
AddAssert($"score panel position is {real_user_position}",
|
||||
() => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).ScorePosition.Value == real_user_position);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -74,14 +81,16 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
AddStep("bind user score info handler", () =>
|
||||
{
|
||||
userScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { OnlineScoreID = currentScoreId++ };
|
||||
userScore = TestResources.CreateTestScoreInfo();
|
||||
userScore.OnlineID = currentScoreId++;
|
||||
|
||||
bindHandler(true, userScore);
|
||||
});
|
||||
|
||||
createResults(() => userScore);
|
||||
|
||||
AddAssert("more than 1 panel displayed", () => this.ChildrenOfType<ScorePanel>().Count() > 1);
|
||||
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineScoreID == userScore.OnlineScoreID).State == PanelState.Expanded);
|
||||
AddAssert("user score selected", () => this.ChildrenOfType<ScorePanel>().Single(p => p.Score.OnlineID == userScore.OnlineID).State == PanelState.Expanded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -123,7 +132,9 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
AddStep("bind user score info handler", () =>
|
||||
{
|
||||
userScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { OnlineScoreID = currentScoreId++ };
|
||||
userScore = TestResources.CreateTestScoreInfo();
|
||||
userScore.OnlineID = currentScoreId++;
|
||||
|
||||
bindHandler(userScore: userScore);
|
||||
});
|
||||
|
||||
@ -230,12 +241,12 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
{
|
||||
var multiplayerUserScore = new MultiplayerScore
|
||||
{
|
||||
ID = (int)(userScore.OnlineScoreID ?? currentScoreId++),
|
||||
ID = (int)(userScore.OnlineID > 0 ? userScore.OnlineID : currentScoreId++),
|
||||
Accuracy = userScore.Accuracy,
|
||||
EndedAt = userScore.Date,
|
||||
Passed = userScore.Passed,
|
||||
Rank = userScore.Rank,
|
||||
Position = 200,
|
||||
Position = real_user_position,
|
||||
MaxCombo = userScore.MaxCombo,
|
||||
TotalScore = userScore.TotalScore,
|
||||
User = userScore.User,
|
||||
|
@ -15,9 +15,11 @@ using osu.Game.Database;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.OnlinePlay.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Playlists;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Visual.OnlinePlay;
|
||||
using osuTK.Input;
|
||||
|
||||
@ -112,37 +114,80 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
[Test]
|
||||
public void TestBeatmapUpdatedOnReImport()
|
||||
{
|
||||
BeatmapSetInfo importedSet = null;
|
||||
string realHash = null;
|
||||
int realOnlineId = 0;
|
||||
int realOnlineSetId = 0;
|
||||
|
||||
AddStep("import altered beatmap", () =>
|
||||
AddStep("store real beatmap values", () =>
|
||||
{
|
||||
IBeatmap beatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
|
||||
|
||||
beatmap.BeatmapInfo.BaseDifficulty.CircleSize = 1;
|
||||
|
||||
// intentionally increment online IDs to clash with import below.
|
||||
beatmap.BeatmapInfo.OnlineID++;
|
||||
beatmap.BeatmapInfo.BeatmapSet.OnlineID++;
|
||||
|
||||
importedSet = manager.Import(beatmap.BeatmapInfo.BeatmapSet).Result.Value;
|
||||
realHash = importedBeatmap.Value.Beatmaps[0].MD5Hash;
|
||||
realOnlineId = importedBeatmap.Value.Beatmaps[0].OnlineID ?? -1;
|
||||
realOnlineSetId = importedBeatmap.Value.OnlineID ?? -1;
|
||||
});
|
||||
|
||||
AddStep("import modified beatmap", () =>
|
||||
{
|
||||
var modifiedBeatmap = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
OnlineID = realOnlineId,
|
||||
BeatmapSet =
|
||||
{
|
||||
OnlineID = realOnlineSetId
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
modifiedBeatmap.HitObjects.Clear();
|
||||
modifiedBeatmap.HitObjects.Add(new HitCircle { StartTime = 5000 });
|
||||
|
||||
manager.Import(modifiedBeatmap.BeatmapInfo.BeatmapSet).Wait();
|
||||
});
|
||||
|
||||
// Create the room using the real beatmap values.
|
||||
setupAndCreateRoom(room =>
|
||||
{
|
||||
room.Name.Value = "my awesome room";
|
||||
room.Host.Value = API.LocalUser.Value;
|
||||
room.Playlist.Add(new PlaylistItem
|
||||
{
|
||||
Beatmap = { Value = importedSet.Beatmaps[0] },
|
||||
Beatmap =
|
||||
{
|
||||
Value = new BeatmapInfo
|
||||
{
|
||||
MD5Hash = realHash,
|
||||
OnlineID = realOnlineId,
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineID = realOnlineSetId,
|
||||
}
|
||||
}
|
||||
},
|
||||
Ruleset = { Value = new OsuRuleset().RulesetInfo }
|
||||
});
|
||||
});
|
||||
|
||||
AddAssert("match has altered beatmap", () => match.Beatmap.Value.Beatmap.Difficulty.CircleSize == 1);
|
||||
AddAssert("match has default beatmap", () => match.Beatmap.IsDefault);
|
||||
|
||||
importBeatmap();
|
||||
AddStep("reimport original beatmap", () =>
|
||||
{
|
||||
var originalBeatmap = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
OnlineID = realOnlineId,
|
||||
BeatmapSet =
|
||||
{
|
||||
OnlineID = realOnlineSetId
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
AddAssert("match has original beatmap", () => match.Beatmap.Value.Beatmap.Difficulty.CircleSize != 1);
|
||||
manager.Import(originalBeatmap.BeatmapInfo.BeatmapSet).Wait();
|
||||
});
|
||||
|
||||
AddUntilStep("match has correct beatmap", () => realHash == match.Beatmap.Value.BeatmapInfo.MD5Hash);
|
||||
}
|
||||
|
||||
private void setupAndCreateRoom(Action<Room> room)
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -13,6 +14,7 @@ using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Contracted;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
@ -22,13 +24,18 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestShowPanel()
|
||||
{
|
||||
AddStep("show example score", () => showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new TestScoreInfo(new OsuRuleset().RulesetInfo)));
|
||||
AddStep("show example score", () => showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), TestResources.CreateTestScoreInfo()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExcessMods()
|
||||
{
|
||||
AddStep("show excess mods score", () => showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new TestScoreInfo(new OsuRuleset().RulesetInfo, true)));
|
||||
AddStep("show excess mods score", () =>
|
||||
{
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Mods = score.BeatmapInfo.Ruleset.CreateInstance().CreateAllMods().ToArray();
|
||||
showPanel(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), score);
|
||||
});
|
||||
}
|
||||
|
||||
private void showPanel(WorkingBeatmap workingBeatmap, ScoreInfo score)
|
||||
|
@ -20,6 +20,7 @@ using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
@ -34,21 +35,21 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
var author = new APIUser { Username = "mapper_name" };
|
||||
|
||||
AddStep("show example score", () => showPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo = createTestBeatmap(author)
|
||||
}));
|
||||
AddStep("show example score", () => showPanel(TestResources.CreateTestScoreInfo(createTestBeatmap(author))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExcessMods()
|
||||
{
|
||||
var author = new APIUser { Username = "mapper_name" };
|
||||
|
||||
AddStep("show excess mods score", () => showPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo, true)
|
||||
AddStep("show excess mods score", () =>
|
||||
{
|
||||
BeatmapInfo = createTestBeatmap(author)
|
||||
}));
|
||||
var author = new APIUser { Username = "mapper_name" };
|
||||
|
||||
var score = TestResources.CreateTestScoreInfo(createTestBeatmap(author));
|
||||
score.Mods = score.BeatmapInfo.Ruleset.CreateInstance().CreateAllMods().ToArray();
|
||||
|
||||
showPanel(score);
|
||||
});
|
||||
|
||||
AddAssert("mapper name present", () => this.ChildrenOfType<OsuSpriteText>().Any(spriteText => spriteText.Current.Value == "mapper_name"));
|
||||
}
|
||||
@ -56,10 +57,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestMapWithUnknownMapper()
|
||||
{
|
||||
AddStep("show example score", () => showPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo = createTestBeatmap(new APIUser())
|
||||
}));
|
||||
AddStep("show example score", () => showPanel(TestResources.CreateTestScoreInfo(createTestBeatmap(new APIUser()))));
|
||||
|
||||
AddAssert("mapped by text not present", () =>
|
||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by")));
|
||||
@ -77,12 +75,12 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
var mods = new Mod[] { ruleset.GetAutoplayMod() };
|
||||
var beatmap = createTestBeatmap(new APIUser());
|
||||
|
||||
showPanel(new TestScoreInfo(ruleset.RulesetInfo)
|
||||
{
|
||||
Mods = mods,
|
||||
BeatmapInfo = beatmap,
|
||||
Date = default,
|
||||
});
|
||||
var score = TestResources.CreateTestScoreInfo(beatmap);
|
||||
|
||||
score.Mods = mods;
|
||||
score.Date = default;
|
||||
|
||||
showPanel(score);
|
||||
});
|
||||
|
||||
AddAssert("play time not displayed", () => !this.ChildrenOfType<ExpandedPanelMiddleContent.PlayedOnText>().Any());
|
||||
|
@ -5,8 +5,8 @@ using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Ranking.Expanded;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4Extensions.FromHex("#444"),
|
||||
},
|
||||
new ExpandedPanelTopContent(new TestScoreInfo(new OsuRuleset().RulesetInfo).User),
|
||||
new ExpandedPanelTopContent(TestResources.CreateTestScoreInfo().User),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -15,12 +15,12 @@ using osu.Framework.Utils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Screens.Ranking.Statistics;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
@ -72,11 +72,10 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
TestResultsScreen screen = null;
|
||||
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
Accuracy = accuracy,
|
||||
Rank = rank
|
||||
};
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
|
||||
score.Accuracy = accuracy;
|
||||
score.Rank = rank;
|
||||
|
||||
AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen(score)));
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
@ -204,7 +203,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
DelayedFetchResultsScreen screen = null;
|
||||
|
||||
AddStep("load results", () => Child = new TestResultsContainer(screen = new DelayedFetchResultsScreen(new TestScoreInfo(new OsuRuleset().RulesetInfo), 3000)));
|
||||
AddStep("load results", () => Child = new TestResultsContainer(screen = new DelayedFetchResultsScreen(TestResources.CreateTestScoreInfo(), 3000)));
|
||||
AddUntilStep("wait for loaded", () => screen.IsLoaded);
|
||||
AddStep("click expanded panel", () =>
|
||||
{
|
||||
@ -237,9 +236,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
AddAssert("download button is enabled", () => screen.ChildrenOfType<DownloadButton>().Last().Enabled.Value);
|
||||
}
|
||||
|
||||
private TestResultsScreen createResultsScreen(ScoreInfo score = null) => new TestResultsScreen(score ?? new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||
private TestResultsScreen createResultsScreen(ScoreInfo score = null) => new TestResultsScreen(score ?? TestResources.CreateTestScoreInfo());
|
||||
|
||||
private UnrankedSoloResultsScreen createUnrankedSoloResultsScreen() => new UnrankedSoloResultsScreen(new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||
private UnrankedSoloResultsScreen createUnrankedSoloResultsScreen() => new UnrankedSoloResultsScreen(TestResources.CreateTestScoreInfo());
|
||||
|
||||
private class TestResultsContainer : Container
|
||||
{
|
||||
@ -282,7 +281,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.TotalScore += 10 - i;
|
||||
score.Hash = $"test{i}";
|
||||
scores.Add(score);
|
||||
@ -316,7 +315,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.TotalScore += 10 - i;
|
||||
scores.Add(score);
|
||||
}
|
||||
|
@ -3,10 +3,10 @@
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Resources;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
@ -17,7 +17,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestDRank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.5, Rank = ScoreRank.D };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.5;
|
||||
score.Rank = ScoreRank.D;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -25,7 +27,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestCRank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.75, Rank = ScoreRank.C };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.75;
|
||||
score.Rank = ScoreRank.C;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -33,7 +37,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestBRank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.85, Rank = ScoreRank.B };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.85;
|
||||
score.Rank = ScoreRank.B;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -41,7 +47,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestARank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -49,7 +57,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestSRank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.975, Rank = ScoreRank.S };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.975;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -57,7 +67,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAlmostSSRank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.9999, Rank = ScoreRank.S };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.9999;
|
||||
score.Rank = ScoreRank.S;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -65,7 +77,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestSSRank()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 1, Rank = ScoreRank.X };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 1;
|
||||
score.Rank = ScoreRank.X;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -73,7 +87,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAllHitResults()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Statistics = { [HitResult.Perfect] = 350, [HitResult.Ok] = 200 } };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Statistics[HitResult.Perfect] = 350;
|
||||
score.Statistics[HitResult.Ok] = 200;
|
||||
|
||||
addPanelStep(score);
|
||||
}
|
||||
@ -81,7 +97,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestContractedPanel()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
|
||||
addPanelStep(score, PanelState.Contracted);
|
||||
}
|
||||
@ -89,7 +107,9 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestExpandAndContract()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo) { Accuracy = 0.925, Rank = ScoreRank.A };
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.Accuracy = 0.925;
|
||||
score.Rank = ScoreRank.A;
|
||||
|
||||
addPanelStep(score, PanelState.Contracted);
|
||||
AddWaitStep("wait for transition", 10);
|
||||
|
@ -7,9 +7,9 @@ using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
@ -29,14 +29,14 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
{
|
||||
createListStep(() => new ScorePanelList
|
||||
{
|
||||
SelectedScore = { Value = new TestScoreInfo(new OsuRuleset().RulesetInfo) }
|
||||
SelectedScore = { Value = TestResources.CreateTestScoreInfo() }
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddPanelAfterSelectingScore()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
|
||||
createListStep(() => new ScorePanelList
|
||||
{
|
||||
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAddPanelBeforeSelectingScore()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
|
||||
createListStep(() => new ScorePanelList());
|
||||
|
||||
@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
AddStep("add many scores", () =>
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||
list.AddScore(TestResources.CreateTestScoreInfo());
|
||||
});
|
||||
|
||||
assertFirstPanelCentred();
|
||||
@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAddManyScoresAfterExpandedPanel()
|
||||
{
|
||||
var initialScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var initialScore = TestResources.CreateTestScoreInfo();
|
||||
|
||||
createListStep(() => new ScorePanelList());
|
||||
|
||||
@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
AddStep("add many scores", () =>
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore - i - 1 });
|
||||
list.AddScore(createScoreForTotalScore(initialScore.TotalScore - i - 1));
|
||||
});
|
||||
|
||||
assertScoreState(initialScore, true);
|
||||
@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAddManyScoresBeforeExpandedPanel()
|
||||
{
|
||||
var initialScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var initialScore = TestResources.CreateTestScoreInfo();
|
||||
|
||||
createListStep(() => new ScorePanelList());
|
||||
|
||||
@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
AddStep("add scores", () =>
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore + i + 1 });
|
||||
list.AddScore(createScoreForTotalScore(initialScore.TotalScore + i + 1));
|
||||
});
|
||||
|
||||
assertScoreState(initialScore, true);
|
||||
@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAddManyPanelsOnBothSidesOfExpandedPanel()
|
||||
{
|
||||
var initialScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var initialScore = TestResources.CreateTestScoreInfo();
|
||||
|
||||
createListStep(() => new ScorePanelList());
|
||||
|
||||
@ -143,10 +143,10 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
AddStep("add scores after", () =>
|
||||
{
|
||||
for (int i = 0; i < 20; i++)
|
||||
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore - i - 1 });
|
||||
list.AddScore(createScoreForTotalScore(initialScore.TotalScore - i - 1));
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
list.AddScore(new TestScoreInfo(new OsuRuleset().RulesetInfo) { TotalScore = initialScore.TotalScore + i + 1 });
|
||||
list.AddScore(createScoreForTotalScore(initialScore.TotalScore + i + 1));
|
||||
});
|
||||
|
||||
assertScoreState(initialScore, true);
|
||||
@ -156,11 +156,11 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestSelectMultipleScores()
|
||||
{
|
||||
var firstScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var secondScore = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var firstScore = TestResources.CreateTestScoreInfo();
|
||||
var secondScore = TestResources.CreateTestScoreInfo();
|
||||
|
||||
firstScore.User.Username = "A";
|
||||
secondScore.User.Username = "B";
|
||||
firstScore.UserString = "A";
|
||||
secondScore.UserString = "B";
|
||||
|
||||
createListStep(() => new ScorePanelList());
|
||||
|
||||
@ -190,7 +190,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestAddScoreImmediately()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo);
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
|
||||
createListStep(() =>
|
||||
{
|
||||
@ -206,9 +206,14 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestKeyboardNavigation()
|
||||
{
|
||||
var lowestScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { MaxCombo = 100 };
|
||||
var middleScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { MaxCombo = 200 };
|
||||
var highestScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { MaxCombo = 300 };
|
||||
var lowestScore = TestResources.CreateTestScoreInfo();
|
||||
lowestScore.MaxCombo = 100;
|
||||
|
||||
var middleScore = TestResources.CreateTestScoreInfo();
|
||||
middleScore.MaxCombo = 200;
|
||||
|
||||
var highestScore = TestResources.CreateTestScoreInfo();
|
||||
highestScore.MaxCombo = 300;
|
||||
|
||||
createListStep(() => new ScorePanelList());
|
||||
|
||||
@ -270,6 +275,13 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
assertExpandedPanelCentred();
|
||||
}
|
||||
|
||||
private ScoreInfo createScoreForTotalScore(long totalScore)
|
||||
{
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.TotalScore = totalScore;
|
||||
return score;
|
||||
}
|
||||
|
||||
private void createListStep(Func<ScorePanelList> creationFunc)
|
||||
{
|
||||
AddStep("create list", () => Child = list = creationFunc().With(d =>
|
||||
|
@ -6,11 +6,11 @@ using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking.Statistics;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Ranking
|
||||
@ -20,10 +20,8 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestScoreWithTimeStatistics()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents()
|
||||
};
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.HitEvents = TestSceneHitEventTimingDistributionGraph.CreateDistributedHitEvents();
|
||||
|
||||
loadPanel(score);
|
||||
}
|
||||
@ -31,10 +29,8 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestScoreWithPositionStatistics()
|
||||
{
|
||||
var score = new TestScoreInfo(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
HitEvents = createPositionDistributedHitEvents()
|
||||
};
|
||||
var score = TestResources.CreateTestScoreInfo();
|
||||
score.HitEvents = createPositionDistributedHitEvents();
|
||||
|
||||
loadPanel(score);
|
||||
}
|
||||
@ -42,7 +38,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
[Test]
|
||||
public void TestScoreWithoutStatistics()
|
||||
{
|
||||
loadPanel(new TestScoreInfo(new OsuRuleset().RulesetInfo));
|
||||
loadPanel(TestResources.CreateTestScoreInfo());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -835,12 +835,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
// this beatmap change should be overridden by the present.
|
||||
Beatmap.Value = manager.GetWorkingBeatmap(getSwitchBeatmap());
|
||||
|
||||
songSelect.PresentScore(new ScoreInfo
|
||||
{
|
||||
User = new APIUser { Username = "woo" },
|
||||
BeatmapInfo = getPresentBeatmap(),
|
||||
Ruleset = getPresentBeatmap().Ruleset
|
||||
});
|
||||
songSelect.PresentScore(TestResources.CreateTestScoreInfo(getPresentBeatmap()));
|
||||
});
|
||||
|
||||
AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen());
|
||||
|
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
var score = new ScoreInfo
|
||||
{
|
||||
OnlineScoreID = i,
|
||||
OnlineID = i,
|
||||
BeatmapInfo = beatmapInfo,
|
||||
BeatmapInfoID = beatmapInfo.ID,
|
||||
Accuracy = RNG.NextDouble(),
|
||||
@ -163,7 +163,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
});
|
||||
|
||||
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
|
||||
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != scoreBeingDeleted.OnlineScoreID));
|
||||
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -171,7 +171,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
AddStep("delete top score", () => scoreManager.Delete(importedScores[0]));
|
||||
AddUntilStep("wait for fetch", () => leaderboard.Scores != null);
|
||||
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != importedScores[0].OnlineScoreID));
|
||||
AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ namespace osu.Game.Database
|
||||
|
||||
modelBuilder.Entity<BeatmapInfo>().HasOne(b => b.BaseDifficulty);
|
||||
|
||||
modelBuilder.Entity<ScoreInfo>().HasIndex(b => b.OnlineScoreID).IsUnique();
|
||||
modelBuilder.Entity<ScoreInfo>().HasIndex(b => b.OnlineID).IsUnique();
|
||||
}
|
||||
|
||||
private class OsuDbLoggerFactory : ILoggerFactory
|
||||
|
@ -104,6 +104,14 @@ namespace osu.Game.Extensions
|
||||
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
||||
public static bool MatchesOnlineID(this APIUser? instance, APIUser? other) => matchesOnlineID(instance, other);
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the online ID of two <see cref="IScoreInfo"/>s match.
|
||||
/// </summary>
|
||||
/// <param name="instance">The instance to compare.</param>
|
||||
/// <param name="other">The other instance to compare against.</param>
|
||||
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
||||
public static bool MatchesOnlineID(this IScoreInfo? instance, IScoreInfo? other) => matchesOnlineID(instance, other);
|
||||
|
||||
private static bool matchesOnlineID(this IHasOnlineID<long>? instance, IHasOnlineID<long>? other)
|
||||
{
|
||||
if (instance == null || other == null)
|
||||
|
@ -81,20 +81,37 @@ namespace osu.Game.Input
|
||||
// compare counts in database vs defaults for each action type.
|
||||
foreach (var defaultsForAction in defaults.GroupBy(k => k.Action))
|
||||
{
|
||||
// avoid performing redundant queries when the database is empty and needs to be re-filled.
|
||||
int existingCount = existingBindings.Count(k => k.RulesetName == rulesetName && k.Variant == variant && k.ActionInt == (int)defaultsForAction.Key);
|
||||
IEnumerable<RealmKeyBinding> existing = existingBindings.Where(k =>
|
||||
k.RulesetName == rulesetName
|
||||
&& k.Variant == variant
|
||||
&& k.ActionInt == (int)defaultsForAction.Key);
|
||||
|
||||
if (defaultsForAction.Count() <= existingCount)
|
||||
continue;
|
||||
int defaultsCount = defaultsForAction.Count();
|
||||
int existingCount = existing.Count();
|
||||
|
||||
// insert any defaults which are missing.
|
||||
realm.Add(defaultsForAction.Skip(existingCount).Select(k => new RealmKeyBinding
|
||||
if (defaultsCount > existingCount)
|
||||
{
|
||||
KeyCombinationString = k.KeyCombination.ToString(),
|
||||
ActionInt = (int)k.Action,
|
||||
RulesetName = rulesetName,
|
||||
Variant = variant
|
||||
}));
|
||||
// insert any defaults which are missing.
|
||||
realm.Add(defaultsForAction.Skip(existingCount).Select(k => new RealmKeyBinding
|
||||
{
|
||||
KeyCombinationString = k.KeyCombination.ToString(),
|
||||
ActionInt = (int)k.Action,
|
||||
RulesetName = rulesetName,
|
||||
Variant = variant
|
||||
}));
|
||||
}
|
||||
else if (defaultsCount < existingCount)
|
||||
{
|
||||
// generally this shouldn't happen, but if the user has more key bindings for an action than we expect,
|
||||
// remove the last entries until the count matches for sanity.
|
||||
foreach (var k in existing.TakeLast(existingCount - defaultsCount).ToArray())
|
||||
{
|
||||
realm.Remove(k);
|
||||
|
||||
// Remove from the local flattened/cached list so future lookups don't query now deleted rows.
|
||||
existingBindings.Remove(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserScoresRequest : PaginatedAPIRequest<List<APIScoreInfo>>
|
||||
public class GetUserScoresRequest : PaginatedAPIRequest<List<APIScore>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly ScoreType type;
|
||||
|
@ -13,10 +13,11 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
public class APIScoreInfo : IScoreInfo
|
||||
public class APIScore : IScoreInfo
|
||||
{
|
||||
[JsonProperty(@"score")]
|
||||
public long TotalScore { get; set; }
|
||||
@ -101,7 +102,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
BeatmapInfo = beatmap,
|
||||
User = User,
|
||||
Accuracy = Accuracy,
|
||||
OnlineScoreID = OnlineID,
|
||||
OnlineID = OnlineID,
|
||||
Date = Date,
|
||||
PP = PP,
|
||||
RulesetID = RulesetID,
|
||||
@ -150,6 +151,11 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
public IRulesetInfo Ruleset => new RulesetInfo { OnlineID = RulesetID };
|
||||
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => throw new NotImplementedException();
|
||||
|
||||
#region Implementation of IScoreInfo
|
||||
|
||||
IBeatmapInfo IScoreInfo.Beatmap => Beatmap;
|
||||
IUser IScoreInfo.User => User;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
public int? Position;
|
||||
|
||||
[JsonProperty(@"score")]
|
||||
public APIScoreInfo Score;
|
||||
public APIScore Score;
|
||||
|
||||
public ScoreInfo CreateScoreInfo(RulesetStore rulesets, BeatmapInfo beatmap = null)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
public class APIScoresCollection
|
||||
{
|
||||
[JsonProperty(@"scores")]
|
||||
public List<APIScoreInfo> Scores;
|
||||
public List<APIScore> Scores;
|
||||
|
||||
[JsonProperty(@"userScore")]
|
||||
public APIScoreWithPosition UserScore;
|
||||
|
@ -1,10 +1,10 @@
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -120,16 +120,21 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
private void checkForMentions(Channel channel, Message message)
|
||||
{
|
||||
if (!notifyOnUsername.Value || !checkContainsUsername(message.Content, localUser.Value.Username)) return;
|
||||
if (!notifyOnUsername.Value || !CheckContainsUsername(message.Content, localUser.Value.Username)) return;
|
||||
|
||||
notifications.Post(new MentionNotification(message.Sender.Username, channel));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if <paramref name="message"/> contains <paramref name="username"/>.
|
||||
/// Checks if <paramref name="message"/> mentions <paramref name="username"/>.
|
||||
/// This will match against the case where underscores are used instead of spaces (which is how osu-stable handles usernames with spaces).
|
||||
/// </summary>
|
||||
private static bool checkContainsUsername(string message, string username) => message.Contains(username, StringComparison.OrdinalIgnoreCase) || message.Contains(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase);
|
||||
public static bool CheckContainsUsername(string message, string username)
|
||||
{
|
||||
string fullName = Regex.Escape(username);
|
||||
string underscoreName = Regex.Escape(username.Replace(' ', '_'));
|
||||
return Regex.IsMatch(message, $@"(^|\W)({fullName}|{underscoreName})($|\W)", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public class PrivateMessageNotification : OpenChannelNotification
|
||||
{
|
||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Online.Leaderboards
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = user.Id == api.LocalUser.Value.Id && allowHighlight ? colour.Green : Color4.Black,
|
||||
Colour = user.OnlineID == api.LocalUser.Value.Id && allowHighlight ? colour.Green : Color4.Black,
|
||||
Alpha = background_alpha,
|
||||
},
|
||||
},
|
||||
|
@ -95,8 +95,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
protected readonly BindableList<int> PlayingUserIds = new BindableList<int>();
|
||||
|
||||
public readonly Bindable<PlaylistItem?> CurrentMatchPlayingItem = new Bindable<PlaylistItem?>();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MultiplayerRoomUser"/> corresponding to the local player, if available.
|
||||
/// </summary>
|
||||
@ -162,9 +160,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
var joinedRoom = await JoinRoom(room.RoomID.Value.Value, password ?? room.Password.Value).ConfigureAwait(false);
|
||||
Debug.Assert(joinedRoom != null);
|
||||
|
||||
// Populate playlist items.
|
||||
var playlistItems = await Task.WhenAll(joinedRoom.Playlist.Select(item => createPlaylistItem(item, item.ID == joinedRoom.Settings.PlaylistItemId))).ConfigureAwait(false);
|
||||
|
||||
// Populate users.
|
||||
Debug.Assert(joinedRoom.Users != null);
|
||||
await Task.WhenAll(joinedRoom.Users.Select(PopulateUser)).ConfigureAwait(false);
|
||||
@ -176,7 +171,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
APIRoom = room;
|
||||
|
||||
APIRoom.Playlist.Clear();
|
||||
APIRoom.Playlist.AddRange(playlistItems);
|
||||
APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(createPlaylistItem));
|
||||
|
||||
Debug.Assert(LocalUser != null);
|
||||
addUserToAPIRoom(LocalUser);
|
||||
@ -219,7 +214,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
APIRoom = null;
|
||||
Room = null;
|
||||
CurrentMatchPlayingItem.Value = null;
|
||||
PlayingUserIds.Clear();
|
||||
|
||||
RoomUpdated?.Invoke();
|
||||
@ -477,28 +471,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
Debug.Assert(APIRoom != null);
|
||||
Debug.Assert(Room != null);
|
||||
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
// ensure the new selected item is populated immediately.
|
||||
var playlistItem = APIRoom.Playlist.Single(p => p.ID == newSettings.PlaylistItemId);
|
||||
|
||||
if (playlistItem != null)
|
||||
{
|
||||
GetAPIBeatmap(playlistItem.BeatmapID).ContinueWith(b =>
|
||||
{
|
||||
// Should be called outside of the `Scheduler` logic (and specifically accessing `Exception`) to suppress an exception from firing outwards.
|
||||
bool success = b.Exception == null;
|
||||
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
if (success)
|
||||
playlistItem.Beatmap.Value = b.Result;
|
||||
|
||||
updateLocalRoomSettings(newSettings);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
Scheduler.Add(() => updateLocalRoomSettings(newSettings));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -653,12 +626,10 @@ namespace osu.Game.Online.Multiplayer
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task PlaylistItemAdded(MultiplayerPlaylistItem item)
|
||||
public Task PlaylistItemAdded(MultiplayerPlaylistItem item)
|
||||
{
|
||||
if (Room == null)
|
||||
return;
|
||||
|
||||
var playlistItem = await createPlaylistItem(item, true).ConfigureAwait(false);
|
||||
return Task.CompletedTask;
|
||||
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
@ -668,11 +639,13 @@ namespace osu.Game.Online.Multiplayer
|
||||
Debug.Assert(APIRoom != null);
|
||||
|
||||
Room.Playlist.Add(item);
|
||||
APIRoom.Playlist.Add(playlistItem);
|
||||
APIRoom.Playlist.Add(createPlaylistItem(item));
|
||||
|
||||
ItemAdded?.Invoke(item);
|
||||
RoomUpdated?.Invoke();
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task PlaylistItemRemoved(long playlistItemId)
|
||||
@ -697,12 +670,10 @@ namespace osu.Game.Online.Multiplayer
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task PlaylistItemChanged(MultiplayerPlaylistItem item)
|
||||
public Task PlaylistItemChanged(MultiplayerPlaylistItem item)
|
||||
{
|
||||
if (Room == null)
|
||||
return;
|
||||
|
||||
var playlistItem = await createPlaylistItem(item, true).ConfigureAwait(false);
|
||||
return Task.CompletedTask;
|
||||
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
@ -715,15 +686,13 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID));
|
||||
APIRoom.Playlist.RemoveAt(existingIndex);
|
||||
APIRoom.Playlist.Insert(existingIndex, playlistItem);
|
||||
|
||||
// If the currently-selected item was the one that got replaced, update the selected item to the new one.
|
||||
if (CurrentMatchPlayingItem.Value?.ID == playlistItem.ID)
|
||||
CurrentMatchPlayingItem.Value = playlistItem;
|
||||
APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item));
|
||||
|
||||
ItemChanged?.Invoke(item);
|
||||
RoomUpdated?.Invoke();
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -752,12 +721,11 @@ namespace osu.Game.Online.Multiplayer
|
||||
APIRoom.Password.Value = Room.Settings.Password;
|
||||
APIRoom.Type.Value = Room.Settings.MatchType;
|
||||
APIRoom.QueueMode.Value = Room.Settings.QueueMode;
|
||||
RoomUpdated?.Invoke();
|
||||
|
||||
CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId);
|
||||
RoomUpdated?.Invoke();
|
||||
}
|
||||
|
||||
private async Task<PlaylistItem> createPlaylistItem(MultiplayerPlaylistItem item, bool populateBeatmapImmediately)
|
||||
private PlaylistItem createPlaylistItem(MultiplayerPlaylistItem item)
|
||||
{
|
||||
var ruleset = Rulesets.GetRuleset(item.RulesetID);
|
||||
|
||||
@ -779,9 +747,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
playlistItem.RequiredMods.AddRange(item.RequiredMods.Select(m => m.ToMod(rulesetInstance)));
|
||||
playlistItem.AllowedMods.AddRange(item.AllowedMods.Select(m => m.ToMod(rulesetInstance)));
|
||||
|
||||
if (populateBeatmapImmediately)
|
||||
playlistItem.Beatmap.Value = await GetAPIBeatmap(item.BeatmapID).ConfigureAwait(false);
|
||||
|
||||
return playlistItem;
|
||||
}
|
||||
|
||||
@ -791,7 +756,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
/// <param name="beatmapId">The beatmap ID.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the request.</param>
|
||||
/// <returns>The <see cref="APIBeatmap"/> retrieval task.</returns>
|
||||
protected abstract Task<APIBeatmap> GetAPIBeatmap(int beatmapId, CancellationToken cancellationToken = default);
|
||||
public abstract Task<APIBeatmap> GetAPIBeatmap(int beatmapId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// For the provided user ID, update whether the user is included in <see cref="CurrentMatchPlayingUserIds"/>.
|
||||
|
@ -178,7 +178,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), playlistItemId);
|
||||
}
|
||||
|
||||
protected override Task<APIBeatmap> GetAPIBeatmap(int beatmapId, CancellationToken cancellationToken = default)
|
||||
public override Task<APIBeatmap> GetAPIBeatmap(int beatmapId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return beatmapLookupCache.GetBeatmapAsync(beatmapId, cancellationToken);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Online.Rooms
|
||||
|
||||
var scoreInfo = new ScoreInfo
|
||||
{
|
||||
OnlineScoreID = ID,
|
||||
OnlineID = ID,
|
||||
TotalScore = TotalScore,
|
||||
MaxCombo = MaxCombo,
|
||||
BeatmapInfo = beatmap,
|
||||
|
@ -40,6 +40,11 @@ namespace osu.Game.Online.Rooms
|
||||
|
||||
private BeatmapDownloadTracker downloadTracker;
|
||||
|
||||
/// <summary>
|
||||
/// The beatmap matching the required hash (and providing a final <see cref="BeatmapAvailability.LocallyAvailable"/> state).
|
||||
/// </summary>
|
||||
private BeatmapInfo matchingHash;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
@ -71,13 +76,34 @@ namespace osu.Game.Online.Rooms
|
||||
progressUpdate = Scheduler.AddDelayed(updateAvailability, progressUpdate == null ? 0 : 500);
|
||||
}, true);
|
||||
}, true);
|
||||
|
||||
// These events are needed for a fringe case where a modified/altered beatmap is imported with matching OnlineIDs.
|
||||
// During the import process this will cause the existing beatmap set to be silently deleted and replaced with the new one.
|
||||
// This is not exposed to us via `BeatmapDownloadTracker` so we have to take it into our own hands (as we care about the hash matching).
|
||||
beatmapManager.ItemUpdated += itemUpdated;
|
||||
beatmapManager.ItemRemoved += itemRemoved;
|
||||
}
|
||||
|
||||
private void itemUpdated(BeatmapSetInfo item) => Schedule(() =>
|
||||
{
|
||||
if (matchingHash?.BeatmapSet.ID == item.ID || SelectedItem.Value?.Beatmap.Value.BeatmapSet?.OnlineID == item.OnlineID)
|
||||
updateAvailability();
|
||||
});
|
||||
|
||||
private void itemRemoved(BeatmapSetInfo item) => Schedule(() =>
|
||||
{
|
||||
if (matchingHash?.BeatmapSet.ID == item.ID)
|
||||
updateAvailability();
|
||||
});
|
||||
|
||||
private void updateAvailability()
|
||||
{
|
||||
if (downloadTracker == null)
|
||||
return;
|
||||
|
||||
// will be repopulated below if still valid.
|
||||
matchingHash = null;
|
||||
|
||||
switch (downloadTracker.State.Value)
|
||||
{
|
||||
case DownloadState.NotDownloaded:
|
||||
@ -93,7 +119,9 @@ namespace osu.Game.Online.Rooms
|
||||
break;
|
||||
|
||||
case DownloadState.LocallyAvailable:
|
||||
bool hashMatches = checkHashValidity();
|
||||
matchingHash = findMatchingHash();
|
||||
|
||||
bool hashMatches = matchingHash != null;
|
||||
|
||||
availability.Value = hashMatches ? BeatmapAvailability.LocallyAvailable() : BeatmapAvailability.NotDownloaded();
|
||||
|
||||
@ -108,12 +136,23 @@ namespace osu.Game.Online.Rooms
|
||||
}
|
||||
}
|
||||
|
||||
private bool checkHashValidity()
|
||||
private BeatmapInfo findMatchingHash()
|
||||
{
|
||||
int onlineId = SelectedItem.Value.Beatmap.Value.OnlineID;
|
||||
string checksum = SelectedItem.Value.Beatmap.Value.MD5Hash;
|
||||
|
||||
return beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending) != null;
|
||||
return beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId && b.MD5Hash == checksum && !b.BeatmapSet.DeletePending);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (beatmapManager != null)
|
||||
{
|
||||
beatmapManager.ItemUpdated -= itemUpdated;
|
||||
beatmapManager.ItemRemoved -= itemRemoved;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Online.Rooms
|
||||
|
||||
req.ContentType = "application/json";
|
||||
req.Method = HttpMethod.Put;
|
||||
req.Timeout = 30000;
|
||||
|
||||
req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
@ -35,7 +36,7 @@ namespace osu.Game.Online
|
||||
var scoreInfo = new ScoreInfo
|
||||
{
|
||||
ID = TrackedItem.ID,
|
||||
OnlineScoreID = TrackedItem.OnlineScoreID
|
||||
OnlineID = TrackedItem.OnlineID
|
||||
};
|
||||
|
||||
if (Manager.IsAvailableLocally(scoreInfo))
|
||||
@ -113,7 +114,7 @@ namespace osu.Game.Online
|
||||
UpdateState(DownloadState.NotDownloaded);
|
||||
});
|
||||
|
||||
private bool checkEquality(IScoreInfo x, IScoreInfo y) => x.OnlineID == y.OnlineID;
|
||||
private bool checkEquality(IScoreInfo x, IScoreInfo y) => x.MatchesOnlineID(y);
|
||||
|
||||
#region Disposal
|
||||
|
||||
|
@ -31,6 +31,7 @@ namespace osu.Game.Online.Solo
|
||||
|
||||
req.ContentType = "application/json";
|
||||
req.Method = HttpMethod.Put;
|
||||
req.Timeout = 30000;
|
||||
|
||||
req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Online.Solo
|
||||
{
|
||||
/// <summary>
|
||||
/// A class specifically for sending scores to the API during score submission.
|
||||
/// This is used instead of <see cref="APIScoreInfo"/> due to marginally different serialisation naming requirements.
|
||||
/// This is used instead of <see cref="APIScore"/> due to marginally different serialisation naming requirements.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SubmittableScore
|
||||
|
@ -103,7 +103,7 @@ namespace osu.Game
|
||||
|
||||
private Container topMostOverlayContent;
|
||||
|
||||
private ScalingContainer screenContainer;
|
||||
protected ScalingContainer ScreenContainer { get; private set; }
|
||||
|
||||
protected Container ScreenOffsetContainer { get; private set; }
|
||||
|
||||
@ -179,7 +179,7 @@ namespace osu.Game
|
||||
}
|
||||
|
||||
private void updateBlockingOverlayFade() =>
|
||||
screenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
|
||||
ScreenContainer.FadeColour(visibleBlockingOverlays.Any() ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
|
||||
|
||||
public void AddBlockingOverlay(OverlayContainer overlay)
|
||||
{
|
||||
@ -487,8 +487,8 @@ namespace osu.Game
|
||||
// to ensure all the required data for presenting a replay are present.
|
||||
ScoreInfo databasedScoreInfo = null;
|
||||
|
||||
if (score.OnlineScoreID != null)
|
||||
databasedScoreInfo = ScoreManager.Query(s => s.OnlineScoreID == score.OnlineScoreID);
|
||||
if (score.OnlineID > 0)
|
||||
databasedScoreInfo = ScoreManager.Query(s => s.OnlineID == score.OnlineID);
|
||||
|
||||
databasedScoreInfo ??= ScoreManager.Query(s => s.Hash == score.Hash);
|
||||
|
||||
@ -698,7 +698,7 @@ namespace osu.Game
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
|
||||
ScreenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
@ -801,7 +801,7 @@ namespace osu.Game
|
||||
loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true);
|
||||
loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true);
|
||||
loadComponentSingleFile(wikiOverlay = new WikiOverlay(), overlayContent.Add, true);
|
||||
loadComponentSingleFile(skinEditor = new SkinEditorOverlay(screenContainer), overlayContent.Add, true);
|
||||
loadComponentSingleFile(skinEditor = new SkinEditorOverlay(ScreenContainer), overlayContent.Add, true);
|
||||
|
||||
loadComponentSingleFile(new LoginOverlay
|
||||
{
|
||||
|
@ -94,7 +94,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
topScoresContainer.Add(new DrawableTopScore(topScore));
|
||||
|
||||
if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID)
|
||||
if (userScoreInfo != null && userScoreInfo.OnlineID != topScore.OnlineID)
|
||||
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
|
||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
|
||||
private const float performance_background_shear = 0.45f;
|
||||
|
||||
protected readonly APIScoreInfo Score;
|
||||
protected readonly APIScore Score;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
public DrawableProfileScore(APIScoreInfo score)
|
||||
public DrawableProfileScore(APIScore score)
|
||||
{
|
||||
Score = score;
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
private readonly double weight;
|
||||
|
||||
public DrawableProfileWeightedScore(APIScoreInfo score, double weight)
|
||||
public DrawableProfileWeightedScore(APIScore score, double weight)
|
||||
: base(score)
|
||||
{
|
||||
this.weight = weight;
|
||||
|
@ -15,7 +15,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
public class PaginatedScoreContainer : PaginatedProfileSubsection<APIScoreInfo>
|
||||
public class PaginatedScoreContainer : PaginatedProfileSubsection<APIScore>
|
||||
{
|
||||
private readonly ScoreType type;
|
||||
|
||||
@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnItemsReceived(List<APIScoreInfo> items)
|
||||
protected override void OnItemsReceived(List<APIScore> items)
|
||||
{
|
||||
if (VisiblePages == 0)
|
||||
drawableItemIndex = 0;
|
||||
@ -59,12 +59,12 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
base.OnItemsReceived(items);
|
||||
}
|
||||
|
||||
protected override APIRequest<List<APIScoreInfo>> CreateRequest() =>
|
||||
protected override APIRequest<List<APIScore>> CreateRequest() =>
|
||||
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
||||
|
||||
private int drawableItemIndex;
|
||||
|
||||
protected override Drawable CreateDrawableItem(APIScoreInfo model)
|
||||
protected override Drawable CreateDrawableItem(APIScore model)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -4,14 +4,14 @@
|
||||
using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
public interface IScoreInfo : IHasOnlineID<long>, IHasNamedFiles
|
||||
{
|
||||
APIUser User { get; }
|
||||
IUser User { get; }
|
||||
|
||||
long TotalScore { get; }
|
||||
|
||||
|
@ -80,12 +80,9 @@ namespace osu.Game.Scoring.Legacy
|
||||
byte[] compressedReplay = sr.ReadByteArray();
|
||||
|
||||
if (version >= 20140721)
|
||||
scoreInfo.OnlineScoreID = sr.ReadInt64();
|
||||
scoreInfo.OnlineID = sr.ReadInt64();
|
||||
else if (version >= 20121008)
|
||||
scoreInfo.OnlineScoreID = sr.ReadInt32();
|
||||
|
||||
if (scoreInfo.OnlineScoreID <= 0)
|
||||
scoreInfo.OnlineScoreID = null;
|
||||
scoreInfo.OnlineID = sr.ReadInt32();
|
||||
|
||||
if (compressedReplay?.Length > 0)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Utils;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
@ -136,7 +137,14 @@ namespace osu.Game.Scoring
|
||||
[Column("Beatmap")]
|
||||
public BeatmapInfo BeatmapInfo { get; set; }
|
||||
|
||||
public long? OnlineScoreID { get; set; }
|
||||
private long? onlineID;
|
||||
|
||||
[Column("OnlineScoreID")]
|
||||
public long? OnlineID
|
||||
{
|
||||
get => onlineID;
|
||||
set => onlineID = value > 0 ? value : null;
|
||||
}
|
||||
|
||||
public DateTimeOffset Date { get; set; }
|
||||
|
||||
@ -231,24 +239,18 @@ namespace osu.Game.Scoring
|
||||
|
||||
public bool Equals(ScoreInfo other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (other == null) return false;
|
||||
|
||||
if (ID != 0 && other.ID != 0)
|
||||
return ID == other.ID;
|
||||
|
||||
if (OnlineScoreID.HasValue && other.OnlineScoreID.HasValue)
|
||||
return OnlineScoreID == other.OnlineScoreID;
|
||||
|
||||
if (!string.IsNullOrEmpty(Hash) && !string.IsNullOrEmpty(other.Hash))
|
||||
return Hash == other.Hash;
|
||||
|
||||
return ReferenceEquals(this, other);
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Implementation of IHasOnlineID
|
||||
|
||||
public long OnlineID => OnlineScoreID ?? -1;
|
||||
long IHasOnlineID<long>.OnlineID => OnlineID ?? -1;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -256,6 +258,7 @@ namespace osu.Game.Scoring
|
||||
|
||||
IBeatmapInfo IScoreInfo.Beatmap => BeatmapInfo;
|
||||
IRulesetInfo IScoreInfo.Ruleset => Ruleset;
|
||||
IUser IScoreInfo.User => User;
|
||||
bool IScoreInfo.HasReplay => Files.Any();
|
||||
|
||||
#endregion
|
||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Scoring
|
||||
|
||||
return scores.Select((score, index) => (score, totalScore: totalScores[index]))
|
||||
.OrderByDescending(g => g.totalScore)
|
||||
.ThenBy(g => g.score.OnlineScoreID)
|
||||
.ThenBy(g => g.score.OnlineID)
|
||||
.Select(g => g.score)
|
||||
.ToArray();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
|
||||
@ -17,6 +18,6 @@ namespace osu.Game.Scoring
|
||||
protected override ArchiveDownloadRequest<IScoreInfo> CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
||||
|
||||
public override ArchiveDownloadRequest<IScoreInfo> GetExistingDownload(IScoreInfo model)
|
||||
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
||||
=> CurrentDownloads.Find(r => r.Model.MatchesOnlineID(model));
|
||||
}
|
||||
}
|
||||
|
@ -66,6 +66,6 @@ namespace osu.Game.Scoring
|
||||
|
||||
protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable<ScoreInfo> items)
|
||||
=> base.CheckLocalAvailability(model, items)
|
||||
|| (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID));
|
||||
|| (model.OnlineID > 0 && items.Any(i => i.OnlineID == model.OnlineID));
|
||||
}
|
||||
}
|
||||
|
@ -48,16 +48,19 @@ namespace osu.Game.Screens.Backgrounds
|
||||
|
||||
AddInternal(seasonalBackgroundLoader);
|
||||
|
||||
user.ValueChanged += _ => Next();
|
||||
skin.ValueChanged += _ => Next();
|
||||
mode.ValueChanged += _ => Next();
|
||||
beatmap.ValueChanged += _ => Next();
|
||||
introSequence.ValueChanged += _ => Next();
|
||||
seasonalBackgroundLoader.SeasonalBackgroundChanged += () => Next();
|
||||
user.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
skin.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
mode.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
beatmap.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
introSequence.ValueChanged += _ => Scheduler.AddOnce(loadNextIfRequired);
|
||||
seasonalBackgroundLoader.SeasonalBackgroundChanged += () => Scheduler.AddOnce(loadNextIfRequired);
|
||||
|
||||
currentDisplay = RNG.Next(0, background_count);
|
||||
|
||||
Next();
|
||||
|
||||
// helper function required for AddOnce usage.
|
||||
void loadNextIfRequired() => Next();
|
||||
}
|
||||
|
||||
private ScheduledDelegate nextTask;
|
||||
@ -67,7 +70,7 @@ namespace osu.Game.Screens.Backgrounds
|
||||
/// Request loading the next background.
|
||||
/// </summary>
|
||||
/// <returns>Whether a new background was queued for load. May return false if the current background is still valid.</returns>
|
||||
public bool Next()
|
||||
public virtual bool Next()
|
||||
{
|
||||
var nextBackground = createBackground();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@ -9,6 +10,7 @@ using osu.Framework.Screens;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
@ -53,6 +55,14 @@ namespace osu.Game.Screens.Edit
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// will be restored via lease, see `DisallowExternalBeatmapRulesetChanges`.
|
||||
Mods.Value = Array.Empty<Mod>();
|
||||
}
|
||||
|
||||
protected virtual Editor CreateEditor() => new Editor(this);
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Development;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Online.API;
|
||||
@ -107,6 +108,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
|
||||
public void AddOrUpdateRoom(Room room)
|
||||
{
|
||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||
Debug.Assert(room.RoomID.Value != null);
|
||||
|
||||
if (ignoredRooms.Contains(room.RoomID.Value.Value))
|
||||
@ -136,12 +138,16 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
|
||||
public void RemoveRoom(Room room)
|
||||
{
|
||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||
|
||||
rooms.Remove(room);
|
||||
notifyRoomsUpdated();
|
||||
}
|
||||
|
||||
public void ClearRooms()
|
||||
{
|
||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||
|
||||
rooms.Clear();
|
||||
notifyRoomsUpdated();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -24,6 +25,7 @@ using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Rulesets;
|
||||
@ -90,6 +92,10 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
[Resolved]
|
||||
private UserLookupCache userLookupCache { get; set; }
|
||||
|
||||
[CanBeNull]
|
||||
[Resolved(CanBeNull = true)]
|
||||
private MultiplayerClient multiplayerClient { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private BeatmapLookupCache beatmapLookupCache { get; set; }
|
||||
|
||||
@ -157,7 +163,15 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
|
||||
if (Item.Beatmap.Value == null)
|
||||
{
|
||||
var foundBeatmap = await beatmapLookupCache.GetBeatmapAsync(Item.BeatmapID).ConfigureAwait(false);
|
||||
IBeatmapInfo foundBeatmap;
|
||||
|
||||
if (multiplayerClient != null)
|
||||
// This call can eventually go away (and use the else case below).
|
||||
// Currently required only due to the method being overridden to provide special behaviour in tests.
|
||||
foundBeatmap = await multiplayerClient.GetAPIBeatmap(Item.BeatmapID).ConfigureAwait(false);
|
||||
else
|
||||
foundBeatmap = await beatmapLookupCache.GetBeatmapAsync(Item.BeatmapID).ConfigureAwait(false);
|
||||
|
||||
Schedule(() => Item.Beatmap.Value = foundBeatmap);
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
public abstract class RoomSubScreen : OnlinePlaySubScreen, IPreviewTrackOwner
|
||||
{
|
||||
[Cached(typeof(IBindable<PlaylistItem>))]
|
||||
protected readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
|
||||
public readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
|
||||
|
||||
public override bool? AllowTrackAdjustments => true;
|
||||
|
||||
@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
protected OnlinePlayScreen ParentScreen { get; private set; }
|
||||
|
||||
[Cached]
|
||||
private OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker { get; set; }
|
||||
private readonly OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker();
|
||||
|
||||
protected IBindable<BeatmapAvailability> BeatmapAvailability => beatmapAvailabilityTracker.Availability;
|
||||
|
||||
@ -90,11 +90,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
|
||||
Padding = new MarginPadding { Top = Header.HEIGHT };
|
||||
|
||||
beatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker
|
||||
{
|
||||
SelectedItem = { BindTarget = SelectedItem }
|
||||
};
|
||||
|
||||
RoomId.BindTo(room.RoomID);
|
||||
}
|
||||
|
||||
@ -247,10 +242,10 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
}, true);
|
||||
|
||||
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
|
||||
|
||||
beatmapManager.ItemUpdated += beatmapUpdated;
|
||||
|
||||
UserMods.BindValueChanged(_ => Scheduler.AddOnce(UpdateMods));
|
||||
|
||||
beatmapAvailabilityTracker.SelectedItem.BindTo(SelectedItem);
|
||||
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => updateWorkingBeatmap());
|
||||
}
|
||||
|
||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||
@ -374,8 +369,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
}
|
||||
}
|
||||
|
||||
private void beatmapUpdated(BeatmapSetInfo set) => Schedule(updateWorkingBeatmap);
|
||||
|
||||
private void updateWorkingBeatmap()
|
||||
{
|
||||
var beatmap = SelectedItem.Value?.Beatmap.Value;
|
||||
@ -443,14 +436,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
/// <param name="room">The room to change the settings of.</param>
|
||||
protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room);
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
if (beatmapManager != null)
|
||||
beatmapManager.ItemUpdated -= beatmapUpdated;
|
||||
}
|
||||
|
||||
public class UserModSelectButton : PurpleTriangleButton
|
||||
{
|
||||
}
|
||||
|
@ -63,6 +63,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||
sampleUnready = audio.Samples.Get(@"Multiplayer/player-unready");
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
SelectedItem.BindValueChanged(_ => updateState());
|
||||
}
|
||||
|
||||
protected override void OnRoomUpdated()
|
||||
{
|
||||
base.OnRoomUpdated();
|
||||
@ -104,7 +111,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
|
||||
|
||||
bool enableButton =
|
||||
Room?.State == MultiplayerRoomState.Open
|
||||
&& Client.CurrentMatchPlayingItem.Value?.Expired == false
|
||||
&& SelectedItem.Value?.ID == Room.Settings.PlaylistItemId
|
||||
&& !Room.Playlist.Single(i => i.ID == Room.Settings.PlaylistItemId).Expired
|
||||
&& !operationInProgress.Value;
|
||||
|
||||
// When the local user is the host and spectating the match, the "start match" state should be enabled if any users are ready.
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
[Resolved]
|
||||
private MultiplayerClient client { get; set; }
|
||||
|
||||
private readonly PlaylistItem itemToEdit;
|
||||
private readonly long? itemToEdit;
|
||||
|
||||
private LoadingLayer loadingLayer;
|
||||
|
||||
@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
/// <param name="itemToEdit">The item to be edited. May be null, in which case a new item will be added to the playlist.</param>
|
||||
/// <param name="beatmap">An optional initial beatmap selection to perform.</param>
|
||||
/// <param name="ruleset">An optional initial ruleset selection to perform.</param>
|
||||
public MultiplayerMatchSongSelect(Room room, PlaylistItem itemToEdit = null, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null)
|
||||
public MultiplayerMatchSongSelect(Room room, long? itemToEdit = null, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null)
|
||||
: base(room)
|
||||
{
|
||||
this.itemToEdit = itemToEdit;
|
||||
@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
|
||||
var multiplayerItem = new MultiplayerPlaylistItem
|
||||
{
|
||||
ID = itemToEdit?.ID ?? 0,
|
||||
ID = itemToEdit ?? 0,
|
||||
BeatmapID = item.BeatmapID,
|
||||
BeatmapChecksum = item.Beatmap.Value.MD5Hash,
|
||||
RulesetID = item.RulesetID,
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
@ -67,8 +68,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
SelectedItem.BindTo(client.CurrentMatchPlayingItem);
|
||||
|
||||
BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true);
|
||||
UserMods.BindValueChanged(onUserModsChanged);
|
||||
|
||||
@ -147,7 +146,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
new MultiplayerPlaylist
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RequestEdit = OpenSongSelection
|
||||
RequestEdit = item => OpenSongSelection(item.ID)
|
||||
}
|
||||
},
|
||||
new[]
|
||||
@ -224,7 +223,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
/// Opens the song selection screen to add or edit an item.
|
||||
/// </summary>
|
||||
/// <param name="itemToEdit">An optional playlist item to edit. If null, a new item will be added instead.</param>
|
||||
internal void OpenSongSelection([CanBeNull] PlaylistItem itemToEdit = null)
|
||||
internal void OpenSongSelection(long? itemToEdit = null)
|
||||
{
|
||||
if (!this.IsCurrentScreen())
|
||||
return;
|
||||
@ -327,10 +326,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
if (client.LocalUser?.State == MultiplayerUserState.Ready)
|
||||
client.ChangeState(MultiplayerUserState.Idle);
|
||||
}
|
||||
else
|
||||
else if (client.LocalUser?.State == MultiplayerUserState.Spectating
|
||||
&& (client.Room?.State == MultiplayerRoomState.WaitingForLoad || client.Room?.State == MultiplayerRoomState.Playing))
|
||||
{
|
||||
if (client.LocalUser?.State == MultiplayerUserState.Spectating && (client.Room?.State == MultiplayerRoomState.WaitingForLoad || client.Room?.State == MultiplayerRoomState.Playing))
|
||||
onLoadRequested();
|
||||
onLoadRequested();
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,11 +388,50 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
return;
|
||||
}
|
||||
|
||||
updateCurrentItem();
|
||||
|
||||
addItemButton.Alpha = client.IsHost || Room.QueueMode.Value != QueueMode.HostOnly ? 1 : 0;
|
||||
|
||||
Scheduler.AddOnce(UpdateMods);
|
||||
}
|
||||
|
||||
private void updateCurrentItem()
|
||||
{
|
||||
Debug.Assert(client.Room != null);
|
||||
|
||||
var expectedSelectedItem = Room.Playlist.SingleOrDefault(i => i.ID == client.Room.Settings.PlaylistItemId);
|
||||
|
||||
if (expectedSelectedItem == null)
|
||||
return;
|
||||
|
||||
// There's no reason to renew the selected item if its content hasn't changed.
|
||||
if (SelectedItem.Value?.Equals(expectedSelectedItem) == true && expectedSelectedItem.Beatmap.Value != null)
|
||||
return;
|
||||
|
||||
// Clear the selected item while the lookup is performed, so components like the ready button can enter their disabled states.
|
||||
SelectedItem.Value = null;
|
||||
|
||||
if (expectedSelectedItem.Beatmap.Value == null)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var beatmap = await client.GetAPIBeatmap(expectedSelectedItem.BeatmapID).ConfigureAwait(false);
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
expectedSelectedItem.Beatmap.Value = beatmap;
|
||||
|
||||
if (Room.Playlist.SingleOrDefault(i => i.ID == client.Room?.Settings.PlaylistItemId)?.Equals(expectedSelectedItem) == true)
|
||||
applyCurrentItem();
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
applyCurrentItem();
|
||||
|
||||
void applyCurrentItem() => SelectedItem.Value = expectedSelectedItem;
|
||||
}
|
||||
|
||||
private void handleRoomLost() => Schedule(() =>
|
||||
{
|
||||
if (this.IsCurrentScreen())
|
||||
@ -446,6 +484,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
if (!this.IsCurrentScreen())
|
||||
return;
|
||||
|
||||
if (client.Room == null)
|
||||
return;
|
||||
|
||||
if (!client.IsHost)
|
||||
{
|
||||
// todo: should handle this when the request queue is implemented.
|
||||
@ -454,7 +495,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
return;
|
||||
}
|
||||
|
||||
this.Push(new MultiplayerMatchSongSelect(Room, SelectedItem.Value, beatmap, ruleset));
|
||||
this.Push(new MultiplayerMatchSongSelect(Room, client.Room.Settings.PlaylistItemId, beatmap, ruleset));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
|
@ -87,6 +87,13 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
{
|
||||
var allScores = new List<MultiplayerScore> { userScore };
|
||||
|
||||
// Other scores could have arrived between score submission and entering the results screen. Ensure the local player score position is up to date.
|
||||
if (Score != null)
|
||||
{
|
||||
Score.Position = userScore.Position;
|
||||
ScorePanelList.GetPanelForScore(Score).ScorePosition.Value = userScore.Position;
|
||||
}
|
||||
|
||||
if (userScore.ScoresAround?.Higher != null)
|
||||
{
|
||||
allScores.AddRange(userScore.ScoresAround.Higher.Scores);
|
||||
@ -186,12 +193,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
Schedule(() =>
|
||||
{
|
||||
// Prefer selecting the local user's score, or otherwise default to the first visible score.
|
||||
SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
|
||||
SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.OnlineID == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault();
|
||||
});
|
||||
}
|
||||
|
||||
// Invoke callback to add the scores. Exclude the user's current score which was added previously.
|
||||
callback.Invoke(scoreInfos.Where(s => s.OnlineScoreID != Score?.OnlineScoreID));
|
||||
callback.Invoke(scoreInfos.Where(s => s.OnlineID != Score?.OnlineID));
|
||||
|
||||
hideLoadingSpinners(pivot);
|
||||
}));
|
||||
|
@ -6,6 +6,7 @@ using osu.Framework.Bindables;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using ManagedBass.Fx;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Sample;
|
||||
@ -18,6 +19,7 @@ using osu.Framework.Utils;
|
||||
using osu.Game.Audio.Effects;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -58,6 +60,12 @@ namespace osu.Game.Screens.Play
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The player screen background, used to adjust appearance on failing.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public BackgroundScreen Background { private get; set; }
|
||||
|
||||
public FailAnimation(DrawableRuleset drawableRuleset)
|
||||
{
|
||||
this.drawableRuleset = drawableRuleset;
|
||||
@ -136,6 +144,9 @@ namespace osu.Game.Screens.Play
|
||||
Content.ScaleTo(0.85f, duration, Easing.OutQuart);
|
||||
Content.RotateTo(1, duration, Easing.OutQuart);
|
||||
Content.FadeColour(Color4.Gray, duration);
|
||||
|
||||
// Will be restored by `ApplyToBackground` logic in `SongSelect`.
|
||||
Background?.FadeColour(OsuColour.Gray(0.3f), 60);
|
||||
}
|
||||
|
||||
public void RemoveFilters(bool resetTrackFrequency = true)
|
||||
|
@ -921,6 +921,8 @@ namespace osu.Game.Screens.Play
|
||||
b.IsBreakTime.BindTo(breakTracker.IsBreakTime);
|
||||
|
||||
b.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground);
|
||||
|
||||
failAnimationLayer.Background = b;
|
||||
});
|
||||
|
||||
HUDOverlay.IsBreakTime.BindTo(breakTracker.IsBreakTime);
|
||||
@ -1031,13 +1033,13 @@ namespace osu.Game.Screens.Play
|
||||
//
|
||||
// Until we better define the server-side logic behind this, let's not store the online ID to avoid potential unique constraint
|
||||
// conflicts across various systems (ie. solo and multiplayer).
|
||||
long? onlineScoreId = score.ScoreInfo.OnlineScoreID;
|
||||
score.ScoreInfo.OnlineScoreID = null;
|
||||
long? onlineScoreId = score.ScoreInfo.OnlineID;
|
||||
score.ScoreInfo.OnlineID = -1;
|
||||
|
||||
await scoreManager.Import(score.ScoreInfo, replayReader).ConfigureAwait(false);
|
||||
|
||||
// ... And restore the online ID for other processes to handle correctly (e.g. de-duplication for the results screen).
|
||||
score.ScoreInfo.OnlineScoreID = onlineScoreId;
|
||||
score.ScoreInfo.OnlineID = onlineScoreId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private void userSentFrames(int userId, FrameDataBundle bundle)
|
||||
{
|
||||
if (userId != score.ScoreInfo.User.Id)
|
||||
if (userId != score.ScoreInfo.User.OnlineID)
|
||||
return;
|
||||
|
||||
if (!LoadedBeatmapSuccessfully)
|
||||
|
@ -156,7 +156,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
request.Success += s =>
|
||||
{
|
||||
score.ScoreInfo.OnlineScoreID = s.ID;
|
||||
score.ScoreInfo.OnlineID = s.ID;
|
||||
score.ScoreInfo.Position = s.Position;
|
||||
|
||||
scoreSubmissionSource.SetResult(true);
|
||||
|
@ -2,36 +2,42 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Contracted
|
||||
{
|
||||
public class ContractedPanelTopContent : CompositeDrawable
|
||||
{
|
||||
private readonly ScoreInfo score;
|
||||
public readonly Bindable<int?> ScorePosition = new Bindable<int?>();
|
||||
|
||||
public ContractedPanelTopContent(ScoreInfo score)
|
||||
private OsuSpriteText text;
|
||||
|
||||
public ContractedPanelTopContent()
|
||||
{
|
||||
this.score = score;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = new OsuSpriteText
|
||||
InternalChild = text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Y = 6,
|
||||
Text = score.Position != null ? $"#{score.Position}" : string.Empty,
|
||||
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold)
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
ScorePosition.BindValueChanged(pos => text.Text = pos.NewValue != null ? $"#{pos.NewValue}" : string.Empty, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
@ -78,6 +79,11 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
public event Action<PanelState> StateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the score in the rankings.
|
||||
/// </summary>
|
||||
public readonly Bindable<int?> ScorePosition = new Bindable<int?>();
|
||||
|
||||
/// <summary>
|
||||
/// An action to be invoked if this <see cref="ScorePanel"/> is clicked while in an expanded state.
|
||||
/// </summary>
|
||||
@ -103,6 +109,8 @@ namespace osu.Game.Screens.Ranking
|
||||
{
|
||||
Score = score;
|
||||
displayWithFlair = isNewLocalScore;
|
||||
|
||||
ScorePosition.Value = score.Position;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -211,8 +219,8 @@ namespace osu.Game.Screens.Ranking
|
||||
topLayerBackground.FadeColour(expanded_top_layer_colour, RESIZE_DURATION, Easing.OutQuint);
|
||||
middleLayerBackground.FadeColour(expanded_middle_layer_colour, RESIZE_DURATION, Easing.OutQuint);
|
||||
|
||||
topLayerContentContainer.Add(topLayerContent = new ExpandedPanelTopContent(Score.User).With(d => d.Alpha = 0));
|
||||
middleLayerContentContainer.Add(middleLayerContent = new ExpandedPanelMiddleContent(Score, displayWithFlair).With(d => d.Alpha = 0));
|
||||
topLayerContentContainer.Add(topLayerContent = new ExpandedPanelTopContent(Score.User) { Alpha = 0 });
|
||||
middleLayerContentContainer.Add(middleLayerContent = new ExpandedPanelMiddleContent(Score, displayWithFlair) { Alpha = 0 });
|
||||
|
||||
// only the first expanded display should happen with flair.
|
||||
displayWithFlair = false;
|
||||
@ -224,8 +232,13 @@ namespace osu.Game.Screens.Ranking
|
||||
topLayerBackground.FadeColour(contracted_top_layer_colour, RESIZE_DURATION, Easing.OutQuint);
|
||||
middleLayerBackground.FadeColour(contracted_middle_layer_colour, RESIZE_DURATION, Easing.OutQuint);
|
||||
|
||||
topLayerContentContainer.Add(topLayerContent = new ContractedPanelTopContent(Score).With(d => d.Alpha = 0));
|
||||
middleLayerContentContainer.Add(middleLayerContent = new ContractedPanelMiddleContent(Score).With(d => d.Alpha = 0));
|
||||
topLayerContentContainer.Add(topLayerContent = new ContractedPanelTopContent
|
||||
{
|
||||
ScorePosition = { BindTarget = ScorePosition },
|
||||
Alpha = 0
|
||||
});
|
||||
|
||||
middleLayerContentContainer.Add(middleLayerContent = new ContractedPanelMiddleContent(Score) { Alpha = 0 });
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -341,7 +341,7 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
private IEnumerable<ScorePanelTrackingContainer> applySorting(IEnumerable<Drawable> drawables) => drawables.OfType<ScorePanelTrackingContainer>()
|
||||
.OrderByDescending(GetLayoutPosition)
|
||||
.ThenBy(s => s.Panel.Score.OnlineScoreID);
|
||||
.ThenBy(s => s.Panel.Score.OnlineID);
|
||||
}
|
||||
|
||||
private class Scroll : OsuScrollContainer
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking
|
||||
return null;
|
||||
|
||||
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);
|
||||
getScoreRequest.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => s.OnlineID != Score.OnlineScoreID).Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value.BeatmapInfo)));
|
||||
getScoreRequest.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => s.OnlineID != Score.OnlineID).Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value.BeatmapInfo)));
|
||||
return getScoreRequest;
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,8 @@ namespace osu.Game.Storyboards
|
||||
|
||||
foreach (var l in loops)
|
||||
{
|
||||
if (!(l.EarliestDisplayedTime is double lEarliest))
|
||||
continue;
|
||||
|
||||
earliestStartTime = Math.Min(earliestStartTime, lEarliest);
|
||||
if (l.EarliestDisplayedTime is double loopEarliestDisplayTime)
|
||||
earliestStartTime = Math.Min(earliestStartTime, l.LoopStartTime + loopEarliestDisplayTime);
|
||||
}
|
||||
|
||||
if (earliestStartTime < double.MaxValue)
|
||||
|
@ -1,66 +0,0 @@
|
||||
// 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 System.Linq;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests
|
||||
{
|
||||
public class TestScoreInfo : ScoreInfo
|
||||
{
|
||||
public TestScoreInfo(RulesetInfo ruleset, bool excessMods = false)
|
||||
{
|
||||
User = new APIUser
|
||||
{
|
||||
Id = 2,
|
||||
Username = "peppy",
|
||||
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
|
||||
};
|
||||
|
||||
BeatmapInfo = new TestBeatmap(ruleset).BeatmapInfo;
|
||||
Ruleset = ruleset;
|
||||
RulesetID = ruleset.ID ?? 0;
|
||||
|
||||
Mods = excessMods
|
||||
? ruleset.CreateInstance().CreateAllMods().ToArray()
|
||||
: new Mod[] { new TestModHardRock(), new TestModDoubleTime() };
|
||||
|
||||
TotalScore = 2845370;
|
||||
Accuracy = 0.95;
|
||||
MaxCombo = 999;
|
||||
Rank = ScoreRank.S;
|
||||
Date = DateTimeOffset.Now;
|
||||
|
||||
Statistics[HitResult.Miss] = 1;
|
||||
Statistics[HitResult.Meh] = 50;
|
||||
Statistics[HitResult.Ok] = 100;
|
||||
Statistics[HitResult.Good] = 200;
|
||||
Statistics[HitResult.Great] = 300;
|
||||
Statistics[HitResult.Perfect] = 320;
|
||||
Statistics[HitResult.SmallTickHit] = 50;
|
||||
Statistics[HitResult.SmallTickMiss] = 25;
|
||||
Statistics[HitResult.LargeTickHit] = 100;
|
||||
Statistics[HitResult.LargeTickMiss] = 50;
|
||||
Statistics[HitResult.SmallBonus] = 10;
|
||||
Statistics[HitResult.SmallBonus] = 50;
|
||||
|
||||
Position = 1;
|
||||
}
|
||||
|
||||
private class TestModHardRock : ModHardRock
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
||||
private class TestModDoubleTime : ModDoubleTime
|
||||
{
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -376,7 +376,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
|
||||
public override Task RemovePlaylistItem(long playlistItemId) => RemoveUserPlaylistItem(api.LocalUser.Value.OnlineID, playlistItemId);
|
||||
|
||||
protected override Task<APIBeatmap> GetAPIBeatmap(int beatmapId, CancellationToken cancellationToken = default)
|
||||
public override Task<APIBeatmap> GetAPIBeatmap(int beatmapId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
IBeatmapSetInfo? set = roomManager.ServerSideRooms.SelectMany(r => r.Playlist)
|
||||
.FirstOrDefault(p => p.BeatmapID == beatmapId)?.Beatmap.Value.BeatmapSet
|
||||
|
@ -20,7 +20,7 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||
<PackageReference Include="DiffPlex" Version="1.7.0" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.38" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.39" />
|
||||
<PackageReference Include="Humanizer" Version="2.13.14" />
|
||||
<PackageReference Include="MessagePack" Version="2.3.85" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.11" />
|
||||
@ -31,15 +31,15 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.LocalisationAnalyser" Version="2021.725.0">
|
||||
<PackageReference Include="ppy.LocalisationAnalyser" Version="2021.1210.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="10.7.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.1207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.1210.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1203.0" />
|
||||
<PackageReference Include="Sentry" Version="3.11.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.30.0" />
|
||||
<PackageReference Include="Sentry" Version="3.12.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
<PackageReference Include="TagLibSharp" Version="2.2.0" />
|
||||
|
@ -60,7 +60,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.1210.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1203.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
@ -83,7 +83,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.1207.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2021.1210.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.30.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user