mirror of
https://github.com/ppy/osu.git
synced 2025-01-28 02:43:19 +08:00
Merge branch 'master' into aim-refactor-velocity
This commit is contained in:
commit
5ada167709
@ -14,8 +14,8 @@
|
||||
"jb"
|
||||
]
|
||||
},
|
||||
"smoogipoo.nvika": {
|
||||
"version": "1.0.3",
|
||||
"nvika": {
|
||||
"version": "2.2.0",
|
||||
"commands": [
|
||||
"nvika"
|
||||
]
|
||||
|
@ -52,7 +52,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.1026.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1103.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.1106.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. -->
|
||||
|
@ -86,20 +86,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = foregroundBuffer = new BufferedContainer
|
||||
InternalChild = foregroundBuffer = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
Blending = BlendingParameters.Additive,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box { RelativeSizeAxes = Axes.Both },
|
||||
subtractionBuffer = new BufferedContainer
|
||||
subtractionBuffer = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
// This is needed because we're blending with another object
|
||||
BackgroundColour = Color4.White.Opacity(0),
|
||||
CacheDrawnFrameBuffer = true,
|
||||
// The 'hole' is achieved by subtracting the result of this container with the parent
|
||||
Blending = new BlendingParameters { AlphaEquation = BlendingEquation.ReverseSubtract },
|
||||
Child = subtractionLayer = new CircularContainer
|
||||
|
@ -136,10 +136,9 @@ namespace osu.Game.Rulesets.Osu.Statistics
|
||||
}
|
||||
}
|
||||
},
|
||||
bufferedGrid = new BufferedContainer
|
||||
bufferedGrid = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CacheDrawnFrameBuffer = true,
|
||||
BackgroundColour = Color4Extensions.FromHex("#202624").Opacity(0),
|
||||
Child = pointGrid = new GridContainer
|
||||
{
|
||||
|
@ -673,6 +673,8 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244)));
|
||||
Assert.That(first.ControlPoints[1].Type, Is.EqualTo(null));
|
||||
|
||||
// ReSharper disable once HeuristicUnreachableCode
|
||||
// weird one, see https://youtrack.jetbrains.com/issue/RIDER-70159.
|
||||
Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3)));
|
||||
Assert.That(first.ControlPoints[2].Type, Is.EqualTo(PathType.Bezier));
|
||||
Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15)));
|
||||
|
@ -846,6 +846,42 @@ namespace osu.Game.Tests.Beatmaps.IO
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: needs to be pulled across to realm implementation when this file is nuked.
|
||||
[Test]
|
||||
public void TestSaveRemovesInvalidCharactersFromPath()
|
||||
{
|
||||
// unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportBeatmapTest)))
|
||||
{
|
||||
try
|
||||
{
|
||||
var osu = LoadOsuIntoHost(host);
|
||||
|
||||
var manager = osu.Dependencies.Get<BeatmapManager>();
|
||||
|
||||
var working = manager.CreateNew(new OsuRuleset().RulesetInfo, User.SYSTEM_USER);
|
||||
|
||||
var beatmap = working.Beatmap;
|
||||
|
||||
beatmap.BeatmapInfo.Version = "difficulty";
|
||||
beatmap.BeatmapInfo.Metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = "Artist/With\\Slashes",
|
||||
Title = "Title",
|
||||
AuthorString = "mapper",
|
||||
};
|
||||
|
||||
manager.Save(beatmap.BeatmapInfo, working.Beatmap);
|
||||
|
||||
Assert.AreEqual("Artist_With_Slashes - Title (mapper) [difficulty].osu", beatmap.BeatmapInfo.Path);
|
||||
}
|
||||
finally
|
||||
{
|
||||
host.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateNewEmptyBeatmap()
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
public void TestMissing()
|
||||
{
|
||||
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||
beatmap.Metadata.AudioFile = null;
|
||||
beatmap.Metadata.AudioFile = string.Empty;
|
||||
|
||||
var mock = new Mock<IWorkingBeatmap>();
|
||||
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
public void TestMissing()
|
||||
{
|
||||
// While this is a problem, it is out of scope for this check and is caught by a different one.
|
||||
beatmap.Metadata.BackgroundFile = null;
|
||||
beatmap.Metadata.BackgroundFile = string.Empty;
|
||||
var context = getContext(null, System.Array.Empty<byte>());
|
||||
|
||||
Assert.That(check.Run(context), Is.Empty);
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
[Test]
|
||||
public void TestBackgroundNotSet()
|
||||
{
|
||||
beatmap.Metadata.BackgroundFile = null;
|
||||
beatmap.Metadata.BackgroundFile = string.Empty;
|
||||
|
||||
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||
var issues = check.Run(context).ToList();
|
||||
|
@ -105,6 +105,9 @@ namespace osu.Game.Tests.Mods
|
||||
testMod.ResetSettingsToDefaults();
|
||||
|
||||
Assert.That(testMod.DrainRate.Value, Is.Null);
|
||||
|
||||
// ReSharper disable once HeuristicUnreachableCode
|
||||
// see https://youtrack.jetbrains.com/issue/RIDER-70159.
|
||||
Assert.That(testMod.OverallDifficulty.Value, Is.Null);
|
||||
|
||||
var applied = applyDifficulty(new BeatmapDifficulty
|
||||
|
@ -39,8 +39,8 @@ namespace osu.Game.Tests.NonVisual
|
||||
[Test]
|
||||
public void TestCheckNullID()
|
||||
{
|
||||
var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved };
|
||||
var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved };
|
||||
var ourInfo = new BeatmapSetInfo { Hash = "1" };
|
||||
var otherInfo = new BeatmapSetInfo { Hash = "2" };
|
||||
|
||||
Assert.AreNotEqual(ourInfo, otherInfo);
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
||||
public void TestCriteriaMatchingArtistWithNullUnicodeName(string artistName, bool filtered)
|
||||
{
|
||||
var exampleBeatmapInfo = getExampleBeatmap();
|
||||
exampleBeatmapInfo.Metadata.ArtistUnicode = null;
|
||||
exampleBeatmapInfo.Metadata.ArtistUnicode = string.Empty;
|
||||
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
|
@ -79,8 +79,17 @@ namespace osu.Game.Tests.NonVisual
|
||||
public List<HitObject> HitObjects;
|
||||
public override IEnumerable<HitObject> Objects => HitObjects;
|
||||
|
||||
public override event Action<JudgementResult> NewResult;
|
||||
public override event Action<JudgementResult> RevertResult;
|
||||
public override event Action<JudgementResult> NewResult
|
||||
{
|
||||
add => throw new InvalidOperationException();
|
||||
remove => throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override event Action<JudgementResult> RevertResult
|
||||
{
|
||||
add => throw new InvalidOperationException();
|
||||
remove => throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override Playfield Playfield { get; }
|
||||
public override Container Overlays { get; }
|
||||
@ -95,9 +104,6 @@ namespace osu.Game.Tests.NonVisual
|
||||
public TestDrawableRuleset()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
// won't compile without this.
|
||||
NewResult?.Invoke(null);
|
||||
RevertResult?.Invoke(null);
|
||||
}
|
||||
|
||||
public override void SetReplayScore(Score replayScore) => throw new NotImplementedException();
|
||||
|
@ -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 System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
@ -67,9 +68,11 @@ namespace osu.Game.Tests.Online
|
||||
var deserialised = JsonConvert.DeserializeObject<APIMod>(JsonConvert.SerializeObject(apiMod));
|
||||
var converted = (TestModTimeRamp)deserialised?.ToMod(new TestRuleset());
|
||||
|
||||
Assert.That(converted?.AdjustPitch.Value, Is.EqualTo(false));
|
||||
Assert.That(converted?.InitialRate.Value, Is.EqualTo(1.25));
|
||||
Assert.That(converted?.FinalRate.Value, Is.EqualTo(0.25));
|
||||
Assert.That(converted, Is.Not.Null);
|
||||
|
||||
Assert.That(converted.AdjustPitch.Value, Is.EqualTo(false));
|
||||
Assert.That(converted.InitialRate.Value, Is.EqualTo(1.25));
|
||||
Assert.That(converted.FinalRate.Value, Is.EqualTo(0.25));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -121,11 +124,11 @@ namespace osu.Game.Tests.Online
|
||||
new TestModDifficultyAdjust()
|
||||
};
|
||||
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new System.NotImplementedException();
|
||||
public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null) => throw new NotImplementedException();
|
||||
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
|
||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException();
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException();
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new NotImplementedException();
|
||||
|
||||
public override string Description { get; } = string.Empty;
|
||||
public override string ShortName { get; } = string.Empty;
|
||||
|
@ -168,19 +168,19 @@ namespace osu.Game.Tests.Online
|
||||
return new TestBeatmapModelManager(this, storage, contextFactory, rulesets, api, host);
|
||||
}
|
||||
|
||||
protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IBeatmapModelManager manager, IAPIProvider api, GameHost host)
|
||||
protected override BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> manager, IAPIProvider api, GameHost host)
|
||||
{
|
||||
return new TestBeatmapModelDownloader(manager, api, host);
|
||||
}
|
||||
|
||||
internal class TestBeatmapModelDownloader : BeatmapModelDownloader
|
||||
{
|
||||
public TestBeatmapModelDownloader(IBeatmapModelManager modelManager, IAPIProvider apiProvider, GameHost gameHost)
|
||||
: base(modelManager, apiProvider, gameHost)
|
||||
public TestBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> importer, IAPIProvider apiProvider, GameHost gameHost)
|
||||
: base(importer, apiProvider, gameHost)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize)
|
||||
protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize)
|
||||
=> new TestDownloadRequest(set);
|
||||
}
|
||||
|
||||
@ -202,12 +202,12 @@ namespace osu.Game.Tests.Online
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDownloadRequest : ArchiveDownloadRequest<BeatmapSetInfo>
|
||||
private class TestDownloadRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
|
||||
{
|
||||
public new void SetProgress(float progress) => base.SetProgress(progress);
|
||||
public new void TriggerSuccess(string filename) => base.TriggerSuccess(filename);
|
||||
|
||||
public TestDownloadRequest(BeatmapSetInfo model)
|
||||
public TestDownloadRequest(IBeatmapSetInfo model)
|
||||
: base(model)
|
||||
{
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
Beatmaps = new[]
|
||||
{
|
||||
new APIBeatmap
|
||||
{
|
||||
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = beatmaps,
|
||||
Beatmaps = beatmaps.ToArray(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
|
||||
{
|
||||
RulesetID = difficulty.rulesetId,
|
||||
StarRating = difficulty.stars
|
||||
}).ToList()
|
||||
}).ToArray()
|
||||
};
|
||||
|
||||
[Test]
|
||||
|
@ -5,7 +5,10 @@ using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
@ -29,6 +32,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
private ComposeBlueprintContainer blueprintContainer
|
||||
=> Editor.ChildrenOfType<ComposeBlueprintContainer>().First();
|
||||
|
||||
private ContextMenuContainer contextMenuContainer
|
||||
=> Editor.ChildrenOfType<ContextMenuContainer>().First();
|
||||
|
||||
private void moveMouseToObject(Func<HitObject> targetFunc)
|
||||
{
|
||||
AddStep("move mouse to object", () =>
|
||||
@ -42,6 +48,19 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelectAndShowContextMenu()
|
||||
{
|
||||
var addedObject = new HitCircle { StartTime = 100, Position = new Vector2(100, 100) };
|
||||
AddStep("add hitobject", () => EditorBeatmap.Add(addedObject));
|
||||
|
||||
moveMouseToObject(() => addedObject);
|
||||
AddStep("right click", () => InputManager.Click(MouseButton.Right));
|
||||
|
||||
AddUntilStep("hitobject selected", () => EditorBeatmap.SelectedHitObjects.Single() == addedObject);
|
||||
AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType<OsuContextMenu>().Single().State == MenuState.Open);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNudgeSelection()
|
||||
{
|
||||
|
@ -23,10 +23,10 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddStep("set metadata", () =>
|
||||
{
|
||||
editorBeatmap.Metadata.Artist = "Example Artist";
|
||||
editorBeatmap.Metadata.ArtistUnicode = null;
|
||||
editorBeatmap.Metadata.ArtistUnicode = string.Empty;
|
||||
|
||||
editorBeatmap.Metadata.Title = "Example Title";
|
||||
editorBeatmap.Metadata.TitleUnicode = null;
|
||||
editorBeatmap.Metadata.TitleUnicode = string.Empty;
|
||||
});
|
||||
|
||||
createSection();
|
||||
@ -44,10 +44,10 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddStep("set metadata", () =>
|
||||
{
|
||||
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
|
||||
editorBeatmap.Metadata.Artist = null;
|
||||
editorBeatmap.Metadata.Artist = string.Empty;
|
||||
|
||||
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
|
||||
editorBeatmap.Metadata.Title = null;
|
||||
editorBeatmap.Metadata.Title = string.Empty;
|
||||
});
|
||||
|
||||
createSection();
|
||||
@ -86,10 +86,10 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddStep("set metadata", () =>
|
||||
{
|
||||
editorBeatmap.Metadata.ArtistUnicode = "*なみりん";
|
||||
editorBeatmap.Metadata.Artist = null;
|
||||
editorBeatmap.Metadata.Artist = string.Empty;
|
||||
|
||||
editorBeatmap.Metadata.TitleUnicode = "コイシテイク・プラネット";
|
||||
editorBeatmap.Metadata.Title = null;
|
||||
editorBeatmap.Metadata.Title = string.Empty;
|
||||
});
|
||||
|
||||
createSection();
|
||||
|
@ -235,8 +235,17 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public override IEnumerable<HitObject> Objects => new[] { new HitCircle { HitWindows = HitWindows } };
|
||||
|
||||
public override event Action<JudgementResult> NewResult;
|
||||
public override event Action<JudgementResult> RevertResult;
|
||||
public override event Action<JudgementResult> NewResult
|
||||
{
|
||||
add => throw new InvalidOperationException();
|
||||
remove => throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override event Action<JudgementResult> RevertResult
|
||||
{
|
||||
add => throw new InvalidOperationException();
|
||||
remove => throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override Playfield Playfield { get; }
|
||||
public override Container Overlays { get; }
|
||||
@ -251,9 +260,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
public TestDrawableRuleset()
|
||||
: base(new OsuRuleset())
|
||||
{
|
||||
// won't compile without this.
|
||||
NewResult?.Invoke(null);
|
||||
RevertResult?.Invoke(null);
|
||||
}
|
||||
|
||||
public override void SetReplayScore(Score replayScore) => throw new NotImplementedException();
|
||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
ScoreInfo = { BeatmapInfo = gameplayState.Beatmap.BeatmapInfo }
|
||||
})
|
||||
{
|
||||
ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos)
|
||||
ScreenSpaceToGamefield = pos => recordingManager?.ToLocalSpace(pos) ?? Vector2.Zero,
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
ReplayInputHandler = new TestFramedReplayInputHandler(replay)
|
||||
{
|
||||
GamefieldToScreenSpace = pos => playbackManager.ToScreenSpace(pos),
|
||||
GamefieldToScreenSpace = pos => playbackManager?.ToScreenSpace(pos) ?? Vector2.Zero,
|
||||
},
|
||||
Child = new Container
|
||||
{
|
||||
|
@ -67,6 +67,36 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
}
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Multiplayer room" },
|
||||
Status = { Value = new RoomStatusOpen() },
|
||||
EndDate = { Value = DateTimeOffset.Now.AddDays(1) },
|
||||
Type = { Value = MatchType.HeadToHead },
|
||||
Playlist =
|
||||
{
|
||||
new PlaylistItem
|
||||
{
|
||||
Beatmap =
|
||||
{
|
||||
Value = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||
{
|
||||
BeatmapInfo =
|
||||
{
|
||||
StarDifficulty = 2.5,
|
||||
Metadata =
|
||||
{
|
||||
Artist = "very very very very very very very very very long artist",
|
||||
ArtistUnicode = "very very very very very very very very very long artist",
|
||||
Title = "very very very very very very very very very very very long title",
|
||||
TitleUnicode = "very very very very very very very very very very very long title",
|
||||
}
|
||||
}
|
||||
}.BeatmapInfo,
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
createLoungeRoom(new Room
|
||||
{
|
||||
Name = { Value = "Playlist room with multiple beatmaps" },
|
||||
Status = { Value = new RoomStatusPlaying() },
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -223,11 +224,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestDownloadButtonVisibleInitiallyWhenBeatmapDoesNotExist()
|
||||
{
|
||||
var byOnlineId = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
||||
byOnlineId.BeatmapSet.OnlineBeatmapSetID = 1337; // Some random ID that does not exist locally.
|
||||
var byOnlineId = CreateAPIBeatmap();
|
||||
byOnlineId.OnlineID = 1337; // Some random ID that does not exist locally.
|
||||
|
||||
var byChecksum = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
||||
byChecksum.MD5Hash = "1337"; // Some random checksum that does not exist locally.
|
||||
var byChecksum = CreateAPIBeatmap();
|
||||
byChecksum.Checksum = "1337"; // Some random checksum that does not exist locally.
|
||||
|
||||
createPlaylist(byOnlineId, byChecksum);
|
||||
|
||||
@ -237,8 +238,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
[Test]
|
||||
public void TestExplicitBeatmapItem()
|
||||
{
|
||||
var beatmap = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo;
|
||||
beatmap.BeatmapSet.OnlineInfo.HasExplicitContent = true;
|
||||
var beatmap = CreateAPIBeatmap();
|
||||
|
||||
Debug.Assert(beatmap.BeatmapSet != null);
|
||||
|
||||
beatmap.BeatmapSet.HasExplicitContent = true;
|
||||
|
||||
createPlaylist(beatmap);
|
||||
}
|
||||
@ -310,7 +314,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
|
||||
}
|
||||
|
||||
private void createPlaylist(params BeatmapInfo[] beatmaps)
|
||||
private void createPlaylist(params IBeatmapInfo[] beatmaps)
|
||||
{
|
||||
AddStep("create playlist", () =>
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -37,7 +36,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
selector.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToList()
|
||||
Beatmaps = enabledRulesets.Select(r => new APIBeatmap { RulesetID = r.OnlineID }).ToArray()
|
||||
};
|
||||
});
|
||||
|
||||
@ -55,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
selector.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
Beatmaps = new[]
|
||||
{
|
||||
new APIBeatmap
|
||||
{
|
||||
@ -71,10 +70,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Test]
|
||||
public void TestEmptyBeatmapSet()
|
||||
{
|
||||
AddStep("load empty beatmapset", () => selector.BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = new List<APIBeatmap>()
|
||||
});
|
||||
AddStep("load empty beatmapset", () => selector.BeatmapSet = new APIBeatmapSet());
|
||||
|
||||
AddAssert("no ruleset selected", () => selector.SelectedTab == null);
|
||||
AddAssert("all rulesets disabled", () => selector.TabContainer.TabItems.All(t => !t.Enabled.Value));
|
||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
Beatmaps = new[]
|
||||
{
|
||||
new APIBeatmap
|
||||
{
|
||||
@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
var set = getBeatmapSet();
|
||||
|
||||
set.Beatmaps = beatmaps;
|
||||
set.Beatmaps = beatmaps.ToArray();
|
||||
|
||||
overlay.ShowBeatmapSet(set);
|
||||
});
|
||||
@ -211,7 +211,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
});
|
||||
}
|
||||
|
||||
set.Beatmaps = beatmaps;
|
||||
set.Beatmaps = beatmaps.ToArray();
|
||||
|
||||
return set;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -46,7 +45,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
static APIBeatmapSet createSet() => new APIBeatmapSet
|
||||
{
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
Beatmaps = new[]
|
||||
{
|
||||
new APIBeatmap
|
||||
{
|
||||
|
@ -9,7 +9,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Online;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Tests.Resources;
|
||||
using osuTK;
|
||||
|
||||
@ -110,7 +109,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private IBeatmapSetInfo getDownloadableBeatmapSet()
|
||||
{
|
||||
var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo;
|
||||
var apiBeatmapSet = CreateAPIBeatmapSet();
|
||||
|
||||
apiBeatmapSet.HasVideo = true;
|
||||
apiBeatmapSet.HasStoryboard = true;
|
||||
@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private IBeatmapSetInfo getUndownloadableBeatmapSet()
|
||||
{
|
||||
var apiBeatmapSet = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo).BeatmapSetInfo.OnlineInfo;
|
||||
var apiBeatmapSet = CreateAPIBeatmapSet();
|
||||
|
||||
apiBeatmapSet.Artist = "test";
|
||||
apiBeatmapSet.Title = "undownloadable";
|
||||
|
@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = new List<APIBeatmap>
|
||||
Beatmaps = new[]
|
||||
{
|
||||
new APIBeatmap
|
||||
{
|
||||
@ -129,7 +129,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
HasVideo = true,
|
||||
HasStoryboard = true,
|
||||
Covers = new BeatmapSetOnlineCovers(),
|
||||
Beatmaps = beatmaps,
|
||||
Beatmaps = beatmaps.ToArray(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.SongSelect
|
||||
@ -32,159 +31,112 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
[Test]
|
||||
public void TestAllMetrics()
|
||||
{
|
||||
AddStep("all metrics", () => details.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("all metrics", () => details.BeatmapInfo = new APIBeatmap
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
}
|
||||
},
|
||||
Version = "All Metrics",
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Source = "osu!",
|
||||
Tags = "this beatmap has all the metrics",
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
DifficultyName = "All Metrics",
|
||||
CircleSize = 7,
|
||||
DrainRate = 1,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f,
|
||||
StarRating = 5.3f,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
CircleSize = 7,
|
||||
DrainRate = 1,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f,
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
StarDifficulty = 5.3f,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAllMetricsExceptSource()
|
||||
{
|
||||
AddStep("all except source", () => details.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("all except source", () => details.BeatmapInfo = new APIBeatmap
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
}
|
||||
},
|
||||
Version = "All Metrics",
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Tags = "this beatmap has all the metrics",
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
DifficultyName = "All Metrics",
|
||||
CircleSize = 7,
|
||||
DrainRate = 1,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f,
|
||||
StarRating = 5.3f,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
CircleSize = 7,
|
||||
DrainRate = 1,
|
||||
OverallDifficulty = 5.7f,
|
||||
ApproachRate = 3.5f,
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
StarDifficulty = 5.3f,
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnlyRatings()
|
||||
{
|
||||
AddStep("ratings", () => details.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("ratings", () => details.BeatmapInfo = new APIBeatmap
|
||||
{
|
||||
BeatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
}
|
||||
},
|
||||
Version = "Only Ratings",
|
||||
Metadata = new BeatmapMetadata
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Ratings = Enumerable.Range(0, 11).ToArray(),
|
||||
Source = "osu!",
|
||||
Tags = "this beatmap has ratings metrics but not retries or fails",
|
||||
},
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 6,
|
||||
DrainRate = 9,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 6,
|
||||
},
|
||||
StarDifficulty = 4.8f,
|
||||
DifficultyName = "Only Ratings",
|
||||
CircleSize = 6,
|
||||
DrainRate = 9,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 6,
|
||||
StarRating = 4.8f,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnlyFailsAndRetries()
|
||||
{
|
||||
AddStep("fails retries", () => details.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("fails retries", () => details.BeatmapInfo = new APIBeatmap
|
||||
{
|
||||
Version = "Only Retries and Fails",
|
||||
Metadata = new BeatmapMetadata
|
||||
DifficultyName = "Only Retries and Fails",
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Source = "osu!",
|
||||
Tags = "this beatmap has retries and fails but no ratings",
|
||||
},
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
CircleSize = 3.7f,
|
||||
DrainRate = 6,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 7,
|
||||
StarRating = 2.91f,
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
CircleSize = 3.7f,
|
||||
DrainRate = 6,
|
||||
OverallDifficulty = 6,
|
||||
ApproachRate = 7,
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
StarDifficulty = 2.91f,
|
||||
OnlineInfo = new APIBeatmap
|
||||
{
|
||||
FailTimes = new APIFailTimes
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoMetrics()
|
||||
{
|
||||
AddStep("no metrics", () => details.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("no metrics", () => details.BeatmapInfo = new APIBeatmap
|
||||
{
|
||||
Version = "No Metrics",
|
||||
Metadata = new BeatmapMetadata
|
||||
DifficultyName = "No Metrics",
|
||||
BeatmapSet = new APIBeatmapSet
|
||||
{
|
||||
Source = "osu!",
|
||||
Tags = "this beatmap has no metrics",
|
||||
},
|
||||
Ruleset = new OsuRuleset().RulesetInfo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 5,
|
||||
DrainRate = 5,
|
||||
OverallDifficulty = 5.5f,
|
||||
ApproachRate = 6.5f,
|
||||
},
|
||||
StarDifficulty = 1.97f,
|
||||
CircleSize = 5,
|
||||
DrainRate = 5,
|
||||
OverallDifficulty = 5.5f,
|
||||
ApproachRate = 6.5f,
|
||||
StarRating = 1.97f,
|
||||
});
|
||||
}
|
||||
|
||||
@ -197,10 +149,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
[Test]
|
||||
public void TestOnlineMetrics()
|
||||
{
|
||||
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new BeatmapInfo
|
||||
AddStep("online ratings/retries/fails", () => details.BeatmapInfo = new APIBeatmap
|
||||
{
|
||||
OnlineBeatmapID = 162,
|
||||
Ruleset = new OsuRuleset().RulesetInfo
|
||||
OnlineID = 162,
|
||||
});
|
||||
AddStep("set online", () => api.SetState(APIState.Online));
|
||||
AddStep("set offline", () => api.SetState(APIState.Offline));
|
||||
|
@ -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.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -65,10 +66,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
private void createPaddedComponent(bool hasDescription = false, bool padded = true)
|
||||
{
|
||||
LabelledDrawable<Drawable> component = null;
|
||||
|
||||
AddStep("create component", () =>
|
||||
{
|
||||
LabelledDrawable<Drawable> component;
|
||||
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@ -81,6 +82,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
component.Label = "a sample component";
|
||||
component.Description = hasDescription ? "this text describes the component" : string.Empty;
|
||||
});
|
||||
|
||||
AddAssert($"description {(hasDescription ? "visible" : "hidden")}", () => component.ChildrenOfType<TextFlowContainer>().ElementAt(1).IsPresent == hasDescription);
|
||||
}
|
||||
|
||||
private class PaddedLabelledDrawable : LabelledDrawable<Drawable>
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
AddStep("setup cover", () => Child = new UpdateableOnlineBeatmapSetCover(coverType)
|
||||
{
|
||||
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
|
||||
OnlineInfo = CreateAPIBeatmapSet(),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
});
|
||||
@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("setup covers", () =>
|
||||
{
|
||||
BeatmapSetInfo setInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet;
|
||||
var beatmapSet = CreateAPIBeatmapSet();
|
||||
|
||||
FillFlowContainer fillFlow;
|
||||
|
||||
@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
var cover = new UpdateableOnlineBeatmapSetCover(coverType)
|
||||
{
|
||||
OnlineInfo = setInfo.OnlineInfo,
|
||||
OnlineInfo = beatmapSet,
|
||||
Height = 100,
|
||||
Masking = true,
|
||||
};
|
||||
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover
|
||||
{
|
||||
OnlineInfo = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet.OnlineInfo,
|
||||
OnlineInfo = CreateAPIBeatmapSet(),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
});
|
||||
@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("setup cover", () => Child = updateableCover = new TestUpdateableOnlineBeatmapSetCover(0)
|
||||
{
|
||||
OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg").OnlineInfo,
|
||||
OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1189904/covers/cover.jpg"),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Alpha = 0.4f
|
||||
@ -128,16 +128,13 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("wait for fade complete", () => initialCover.Alpha == 1);
|
||||
|
||||
AddStep("switch beatmap",
|
||||
() => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg").OnlineInfo);
|
||||
() => updateableCover.OnlineInfo = createBeatmapWithCover("https://assets.ppy.sh/beatmaps/1079428/covers/cover.jpg"));
|
||||
AddUntilStep("new cover loaded", () => updateableCover.ChildrenOfType<OnlineBeatmapSetCover>().Except(new[] { initialCover }).Any());
|
||||
}
|
||||
|
||||
private static BeatmapSetInfo createBeatmapWithCover(string coverUrl) => new BeatmapSetInfo
|
||||
private static APIBeatmapSet createBeatmapWithCover(string coverUrl) => new APIBeatmapSet
|
||||
{
|
||||
OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Covers = new BeatmapSetOnlineCovers { Cover = coverUrl }
|
||||
}
|
||||
Covers = new BeatmapSetOnlineCovers { Cover = coverUrl }
|
||||
};
|
||||
|
||||
private class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover
|
||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
[ExcludeFromDynamicCompile]
|
||||
[Serializable]
|
||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IHasPrimaryKey, IBeatmapInfo, IBeatmapOnlineInfo
|
||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IHasPrimaryKey, IBeatmapInfo
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
@ -186,7 +186,7 @@ namespace osu.Game.Beatmaps
|
||||
string IBeatmapInfo.DifficultyName => Version;
|
||||
|
||||
[JsonIgnore]
|
||||
IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata;
|
||||
IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata ?? BeatmapSet?.Metadata ?? new BeatmapMetadata();
|
||||
|
||||
[JsonIgnore]
|
||||
IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => BaseDifficulty;
|
||||
@ -201,24 +201,5 @@ namespace osu.Game.Beatmaps
|
||||
double IBeatmapInfo.StarRating => StarDifficulty;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IBeatmapOnlineInfo
|
||||
|
||||
[JsonIgnore]
|
||||
public int CircleCount => OnlineInfo.CircleCount;
|
||||
|
||||
[JsonIgnore]
|
||||
public int SliderCount => OnlineInfo.SliderCount;
|
||||
|
||||
[JsonIgnore]
|
||||
public int PlayCount => OnlineInfo.PlayCount;
|
||||
|
||||
[JsonIgnore]
|
||||
public int PassCount => OnlineInfo.PassCount;
|
||||
|
||||
[JsonIgnore]
|
||||
public APIFailTimes FailTimes => OnlineInfo.FailTimes;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -11,14 +11,14 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// A user-presentable display title representing this beatmap.
|
||||
/// </summary>
|
||||
public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo) => $"{getClosestMetadata(beatmapInfo)} {getVersionString(beatmapInfo)}".Trim();
|
||||
public static string GetDisplayTitle(this IBeatmapInfo beatmapInfo) => $"{beatmapInfo.Metadata} {getVersionString(beatmapInfo)}".Trim();
|
||||
|
||||
/// <summary>
|
||||
/// A user-presentable display title representing this beatmap, with localisation handling for potentially romanisable fields.
|
||||
/// </summary>
|
||||
public static RomanisableString GetDisplayTitleRomanisable(this IBeatmapInfo beatmapInfo, bool includeDifficultyName = true, bool includeCreator = true)
|
||||
{
|
||||
var metadata = getClosestMetadata(beatmapInfo).GetDisplayTitleRomanisable(includeCreator);
|
||||
var metadata = beatmapInfo.Metadata.GetDisplayTitleRomanisable(includeCreator);
|
||||
|
||||
if (includeDifficultyName)
|
||||
{
|
||||
@ -32,12 +32,8 @@ namespace osu.Game.Beatmaps
|
||||
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
|
||||
{
|
||||
beatmapInfo.DifficultyName
|
||||
}.Concat(getClosestMetadata(beatmapInfo).GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
}.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||||
|
||||
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
||||
|
||||
// temporary helper methods until we figure which metadata should be where.
|
||||
private static IBeatmapMetadataInfo getClosestMetadata(IBeatmapInfo beatmapInfo) =>
|
||||
beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet?.Metadata ?? new BeatmapMetadata();
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps
|
||||
/// Handles general operations related to global beatmap management.
|
||||
/// </summary>
|
||||
[ExcludeFromDynamicCompile]
|
||||
public class BeatmapManager : IModelDownloader<BeatmapSetInfo>, IModelManager<BeatmapSetInfo>, IModelFileManager<BeatmapSetInfo, BeatmapSetFileInfo>, IWorkingBeatmapCache, IDisposable
|
||||
public class BeatmapManager : IModelDownloader<IBeatmapSetInfo>, IModelManager<BeatmapSetInfo>, IModelFileManager<BeatmapSetInfo, BeatmapSetFileInfo>, IModelImporter<BeatmapSetInfo>, IWorkingBeatmapCache, IDisposable
|
||||
{
|
||||
private readonly BeatmapModelManager beatmapModelManager;
|
||||
private readonly BeatmapModelDownloader beatmapModelDownloader;
|
||||
@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual BeatmapModelDownloader CreateBeatmapModelDownloader(IBeatmapModelManager modelManager, IAPIProvider api, GameHost host)
|
||||
protected virtual BeatmapModelDownloader CreateBeatmapModelDownloader(IModelImporter<BeatmapSetInfo> modelManager, IAPIProvider api, GameHost host)
|
||||
{
|
||||
return new BeatmapModelDownloader(modelManager, api, host);
|
||||
}
|
||||
@ -114,7 +114,8 @@ namespace osu.Game.Beatmaps
|
||||
/// <param name="info">The <see cref="BeatmapInfo"/> to save the content against. The file referenced by <see cref="BeatmapInfo.Path"/> will be replaced.</param>
|
||||
/// <param name="beatmapContent">The <see cref="IBeatmap"/> content to write.</param>
|
||||
/// <param name="beatmapSkin">The beatmap <see cref="ISkin"/> content to write, null if to be omitted.</param>
|
||||
public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) => beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
|
||||
public virtual void Save(BeatmapInfo info, IBeatmap beatmapContent, ISkin beatmapSkin = null) =>
|
||||
beatmapModelManager.Save(info, beatmapContent, beatmapSkin);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
||||
@ -245,33 +246,16 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
#region Implementation of IModelDownloader<BeatmapSetInfo>
|
||||
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadBegan => beatmapModelDownloader.DownloadBegan;
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> DownloadBegan => beatmapModelDownloader.DownloadBegan;
|
||||
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> DownloadFailed => beatmapModelDownloader.DownloadFailed;
|
||||
|
||||
// Temporary method until this class supports IBeatmapSetInfo or otherwise.
|
||||
public bool Download(IBeatmapSetInfo model, bool minimiseDownloadSize = false)
|
||||
{
|
||||
return beatmapModelDownloader.Download(new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = model.OnlineID,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = model.Metadata?.Title,
|
||||
Artist = model.Metadata?.Artist,
|
||||
TitleUnicode = model.Metadata?.TitleUnicode,
|
||||
ArtistUnicode = model.Metadata?.ArtistUnicode,
|
||||
Author = new User { Username = model.Metadata?.Author },
|
||||
}
|
||||
}, minimiseDownloadSize);
|
||||
}
|
||||
|
||||
public bool Download(BeatmapSetInfo model, bool minimiseDownloadSize = false)
|
||||
{
|
||||
return beatmapModelDownloader.Download(model, minimiseDownloadSize);
|
||||
}
|
||||
|
||||
public ArchiveDownloadRequest<BeatmapSetInfo> GetExistingDownload(BeatmapSetInfo model)
|
||||
public ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model)
|
||||
{
|
||||
return beatmapModelDownloader.GetExistingDownload(model);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Users;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
[ExcludeFromDynamicCompile]
|
||||
@ -17,21 +19,21 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("title_unicode")]
|
||||
public string TitleUnicode { get; set; }
|
||||
public string TitleUnicode { get; set; } = string.Empty;
|
||||
|
||||
public string Artist { get; set; }
|
||||
public string Artist { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("artist_unicode")]
|
||||
public string ArtistUnicode { get; set; }
|
||||
public string ArtistUnicode { get; set; } = string.Empty;
|
||||
|
||||
[JsonIgnore]
|
||||
public List<BeatmapInfo> Beatmaps { get; set; }
|
||||
public List<BeatmapInfo> Beatmaps { get; set; } = new List<BeatmapInfo>();
|
||||
|
||||
[JsonIgnore]
|
||||
public List<BeatmapSetInfo> BeatmapSets { get; set; }
|
||||
public List<BeatmapSetInfo> BeatmapSets { get; set; } = new List<BeatmapSetInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Helper property to deserialize a username to <see cref="User"/>.
|
||||
@ -55,7 +57,7 @@ namespace osu.Game.Beatmaps
|
||||
[Column("Author")]
|
||||
public string AuthorString
|
||||
{
|
||||
get => Author?.Username;
|
||||
get => Author?.Username ?? string.Empty;
|
||||
set
|
||||
{
|
||||
Author ??= new User();
|
||||
@ -67,22 +69,22 @@ namespace osu.Game.Beatmaps
|
||||
/// The author of the beatmaps in this set.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public User Author;
|
||||
public User? Author;
|
||||
|
||||
public string Source { get; set; }
|
||||
public string Source { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty(@"tags")]
|
||||
public string Tags { get; set; }
|
||||
public string Tags { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The time in milliseconds to begin playing the track for preview purposes.
|
||||
/// If -1, the track should begin playing at 40% of its length.
|
||||
/// </summary>
|
||||
public int PreviewTime { get; set; }
|
||||
public int PreviewTime { get; set; } = -1;
|
||||
|
||||
public string AudioFile { get; set; }
|
||||
public string AudioFile { get; set; } = string.Empty;
|
||||
|
||||
public string BackgroundFile { get; set; }
|
||||
public string BackgroundFile { get; set; } = string.Empty;
|
||||
|
||||
public bool Equals(BeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other);
|
||||
|
||||
|
@ -8,16 +8,16 @@ using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapModelDownloader : ModelDownloader<BeatmapSetInfo>
|
||||
public class BeatmapModelDownloader : ModelDownloader<BeatmapSetInfo, IBeatmapSetInfo>
|
||||
{
|
||||
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
|
||||
protected override ArchiveDownloadRequest<IBeatmapSetInfo> CreateDownloadRequest(IBeatmapSetInfo set, bool minimiseDownloadSize) =>
|
||||
new DownloadBeatmapSetRequest(set, minimiseDownloadSize);
|
||||
|
||||
public override ArchiveDownloadRequest<BeatmapSetInfo> GetExistingDownload(BeatmapSetInfo model)
|
||||
public override ArchiveDownloadRequest<IBeatmapSetInfo> GetExistingDownload(IBeatmapSetInfo model)
|
||||
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
||||
|
||||
public BeatmapModelDownloader(IBeatmapModelManager beatmapModelManager, IAPIProvider api, GameHost host = null)
|
||||
: base(beatmapModelManager, api, host)
|
||||
public BeatmapModelDownloader(IModelImporter<BeatmapSetInfo> beatmapImporter, IAPIProvider api, GameHost host = null)
|
||||
: base(beatmapImporter, api, host)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,8 @@ namespace osu.Game.Beatmaps
|
||||
var fileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)) ?? new BeatmapSetFileInfo();
|
||||
|
||||
// metadata may have changed; update the path with the standard format.
|
||||
beatmapInfo.Path = $"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu";
|
||||
beatmapInfo.Path = GetValidFilename($"{metadata.Artist} - {metadata.Title} ({metadata.Author}) [{beatmapInfo.Version}].osu");
|
||||
|
||||
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
||||
|
||||
// update existing or populate new file's filename.
|
||||
|
@ -6,10 +6,8 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@ -32,13 +30,11 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
public List<BeatmapInfo> Beatmaps { get; set; }
|
||||
|
||||
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
|
||||
|
||||
[NotNull]
|
||||
public List<BeatmapSetFileInfo> Files { get; set; } = new List<BeatmapSetFileInfo>();
|
||||
|
||||
// This field is temporary and only used by `APIBeatmapSet.ToBeatmapSet` (soon to be removed) and tests (to be updated to provide APIBeatmapSet instead).
|
||||
[NotMapped]
|
||||
public APIBeatmapSet OnlineInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum star difficulty of all beatmaps in this set.
|
||||
/// </summary>
|
||||
@ -100,80 +96,5 @@ namespace osu.Game.Beatmaps
|
||||
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => Files;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Delegation for IBeatmapSetOnlineInfo
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public DateTimeOffset Submitted => OnlineInfo.Submitted;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public DateTimeOffset? Ranked => OnlineInfo.Ranked;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public DateTimeOffset? LastUpdated => OnlineInfo.LastUpdated;
|
||||
|
||||
[JsonIgnore]
|
||||
public BeatmapSetOnlineStatus Status { get; set; } = BeatmapSetOnlineStatus.None;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public bool HasExplicitContent => OnlineInfo.HasExplicitContent;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public bool HasVideo => OnlineInfo.HasVideo;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public bool HasStoryboard => OnlineInfo.HasStoryboard;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public BeatmapSetOnlineCovers Covers => OnlineInfo.Covers;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public string Preview => OnlineInfo.Preview;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public double BPM => OnlineInfo.BPM;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public int PlayCount => OnlineInfo.PlayCount;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public int FavouriteCount => OnlineInfo.FavouriteCount;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public bool HasFavourited => OnlineInfo.HasFavourited;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public BeatmapSetOnlineAvailability Availability => OnlineInfo.Availability;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public BeatmapSetOnlineGenre Genre => OnlineInfo.Genre;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public BeatmapSetOnlineLanguage Language => OnlineInfo.Language;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public int? TrackId => OnlineInfo?.TrackId;
|
||||
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public int[] Ratings => OnlineInfo?.Ratings;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -57,12 +57,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
return new OnlineBeatmapSetCover(online, beatmapSetCoverType);
|
||||
|
||||
if (model is BeatmapInfo localModel)
|
||||
{
|
||||
if (localModel.BeatmapSet?.OnlineInfo != null)
|
||||
return new OnlineBeatmapSetCover(localModel.BeatmapSet.OnlineInfo, beatmapSetCoverType);
|
||||
|
||||
return new BeatmapBackgroundSprite(beatmaps.GetWorkingBeatmap(localModel));
|
||||
}
|
||||
|
||||
return new BeatmapBackgroundSprite(beatmaps.DefaultBeatmap);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
writer.WriteLine("[General]");
|
||||
|
||||
if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
|
||||
if (!string.IsNullOrEmpty(beatmap.Metadata.AudioFile)) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
|
||||
@ -126,13 +126,13 @@ namespace osu.Game.Beatmaps.Formats
|
||||
writer.WriteLine("[Metadata]");
|
||||
|
||||
writer.WriteLine(FormattableString.Invariant($"Title: {beatmap.Metadata.Title}"));
|
||||
if (beatmap.Metadata.TitleUnicode != null) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
|
||||
if (!string.IsNullOrEmpty(beatmap.Metadata.TitleUnicode)) writer.WriteLine(FormattableString.Invariant($"TitleUnicode: {beatmap.Metadata.TitleUnicode}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"Artist: {beatmap.Metadata.Artist}"));
|
||||
if (beatmap.Metadata.ArtistUnicode != null) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
|
||||
if (!string.IsNullOrEmpty(beatmap.Metadata.ArtistUnicode)) writer.WriteLine(FormattableString.Invariant($"ArtistUnicode: {beatmap.Metadata.ArtistUnicode}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"Creator: {beatmap.Metadata.AuthorString}"));
|
||||
writer.WriteLine(FormattableString.Invariant($"Version: {beatmap.BeatmapInfo.Version}"));
|
||||
if (beatmap.Metadata.Source != null) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
|
||||
if (beatmap.Metadata.Tags != null) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
|
||||
if (!string.IsNullOrEmpty(beatmap.Metadata.Source)) writer.WriteLine(FormattableString.Invariant($"Source: {beatmap.Metadata.Source}"));
|
||||
if (!string.IsNullOrEmpty(beatmap.Metadata.Tags)) writer.WriteLine(FormattableString.Invariant($"Tags: {beatmap.Metadata.Tags}"));
|
||||
if (beatmap.BeatmapInfo.OnlineBeatmapID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapID: {beatmap.BeatmapInfo.OnlineBeatmapID}"));
|
||||
if (beatmap.BeatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null) writer.WriteLine(FormattableString.Invariant($"BeatmapSetID: {beatmap.BeatmapInfo.BeatmapSet.OnlineBeatmapSetID}"));
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// The metadata representing this beatmap. May be shared between multiple beatmaps.
|
||||
/// </summary>
|
||||
IBeatmapMetadataInfo? Metadata { get; }
|
||||
IBeatmapMetadataInfo Metadata { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The difficulty settings for this beatmap.
|
||||
|
@ -149,7 +149,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected override Texture GetBackground()
|
||||
{
|
||||
if (Metadata?.BackgroundFile == null)
|
||||
if (string.IsNullOrEmpty(Metadata?.BackgroundFile))
|
||||
return null;
|
||||
|
||||
try
|
||||
@ -165,7 +165,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected override Track GetBeatmapTrack()
|
||||
{
|
||||
if (Metadata?.AudioFile == null)
|
||||
if (string.IsNullOrEmpty(Metadata?.AudioFile))
|
||||
return null;
|
||||
|
||||
try
|
||||
@ -181,7 +181,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected override Waveform GetWaveform()
|
||||
{
|
||||
if (Metadata?.AudioFile == null)
|
||||
if (string.IsNullOrEmpty(Metadata?.AudioFile))
|
||||
return null;
|
||||
|
||||
try
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Database
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">The model type.</typeparam>
|
||||
/// <typeparam name="TFileModel">The associated file join type.</typeparam>
|
||||
public abstract class ArchiveModelManager<TModel, TFileModel> : IModelManager<TModel>, IModelFileManager<TModel, TFileModel>
|
||||
public abstract class ArchiveModelManager<TModel, TFileModel> : IModelImporter<TModel>, IModelManager<TModel>, IModelFileManager<TModel, TFileModel>
|
||||
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
|
||||
where TFileModel : class, INamedFileInfo, IHasPrimaryKey, new()
|
||||
{
|
||||
@ -466,7 +466,7 @@ namespace osu.Game.Database
|
||||
if (retrievedItem == null)
|
||||
throw new ArgumentException(@"Specified model could not be found", nameof(item));
|
||||
|
||||
string filename = $"{getValidFilename(item.ToString())}{HandledExtensions.First()}";
|
||||
string filename = $"{GetValidFilename(item.ToString())}{HandledExtensions.First()}";
|
||||
|
||||
using (var stream = exportStorage.GetStream(filename, FileAccess.Write, FileMode.Create))
|
||||
ExportModelTo(retrievedItem, stream);
|
||||
@ -913,9 +913,15 @@ namespace osu.Game.Database
|
||||
return Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
private string getValidFilename(string filename)
|
||||
private readonly char[] invalidFilenameCharacters = Path.GetInvalidFileNameChars()
|
||||
// Backslash is added to avoid issues when exporting to zip.
|
||||
// See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143.
|
||||
.Append('\\')
|
||||
.ToArray();
|
||||
|
||||
protected string GetValidFilename(string filename)
|
||||
{
|
||||
foreach (char c in Path.GetInvalidFileNameChars())
|
||||
foreach (char c in invalidFilenameCharacters)
|
||||
filename = filename.Replace(c, '_');
|
||||
return filename;
|
||||
}
|
||||
|
@ -10,35 +10,35 @@ namespace osu.Game.Database
|
||||
/// <summary>
|
||||
/// Represents a <see cref="IModelManager{TModel}"/> that can download new models from an external source.
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">The model type.</typeparam>
|
||||
public interface IModelDownloader<TModel> : IPostNotifications
|
||||
where TModel : class
|
||||
/// <typeparam name="T">The item's interface type.</typeparam>
|
||||
public interface IModelDownloader<T> : IPostNotifications
|
||||
where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Fired when a <typeparamref name="TModel"/> download begins.
|
||||
/// Fired when a <typeparamref name="T"/> download begins.
|
||||
/// This is NOT run on the update thread and should be scheduled.
|
||||
/// </summary>
|
||||
IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadBegan { get; }
|
||||
IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadBegan { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a <typeparamref name="TModel"/> download is interrupted, either due to user cancellation or failure.
|
||||
/// Fired when a <typeparamref name="T"/> download is interrupted, either due to user cancellation or failure.
|
||||
/// This is NOT run on the update thread and should be scheduled.
|
||||
/// </summary>
|
||||
IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadFailed { get; }
|
||||
IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadFailed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Begin a download for the requested <typeparamref name="TModel"/>.
|
||||
/// Begin a download for the requested <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <param name="model">The <stypeparamref name="TModel"/> to be downloaded.</param>
|
||||
/// <param name="item">The <stypeparamref name="T"/> to be downloaded.</param>
|
||||
/// <param name="minimiseDownloadSize">Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle..</param>
|
||||
/// <returns>Whether the download was started.</returns>
|
||||
bool Download(TModel model, bool minimiseDownloadSize);
|
||||
bool Download(T item, bool minimiseDownloadSize);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an existing <typeparamref name="TModel"/> download request if it exists.
|
||||
/// Gets an existing <typeparamref name="T"/> download request if it exists.
|
||||
/// </summary>
|
||||
/// <param name="model">The <typeparamref name="TModel"/> whose request is wanted.</param>
|
||||
/// <returns>The <see cref="ArchiveDownloadRequest{TModel}"/> object if it exists, otherwise null.</returns>
|
||||
ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model);
|
||||
/// <param name="item">The <typeparamref name="T"/> whose request is wanted.</param>
|
||||
/// <returns>The <see cref="ArchiveDownloadRequest{T}"/> object if it exists, otherwise null.</returns>
|
||||
ArchiveDownloadRequest<T> GetExistingDownload(T item);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Database
|
||||
/// Represents a model manager that publishes events when <typeparamref name="TModel"/>s are added or removed.
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">The model type.</typeparam>
|
||||
public interface IModelManager<TModel> : IModelImporter<TModel>
|
||||
public interface IModelManager<TModel>
|
||||
where TModel : class
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -14,39 +14,40 @@ using osu.Game.Overlays.Notifications;
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public abstract class ModelDownloader<TModel> : IModelDownloader<TModel>
|
||||
where TModel : class, IHasPrimaryKey, ISoftDelete, IEquatable<TModel>
|
||||
public abstract class ModelDownloader<TModel, T> : IModelDownloader<T>
|
||||
where TModel : class, IHasPrimaryKey, ISoftDelete, IEquatable<TModel>, T
|
||||
where T : class
|
||||
{
|
||||
public Action<Notification> PostNotification { protected get; set; }
|
||||
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadBegan => downloadBegan;
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadBegan => downloadBegan;
|
||||
|
||||
private readonly Bindable<WeakReference<ArchiveDownloadRequest<TModel>>> downloadBegan = new Bindable<WeakReference<ArchiveDownloadRequest<TModel>>>();
|
||||
private readonly Bindable<WeakReference<ArchiveDownloadRequest<T>>> downloadBegan = new Bindable<WeakReference<ArchiveDownloadRequest<T>>>();
|
||||
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<TModel>>> DownloadFailed => downloadFailed;
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<T>>> DownloadFailed => downloadFailed;
|
||||
|
||||
private readonly Bindable<WeakReference<ArchiveDownloadRequest<TModel>>> downloadFailed = new Bindable<WeakReference<ArchiveDownloadRequest<TModel>>>();
|
||||
private readonly Bindable<WeakReference<ArchiveDownloadRequest<T>>> downloadFailed = new Bindable<WeakReference<ArchiveDownloadRequest<T>>>();
|
||||
|
||||
private readonly IModelManager<TModel> modelManager;
|
||||
private readonly IModelImporter<TModel> importer;
|
||||
private readonly IAPIProvider api;
|
||||
|
||||
protected readonly List<ArchiveDownloadRequest<TModel>> CurrentDownloads = new List<ArchiveDownloadRequest<TModel>>();
|
||||
protected readonly List<ArchiveDownloadRequest<T>> CurrentDownloads = new List<ArchiveDownloadRequest<T>>();
|
||||
|
||||
protected ModelDownloader(IModelManager<TModel> modelManager, IAPIProvider api, IIpcHost importHost = null)
|
||||
protected ModelDownloader(IModelImporter<TModel> importer, IAPIProvider api, IIpcHost importHost = null)
|
||||
{
|
||||
this.modelManager = modelManager;
|
||||
this.importer = importer;
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the download request for this <typeparamref name="TModel"/>.
|
||||
/// Creates the download request for this <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <param name="model">The <typeparamref name="TModel"/> to be downloaded.</param>
|
||||
/// <param name="model">The <typeparamref name="T"/> to be downloaded.</param>
|
||||
/// <param name="minimiseDownloadSize">Whether this download should be optimised for slow connections. Generally means extras are not included in the download bundle.</param>
|
||||
/// <returns>The request object.</returns>
|
||||
protected abstract ArchiveDownloadRequest<TModel> CreateDownloadRequest(TModel model, bool minimiseDownloadSize);
|
||||
protected abstract ArchiveDownloadRequest<T> CreateDownloadRequest(T model, bool minimiseDownloadSize);
|
||||
|
||||
public bool Download(TModel model, bool minimiseDownloadSize = false)
|
||||
public bool Download(T model, bool minimiseDownloadSize = false)
|
||||
{
|
||||
if (!canDownload(model)) return false;
|
||||
|
||||
@ -68,11 +69,11 @@ namespace osu.Game.Database
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
// This gets scheduled back to the update thread, but we want the import to run in the background.
|
||||
var imported = await modelManager.Import(notification, new ImportTask(filename)).ConfigureAwait(false);
|
||||
var imported = await importer.Import(notification, new ImportTask(filename)).ConfigureAwait(false);
|
||||
|
||||
// for now a failed import will be marked as a failed download for simplicity.
|
||||
if (!imported.Any())
|
||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<T>>(request);
|
||||
|
||||
CurrentDownloads.Remove(request);
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
@ -91,25 +92,25 @@ namespace osu.Game.Database
|
||||
|
||||
api.PerformAsync(request);
|
||||
|
||||
downloadBegan.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||
downloadBegan.Value = new WeakReference<ArchiveDownloadRequest<T>>(request);
|
||||
return true;
|
||||
|
||||
void triggerFailure(Exception error)
|
||||
{
|
||||
CurrentDownloads.Remove(request);
|
||||
|
||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<TModel>>(request);
|
||||
downloadFailed.Value = new WeakReference<ArchiveDownloadRequest<T>>(request);
|
||||
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
|
||||
if (!(error is OperationCanceledException))
|
||||
Logger.Error(error, $"{modelManager.HumanisedModelName.Titleize()} download failed!");
|
||||
Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!");
|
||||
}
|
||||
}
|
||||
|
||||
public abstract ArchiveDownloadRequest<TModel> GetExistingDownload(TModel model);
|
||||
public abstract ArchiveDownloadRequest<T> GetExistingDownload(T model);
|
||||
|
||||
private bool canDownload(TModel model) => GetExistingDownload(model) == null && api != null;
|
||||
private bool canDownload(T model) => GetExistingDownload(model) == null && api != null;
|
||||
|
||||
private class DownloadNotification : ProgressNotification
|
||||
{
|
||||
|
@ -58,10 +58,9 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
RemoveInternal(Sprite);
|
||||
|
||||
AddInternal(bufferedContainer = new BufferedContainer
|
||||
AddInternal(bufferedContainer = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CacheDrawnFrameBuffer = true,
|
||||
RedrawOnScale = false,
|
||||
Child = Sprite
|
||||
});
|
||||
|
@ -69,12 +69,11 @@ namespace osu.Game.Graphics.Sprites
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new BufferedContainer
|
||||
new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BlurSigma = new Vector2(4),
|
||||
CacheDrawnFrameBuffer = true,
|
||||
RedrawOnScale = false,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Blending = BlendingParameters.Additive,
|
||||
|
@ -1,7 +1,9 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osuTK;
|
||||
@ -22,15 +24,9 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Enabled.Value = !isLoading;
|
||||
|
||||
if (value)
|
||||
{
|
||||
loading.Show();
|
||||
OnLoadStarted();
|
||||
}
|
||||
else
|
||||
{
|
||||
loading.Hide();
|
||||
OnLoadFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,18 +40,34 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected LoadingButton()
|
||||
{
|
||||
AddRange(new[]
|
||||
Add(loading = new LoadingSpinner
|
||||
{
|
||||
CreateContent(),
|
||||
loading = new LoadingSpinner
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(12)
|
||||
}
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(12),
|
||||
Depth = -1,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(CreateContent());
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
loading.State.BindValueChanged(s =>
|
||||
{
|
||||
if (s.NewValue == Visibility.Visible)
|
||||
OnLoadStarted();
|
||||
else
|
||||
OnLoadFinished();
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (!Enabled.Value)
|
||||
|
@ -168,7 +168,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
descriptionText.Text = value;
|
||||
|
||||
if (value == default)
|
||||
if (!string.IsNullOrEmpty(value.ToString()))
|
||||
descriptionText.Show();
|
||||
else
|
||||
descriptionText.Hide();
|
||||
|
@ -6,11 +6,11 @@ using osu.Game.Beatmaps;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class DownloadBeatmapSetRequest : ArchiveDownloadRequest<BeatmapSetInfo>
|
||||
public class DownloadBeatmapSetRequest : ArchiveDownloadRequest<IBeatmapSetInfo>
|
||||
{
|
||||
private readonly bool noVideo;
|
||||
|
||||
public DownloadBeatmapSetRequest(BeatmapSetInfo set, bool noVideo)
|
||||
public DownloadBeatmapSetRequest(IBeatmapSetInfo set, bool noVideo)
|
||||
: base(set)
|
||||
{
|
||||
this.noVideo = noVideo;
|
||||
@ -25,6 +25,6 @@ namespace osu.Game.Online.API.Requests
|
||||
|
||||
protected override string FileExtension => ".osz";
|
||||
|
||||
protected override string Target => $@"beatmapsets/{Model.OnlineBeatmapSetID}/download{(noVideo ? "?noVideo=1" : "")}";
|
||||
protected override string Target => $@"beatmapsets/{Model.OnlineID}/download{(noVideo ? "?noVideo=1" : "")}";
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,15 @@ using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class DownloadReplayRequest : ArchiveDownloadRequest<ScoreInfo>
|
||||
public class DownloadReplayRequest : ArchiveDownloadRequest<IScoreInfo>
|
||||
{
|
||||
public DownloadReplayRequest(ScoreInfo score)
|
||||
public DownloadReplayRequest(IScoreInfo score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string FileExtension => ".osr";
|
||||
|
||||
protected override string Target => $@"scores/{Model.Ruleset.ShortName}/{Model.OnlineScoreID}/download";
|
||||
protected override string Target => $@"scores/{Model.Ruleset.ShortName}/{Model.OnlineID}/download";
|
||||
}
|
||||
}
|
||||
|
@ -81,34 +81,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
|
||||
public double BPM { get; set; }
|
||||
|
||||
public virtual BeatmapInfo ToBeatmapInfo(RulesetStore rulesets)
|
||||
{
|
||||
var set = BeatmapSet?.ToBeatmapSet(rulesets);
|
||||
|
||||
return new BeatmapInfo
|
||||
{
|
||||
Metadata = set?.Metadata ?? new BeatmapMetadata(),
|
||||
Ruleset = rulesets.GetRuleset(RulesetID),
|
||||
StarDifficulty = StarRating,
|
||||
OnlineBeatmapID = OnlineID,
|
||||
Version = DifficultyName,
|
||||
// this is actually an incorrect mapping (Length is calculated as drain length in lazer's import process, see BeatmapManager.calculateLength).
|
||||
Length = Length,
|
||||
Status = Status,
|
||||
MD5Hash = Checksum,
|
||||
BeatmapSet = set,
|
||||
MaxCombo = MaxCombo,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
DrainRate = DrainRate,
|
||||
CircleSize = CircleSize,
|
||||
ApproachRate = ApproachRate,
|
||||
OverallDifficulty = OverallDifficulty,
|
||||
},
|
||||
OnlineInfo = this,
|
||||
};
|
||||
}
|
||||
|
||||
#region Implementation of IBeatmapInfo
|
||||
|
||||
public IBeatmapMetadataInfo Metadata => (BeatmapSet as IBeatmapSetInfo)?.Metadata ?? new BeatmapMetadata();
|
||||
|
@ -3,11 +3,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
|
||||
#nullable enable
|
||||
@ -119,28 +117,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
public string Tags { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty(@"beatmaps")]
|
||||
public IEnumerable<APIBeatmap> Beatmaps { get; set; } = Array.Empty<APIBeatmap>();
|
||||
|
||||
public virtual BeatmapSetInfo ToBeatmapSet(RulesetStore rulesets)
|
||||
{
|
||||
var beatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = OnlineID,
|
||||
Metadata = metadata,
|
||||
Status = Status,
|
||||
OnlineInfo = this
|
||||
};
|
||||
|
||||
beatmapSet.Beatmaps = Beatmaps.Select(b =>
|
||||
{
|
||||
var beatmap = b.ToBeatmapInfo(rulesets);
|
||||
beatmap.BeatmapSet = beatmapSet;
|
||||
beatmap.Metadata = beatmapSet.Metadata;
|
||||
return beatmap;
|
||||
}).ToList();
|
||||
|
||||
return beatmapSet;
|
||||
}
|
||||
public APIBeatmap[] Beatmaps { get; set; } = Array.Empty<APIBeatmap>();
|
||||
|
||||
private BeatmapMetadata metadata => new BeatmapMetadata
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
TotalScore = TotalScore,
|
||||
MaxCombo = MaxCombo,
|
||||
BeatmapInfo = Beatmap?.ToBeatmapInfo(rulesets),
|
||||
BeatmapInfo = beatmap,
|
||||
User = User,
|
||||
Accuracy = Accuracy,
|
||||
OnlineScoreID = OnlineID,
|
||||
@ -111,9 +111,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
Mods = modInstances,
|
||||
};
|
||||
|
||||
if (beatmap != null)
|
||||
scoreInfo.BeatmapInfo = beatmap;
|
||||
|
||||
if (Statistics != null)
|
||||
{
|
||||
foreach (var kvp in Statistics)
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Online
|
||||
[Resolved(CanBeNull = true)]
|
||||
protected BeatmapManager? Manager { get; private set; }
|
||||
|
||||
private ArchiveDownloadRequest<BeatmapSetInfo>? attachedRequest;
|
||||
private ArchiveDownloadRequest<IBeatmapSetInfo>? attachedRequest;
|
||||
|
||||
public BeatmapDownloadTracker(IBeatmapSetInfo trackedItem)
|
||||
: base(trackedItem)
|
||||
@ -25,8 +25,8 @@ namespace osu.Game.Online
|
||||
|
||||
private IBindable<WeakReference<BeatmapSetInfo>>? managerUpdated;
|
||||
private IBindable<WeakReference<BeatmapSetInfo>>? managerRemoved;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>>? managerDownloadFailed;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>>? managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>>? managerDownloadFailed;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load()
|
||||
@ -52,7 +52,7 @@ namespace osu.Game.Online
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
}
|
||||
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest)
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
@ -64,7 +64,7 @@ namespace osu.Game.Online
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<BeatmapSetInfo>>> weakRequest)
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IBeatmapSetInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Online
|
||||
}
|
||||
}
|
||||
|
||||
private void attachDownload(ArchiveDownloadRequest<BeatmapSetInfo>? request)
|
||||
private void attachDownload(ArchiveDownloadRequest<IBeatmapSetInfo>? request)
|
||||
{
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ using osu.Framework.Logging;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osu.Game.Online.Rooms.RoomStatuses;
|
||||
using osu.Game.Rulesets;
|
||||
@ -644,24 +645,32 @@ namespace osu.Game.Online.Multiplayer
|
||||
|
||||
RoomUpdated?.Invoke();
|
||||
|
||||
GetOnlineBeatmapSet(settings.BeatmapID, cancellationToken).ContinueWith(set => Schedule(() =>
|
||||
GetOnlineBeatmapSet(settings.BeatmapID, cancellationToken).ContinueWith(task => Schedule(() =>
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
updatePlaylist(settings, set.Result);
|
||||
APIBeatmapSet beatmapSet = task.Result;
|
||||
|
||||
// The incoming response is deserialised without circular reference handling currently.
|
||||
// Because we require using metadata from this instance, populate the nested beatmaps' sets manually here.
|
||||
foreach (var b in beatmapSet.Beatmaps)
|
||||
b.BeatmapSet = beatmapSet;
|
||||
|
||||
updatePlaylist(settings, beatmapSet);
|
||||
}), TaskContinuationOptions.OnlyOnRanToCompletion);
|
||||
}, cancellationToken);
|
||||
|
||||
private void updatePlaylist(MultiplayerRoomSettings settings, BeatmapSetInfo beatmapSet)
|
||||
private void updatePlaylist(MultiplayerRoomSettings settings, APIBeatmapSet beatmapSet)
|
||||
{
|
||||
if (Room == null || !Room.Settings.Equals(settings))
|
||||
return;
|
||||
|
||||
Debug.Assert(APIRoom != null);
|
||||
|
||||
var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID);
|
||||
beatmap.MD5Hash = settings.BeatmapChecksum;
|
||||
var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineID == settings.BeatmapID);
|
||||
|
||||
beatmap.Checksum = settings.BeatmapChecksum;
|
||||
|
||||
var ruleset = Rulesets.GetRuleset(settings.RulesetID).CreateInstance();
|
||||
var mods = settings.RequiredMods.Select(m => m.ToMod(ruleset));
|
||||
@ -694,12 +703,12 @@ namespace osu.Game.Online.Multiplayer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a <see cref="BeatmapSetInfo"/> from an online source.
|
||||
/// Retrieves a <see cref="APIBeatmapSet"/> from an online source.
|
||||
/// </summary>
|
||||
/// <param name="beatmapId">The beatmap set ID.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the request.</param>
|
||||
/// <returns>The <see cref="BeatmapSetInfo"/> retrieval task.</returns>
|
||||
protected abstract Task<BeatmapSetInfo> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default);
|
||||
/// <returns>The <see cref="APIBeatmapSet"/> retrieval task.</returns>
|
||||
protected abstract Task<APIBeatmapSet> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// For the provided user ID, update whether the user is included in <see cref="CurrentMatchPlayingUserIds"/>.
|
||||
|
@ -9,9 +9,9 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Rooms;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
@ -148,9 +148,9 @@ namespace osu.Game.Online.Multiplayer
|
||||
return connection.InvokeAsync(nameof(IMultiplayerServer.StartMatch));
|
||||
}
|
||||
|
||||
protected override Task<BeatmapSetInfo> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
|
||||
protected override Task<APIBeatmapSet> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<BeatmapSetInfo>();
|
||||
var tcs = new TaskCompletionSource<APIBeatmapSet>();
|
||||
var req = new GetBeatmapSetRequest(beatmapId, BeatmapSetLookupType.BeatmapId);
|
||||
|
||||
req.Success += res =>
|
||||
@ -161,7 +161,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
return;
|
||||
}
|
||||
|
||||
tcs.SetResult(res.ToBeatmapSet(Rulesets));
|
||||
tcs.SetResult(res);
|
||||
};
|
||||
|
||||
req.Failure += e => tcs.SetException(e);
|
||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -61,7 +62,7 @@ namespace osu.Game.Online.Rooms
|
||||
[CanBeNull]
|
||||
public MultiplayerScoresAround ScoresAround { get; set; }
|
||||
|
||||
public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem)
|
||||
public ScoreInfo CreateScoreInfo(PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap)
|
||||
{
|
||||
var rulesetInstance = playlistItem.Ruleset.Value.CreateInstance();
|
||||
|
||||
@ -70,7 +71,7 @@ namespace osu.Game.Online.Rooms
|
||||
OnlineScoreID = ID,
|
||||
TotalScore = TotalScore,
|
||||
MaxCombo = MaxCombo,
|
||||
BeatmapInfo = playlistItem.Beatmap.Value,
|
||||
BeatmapInfo = beatmap,
|
||||
BeatmapInfoID = playlistItem.BeatmapID,
|
||||
Ruleset = playlistItem.Ruleset.Value,
|
||||
RulesetID = playlistItem.RulesetID,
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -52,6 +53,8 @@ namespace osu.Game.Online.Rooms
|
||||
|
||||
downloadTracker?.RemoveAndDisposeImmediately();
|
||||
|
||||
Debug.Assert(item.NewValue.Beatmap.Value.BeatmapSet != null);
|
||||
|
||||
downloadTracker = new BeatmapDownloadTracker(item.NewValue.Beatmap.Value.BeatmapSet);
|
||||
|
||||
AddInternal(downloadTracker);
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Online.Rooms
|
||||
public bool Expired { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
|
||||
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||
@ -65,13 +65,13 @@ namespace osu.Game.Online.Rooms
|
||||
|
||||
public PlaylistItem()
|
||||
{
|
||||
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineBeatmapID ?? 0);
|
||||
Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineID ?? -1);
|
||||
Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
|
||||
}
|
||||
|
||||
public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets)
|
||||
public void MapObjects(RulesetStore rulesets)
|
||||
{
|
||||
Beatmap.Value ??= apiBeatmap.ToBeatmapInfo(rulesets);
|
||||
Beatmap.Value ??= apiBeatmap;
|
||||
Ruleset.Value ??= rulesets.GetRuleset(RulesetID);
|
||||
|
||||
Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Online
|
||||
[Resolved(CanBeNull = true)]
|
||||
protected ScoreManager? Manager { get; private set; }
|
||||
|
||||
private ArchiveDownloadRequest<ScoreInfo>? attachedRequest;
|
||||
private ArchiveDownloadRequest<IScoreInfo>? attachedRequest;
|
||||
|
||||
public ScoreDownloadTracker(ScoreInfo trackedItem)
|
||||
: base(trackedItem)
|
||||
@ -25,8 +25,8 @@ namespace osu.Game.Online
|
||||
|
||||
private IBindable<WeakReference<ScoreInfo>>? managerUpdated;
|
||||
private IBindable<WeakReference<ScoreInfo>>? managerRemoved;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>>? managerDownloadFailed;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>>? managerDownloadBegan;
|
||||
private IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>>? managerDownloadFailed;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load()
|
||||
@ -56,7 +56,7 @@ namespace osu.Game.Online
|
||||
managerRemoved.BindValueChanged(itemRemoved);
|
||||
}
|
||||
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest)
|
||||
private void downloadBegan(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
@ -68,7 +68,7 @@ namespace osu.Game.Online
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> weakRequest)
|
||||
private void downloadFailed(ValueChangedEvent<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> weakRequest)
|
||||
{
|
||||
if (weakRequest.NewValue.TryGetTarget(out var request))
|
||||
{
|
||||
@ -80,7 +80,7 @@ namespace osu.Game.Online
|
||||
}
|
||||
}
|
||||
|
||||
private void attachDownload(ArchiveDownloadRequest<ScoreInfo>? request)
|
||||
private void attachDownload(ArchiveDownloadRequest<IScoreInfo>? request)
|
||||
{
|
||||
if (attachedRequest != null)
|
||||
{
|
||||
@ -144,7 +144,7 @@ namespace osu.Game.Online
|
||||
}
|
||||
}
|
||||
|
||||
private bool checkEquality(ScoreInfo x, ScoreInfo y) => x.OnlineScoreID == y.OnlineScoreID;
|
||||
private bool checkEquality(IScoreInfo x, IScoreInfo y) => x.OnlineID == y.OnlineID;
|
||||
|
||||
#region Disposal
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -22,6 +23,11 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
|
||||
public BeatmapSearchMultipleSelectionFilterRow(LocalisableString header)
|
||||
: base(header)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Current.BindTo(filter.Current);
|
||||
}
|
||||
@ -31,6 +37,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
||||
/// <summary>
|
||||
/// Creates a filter control that can be used to simultaneously select multiple values of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
protected virtual MultipleSelectionFilter CreateMultipleSelectionFilter() => new MultipleSelectionFilter();
|
||||
|
||||
protected class MultipleSelectionFilter : FillFlowContainer<MultipleSelectionFilterTabItem>
|
||||
|
@ -147,7 +147,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels
|
||||
{
|
||||
var icons = new List<DifficultyIcon>();
|
||||
|
||||
if (SetInfo.Beatmaps.Count() > maximum_difficulty_icons)
|
||||
if (SetInfo.Beatmaps.Length > maximum_difficulty_icons)
|
||||
{
|
||||
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
|
||||
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.Where(b => b.RulesetID == ruleset.OnlineID).ToList(), ruleset, this is ListBeatmapPanel ? Color4.White : colours.Gray5));
|
||||
|
@ -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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -66,7 +67,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
if (value?.Scores.Any() != true)
|
||||
return;
|
||||
|
||||
scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets, Beatmap.Value.ToBeatmapInfo(rulesets))).ToArray(), loadCancellationSource.Token)
|
||||
var apiBeatmap = Beatmap.Value;
|
||||
|
||||
Debug.Assert(apiBeatmap != null);
|
||||
|
||||
// TODO: temporary. should be removed once `OrderByTotalScore` can accept `IScoreInfo`.
|
||||
var beatmapInfo = new BeatmapInfo
|
||||
{
|
||||
MaxCombo = apiBeatmap.MaxCombo,
|
||||
Status = apiBeatmap.Status
|
||||
};
|
||||
|
||||
scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets, beatmapInfo)).ToArray(), loadCancellationSource.Token)
|
||||
.ContinueWith(ordered => Schedule(() =>
|
||||
{
|
||||
if (loadCancellationSource.IsCancellationRequested)
|
||||
@ -74,11 +86,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
var topScore = ordered.Result.First();
|
||||
|
||||
scoreTable.DisplayScores(ordered.Result, topScore.BeatmapInfo?.Status.GrantsPerformancePoints() == true);
|
||||
scoreTable.DisplayScores(ordered.Result, apiBeatmap.Status.GrantsPerformancePoints());
|
||||
scoreTable.Show();
|
||||
|
||||
var userScore = value.UserScore;
|
||||
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets, Beatmap.Value.ToBeatmapInfo(rulesets));
|
||||
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets, beatmapInfo);
|
||||
|
||||
topScoresContainer.Add(new DrawableTopScore(topScore));
|
||||
|
||||
|
@ -26,6 +26,8 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
public static LocalisableString ListingString => LayoutStrings.HeaderChangelogIndex;
|
||||
|
||||
private readonly Bindable<APIUpdateStream> currentStream = new Bindable<APIUpdateStream>();
|
||||
|
||||
private Box streamsBackground;
|
||||
|
||||
public ChangelogHeader()
|
||||
@ -39,7 +41,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
|
||||
Build.ValueChanged += showBuild;
|
||||
|
||||
Streams.Current.ValueChanged += e =>
|
||||
currentStream.ValueChanged += e =>
|
||||
{
|
||||
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Build.Value?.UpdateStream))
|
||||
Build.Value = e.NewValue.LatestBuild;
|
||||
@ -67,7 +69,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
else
|
||||
{
|
||||
Current.Value = ListingString;
|
||||
Streams.Current.Value = null;
|
||||
currentStream.Value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +94,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
Horizontal = 65,
|
||||
Vertical = 20
|
||||
},
|
||||
Child = Streams = new ChangelogUpdateStreamControl()
|
||||
Child = Streams = new ChangelogUpdateStreamControl { Current = currentStream },
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -110,7 +112,7 @@ namespace osu.Game.Overlays.Changelog
|
||||
if (Build.Value == null)
|
||||
return;
|
||||
|
||||
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
|
||||
currentStream.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
|
||||
}
|
||||
|
||||
private class ChangelogHeaderTitle : OverlayTitle
|
||||
|
@ -175,6 +175,8 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
|
||||
|
||||
private readonly string text;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; }
|
||||
|
||||
@ -184,10 +186,10 @@ namespace osu.Game.Overlays.Comments
|
||||
|
||||
public CommitButton(string text)
|
||||
{
|
||||
this.text = text;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
LoadingAnimationSize = new Vector2(10);
|
||||
|
||||
drawableText.Text = text;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -232,7 +234,8 @@ namespace osu.Game.Overlays.Comments
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||
Margin = new MarginPadding { Horizontal = 20 }
|
||||
Margin = new MarginPadding { Horizontal = 20 },
|
||||
Text = text,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -366,14 +366,13 @@ namespace osu.Game.Overlays
|
||||
private readonly WorkingBeatmap beatmap;
|
||||
|
||||
public Background(WorkingBeatmap beatmap = null)
|
||||
: base(cachedFrameBuffer: true)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
|
||||
Depth = float.MaxValue;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
CacheDrawnFrameBuffer = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sprite = new Sprite
|
||||
|
@ -37,11 +37,7 @@ namespace osu.Game.Overlays
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Margin = new MarginPadding(20),
|
||||
Action = () =>
|
||||
{
|
||||
ScrollToStart();
|
||||
Button.State = Visibility.Hidden;
|
||||
}
|
||||
Action = scrollToTop
|
||||
});
|
||||
}
|
||||
|
||||
@ -58,6 +54,12 @@ namespace osu.Game.Overlays
|
||||
Button.State = Target > button_scroll_position ? Visibility.Visible : Visibility.Hidden;
|
||||
}
|
||||
|
||||
private void scrollToTop()
|
||||
{
|
||||
ScrollToStart();
|
||||
Button.State = Visibility.Hidden;
|
||||
}
|
||||
|
||||
public class ScrollToTopButton : OsuHoverContainer
|
||||
{
|
||||
private const int fade_duration = 500;
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
string audioFile = context.Beatmap.Metadata?.AudioFile;
|
||||
if (audioFile == null)
|
||||
if (string.IsNullOrEmpty(audioFile))
|
||||
yield break;
|
||||
|
||||
var track = context.WorkingBeatmap.Track;
|
||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit.Checks
|
||||
{
|
||||
string filename = GetFilename(context.Beatmap);
|
||||
|
||||
if (filename == null)
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
yield return new IssueTemplateNoneSet(this).Create(TypeOfFile);
|
||||
|
||||
|
@ -30,11 +30,6 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0;
|
||||
|
||||
[Obsolete("Use the mod-supporting override")] // can be removed 20210731
|
||||
public virtual Score CreateReplayScore(IBeatmap beatmap) => new Score { Replay = new Replay() };
|
||||
|
||||
#pragma warning disable 618
|
||||
public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => CreateReplayScore(beatmap);
|
||||
#pragma warning restore 618
|
||||
public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score { Replay = new Replay() };
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
public class ScoreManager : IModelManager<ScoreInfo>, IModelFileManager<ScoreInfo, ScoreFileInfo>, IModelDownloader<ScoreInfo>
|
||||
public class ScoreManager : IModelManager<ScoreInfo>, IModelImporter<ScoreInfo>, IModelFileManager<ScoreInfo, ScoreFileInfo>, IModelDownloader<IScoreInfo>
|
||||
{
|
||||
private readonly Scheduler scheduler;
|
||||
private readonly Func<BeatmapDifficultyCache> difficulties;
|
||||
@ -350,16 +350,14 @@ namespace osu.Game.Scoring
|
||||
|
||||
#region Implementation of IModelDownloader<ScoreInfo>
|
||||
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> DownloadBegan => scoreModelDownloader.DownloadBegan;
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> DownloadBegan => scoreModelDownloader.DownloadBegan;
|
||||
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<ScoreInfo>>> DownloadFailed => scoreModelDownloader.DownloadFailed;
|
||||
public IBindable<WeakReference<ArchiveDownloadRequest<IScoreInfo>>> DownloadFailed => scoreModelDownloader.DownloadFailed;
|
||||
|
||||
public bool Download(ScoreInfo model, bool minimiseDownloadSize)
|
||||
{
|
||||
return scoreModelDownloader.Download(model, minimiseDownloadSize);
|
||||
}
|
||||
public bool Download(IScoreInfo model, bool minimiseDownloadSize) =>
|
||||
scoreModelDownloader.Download(model, minimiseDownloadSize);
|
||||
|
||||
public ArchiveDownloadRequest<ScoreInfo> GetExistingDownload(ScoreInfo model)
|
||||
public ArchiveDownloadRequest<IScoreInfo> GetExistingDownload(IScoreInfo model)
|
||||
{
|
||||
return scoreModelDownloader.GetExistingDownload(model);
|
||||
}
|
||||
|
@ -8,16 +8,16 @@ using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
public class ScoreModelDownloader : ModelDownloader<ScoreInfo>
|
||||
public class ScoreModelDownloader : ModelDownloader<ScoreInfo, IScoreInfo>
|
||||
{
|
||||
public ScoreModelDownloader(ScoreModelManager scoreManager, IAPIProvider api, IIpcHost importHost = null)
|
||||
public ScoreModelDownloader(IModelImporter<ScoreInfo> scoreManager, IAPIProvider api, IIpcHost importHost = null)
|
||||
: base(scoreManager, api, importHost)
|
||||
{
|
||||
}
|
||||
|
||||
protected override ArchiveDownloadRequest<ScoreInfo> CreateDownloadRequest(ScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
||||
protected override ArchiveDownloadRequest<IScoreInfo> CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
|
||||
|
||||
public override ArchiveDownloadRequest<ScoreInfo> GetExistingDownload(ScoreInfo model)
|
||||
=> CurrentDownloads.Find(r => r.Model.OnlineScoreID == model.OnlineScoreID);
|
||||
public override ArchiveDownloadRequest<IScoreInfo> GetExistingDownload(IScoreInfo model)
|
||||
=> CurrentDownloads.Find(r => r.Model.OnlineID == model.OnlineID);
|
||||
}
|
||||
}
|
||||
|
@ -108,11 +108,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
bool selectionPerformed = performMouseDownActions(e);
|
||||
|
||||
// even if a selection didn't occur, a drag event may still move the selection.
|
||||
bool movementPossible = prepareSelectionMovement();
|
||||
|
||||
return selectionPerformed || (e.Button == MouseButton.Left && movementPossible);
|
||||
// check if selection has occurred
|
||||
if (selectionPerformed)
|
||||
{
|
||||
// only unmodified right click should show context menu
|
||||
bool shouldShowContextMenu = e.Button == MouseButton.Right && !e.ShiftPressed && !e.AltPressed && !e.SuperPressed;
|
||||
|
||||
// stop propagation if not showing context menu
|
||||
return !shouldShowContextMenu;
|
||||
}
|
||||
|
||||
// even if a selection didn't occur, a drag event may still move the selection.
|
||||
return e.Button == MouseButton.Left && movementPossible;
|
||||
}
|
||||
|
||||
protected SelectionBlueprint<T> ClickedBlueprint { get; private set; }
|
||||
|
@ -393,6 +393,7 @@ namespace osu.Game.Screens.Menu
|
||||
public class OutlineTriangle : BufferedContainer
|
||||
{
|
||||
public OutlineTriangle(bool outlineOnly, float size)
|
||||
: base(cachedFrameBuffer: true)
|
||||
{
|
||||
Size = new Vector2(size);
|
||||
|
||||
@ -414,7 +415,6 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
|
||||
Blending = BlendingParameters.Additive;
|
||||
CacheDrawnFrameBuffer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Rooms;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@ -61,7 +62,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
{
|
||||
var beatmap = playlistItem?.Beatmap.Value;
|
||||
|
||||
if (background?.BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover == beatmap?.BeatmapSet?.OnlineInfo?.Covers.Cover)
|
||||
string? lastCover = (background?.Beatmap?.BeatmapSet as IBeatmapSetOnlineInfo)?.Covers.Cover;
|
||||
string? newCover = (beatmap?.BeatmapSet as IBeatmapSetOnlineInfo)?.Covers.Cover;
|
||||
|
||||
if (lastCover == newCover)
|
||||
return;
|
||||
|
||||
cancellationSource?.Cancel();
|
||||
|
@ -13,11 +13,11 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
{
|
||||
public class PlaylistItemBackground : Background
|
||||
{
|
||||
public readonly BeatmapInfo? BeatmapInfo;
|
||||
public readonly IBeatmapInfo? Beatmap;
|
||||
|
||||
public PlaylistItemBackground(PlaylistItem? playlistItem)
|
||||
{
|
||||
BeatmapInfo = playlistItem?.Beatmap.Value;
|
||||
Beatmap = playlistItem?.Beatmap.Value;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -26,8 +26,8 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
Texture? texture = null;
|
||||
|
||||
// prefer online cover where available.
|
||||
if (BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover != null)
|
||||
texture = textures.Get(BeatmapInfo.BeatmapSet.OnlineInfo.Covers.Cover);
|
||||
if (Beatmap?.BeatmapSet is IBeatmapSetOnlineInfo online)
|
||||
texture = textures.Get(online.Covers.Cover);
|
||||
|
||||
Sprite.Texture = texture ?? beatmaps.DefaultBeatmap.Background;
|
||||
}
|
||||
@ -38,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
|
||||
return other.GetType() == GetType()
|
||||
&& ((PlaylistItemBackground)other).BeatmapInfo == BeatmapInfo;
|
||||
&& ((PlaylistItemBackground)other).Beatmap == Beatmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
try
|
||||
{
|
||||
foreach (var pi in room.Playlist)
|
||||
pi.MapObjects(beatmaps, rulesets);
|
||||
pi.MapObjects(rulesets);
|
||||
|
||||
var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value);
|
||||
if (existing == null)
|
||||
|
@ -80,10 +80,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
||||
|
||||
private void updateRange(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarDifficulty).ToArray();
|
||||
var orderedDifficulties = Playlist.Select(p => p.Beatmap.Value).OrderBy(b => b.StarRating).ToArray();
|
||||
|
||||
StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarDifficulty : 0, 0);
|
||||
StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarDifficulty : 0, 0);
|
||||
StarDifficulty minDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[0].StarRating : 0, 0);
|
||||
StarDifficulty maxDifficulty = new StarDifficulty(orderedDifficulties.Length > 0 ? orderedDifficulties[^1].StarRating : 0, 0);
|
||||
|
||||
minDisplay.Current.Value = minDifficulty;
|
||||
maxDisplay.Current.Value = maxDifficulty;
|
||||
|
@ -27,6 +27,7 @@ using osu.Game.Overlays.BeatmapSet;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -45,7 +46,7 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
private ExplicitContentBeatmapPill explicitContentPill;
|
||||
private ModDisplay modDisplay;
|
||||
|
||||
private readonly Bindable<BeatmapInfo> beatmap = new Bindable<BeatmapInfo>();
|
||||
private readonly Bindable<IBeatmapInfo> beatmap = new Bindable<IBeatmapInfo>();
|
||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||
private readonly BindableList<Mod> requiredMods = new BindableList<Mod>();
|
||||
|
||||
@ -96,6 +97,7 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
}
|
||||
|
||||
private ScheduledDelegate scheduledRefresh;
|
||||
private PanelBackground panelBackground;
|
||||
|
||||
private void scheduleRefresh()
|
||||
{
|
||||
@ -105,23 +107,25 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
|
||||
private void refresh()
|
||||
{
|
||||
difficultyIconContainer.Child = new DifficultyIcon(beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
|
||||
difficultyIconContainer.Child = new DifficultyIcon(Item.Beatmap.Value, ruleset.Value, requiredMods, performBackgroundDifficultyLookup: false) { Size = new Vector2(32) };
|
||||
|
||||
panelBackground.Beatmap.Value = Item.Beatmap.Value;
|
||||
|
||||
beatmapText.Clear();
|
||||
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineBeatmapID.ToString(), null, text =>
|
||||
beatmapText.AddLink(Item.Beatmap.Value.GetDisplayTitleRomanisable(), LinkAction.OpenBeatmap, Item.Beatmap.Value.OnlineID.ToString(), null, text =>
|
||||
{
|
||||
text.Truncate = true;
|
||||
});
|
||||
|
||||
authorText.Clear();
|
||||
|
||||
if (Item.Beatmap?.Value?.Metadata?.Author != null)
|
||||
if (!string.IsNullOrEmpty(Item.Beatmap.Value?.Metadata.Author))
|
||||
{
|
||||
authorText.AddText("mapped by ");
|
||||
authorText.AddUserLink(Item.Beatmap.Value?.Metadata.Author);
|
||||
authorText.AddUserLink(new User { Username = Item.Beatmap.Value.Metadata.Author });
|
||||
}
|
||||
|
||||
bool hasExplicitContent = Item.Beatmap.Value.BeatmapSet.OnlineInfo?.HasExplicitContent == true;
|
||||
bool hasExplicitContent = (Item.Beatmap.Value.BeatmapSet as IBeatmapSetOnlineInfo)?.HasExplicitContent == true;
|
||||
explicitContentPill.Alpha = hasExplicitContent ? 1 : 0;
|
||||
|
||||
modDisplay.Current.Value = requiredMods.ToArray();
|
||||
@ -145,10 +149,9 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true
|
||||
},
|
||||
new PanelBackground
|
||||
panelBackground = new PanelBackground
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Beatmap = { BindTarget = beatmap }
|
||||
},
|
||||
new GridContainer
|
||||
{
|
||||
@ -181,8 +184,11 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
{
|
||||
beatmapText = new LinkFlowContainer(fontParameters)
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
// workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
|
||||
// TODO: remove when text/link flow can support truncation with ellipsis natively.
|
||||
Height = OsuFont.DEFAULT_FONT_SIZE,
|
||||
Masking = true
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
@ -334,7 +340,7 @@ namespace osu.Game.Screens.OnlinePlay
|
||||
// For now, this is the same implementation as in PanelBackground, but supports a beatmap info rather than a working beatmap
|
||||
private class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222)
|
||||
{
|
||||
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
|
||||
public readonly Bindable<IBeatmapInfo> Beatmap = new Bindable<IBeatmapInfo>();
|
||||
|
||||
public PanelBackground()
|
||||
{
|
||||
|
@ -353,7 +353,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
// workaround to ensure only the first line of text shows, emulating truncation (but without ellipsis at the end).
|
||||
// TODO: remove when text/link flow can support truncation with ellipsis natively.
|
||||
Height = 16,
|
||||
Masking = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -381,11 +384,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
statusText.Text = "Currently playing ";
|
||||
beatmapText.AddLink(item.NewValue.Beatmap.Value.GetDisplayTitleRomanisable(),
|
||||
LinkAction.OpenBeatmap,
|
||||
item.NewValue.Beatmap.Value.OnlineBeatmapID.ToString(),
|
||||
item.NewValue.Beatmap.Value.OnlineID.ToString(),
|
||||
creationParameters: s =>
|
||||
{
|
||||
s.Truncate = true;
|
||||
s.RelativeSizeAxes = Axes.X;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -369,7 +369,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
|
||||
var beatmap = SelectedItem.Value?.Beatmap.Value;
|
||||
|
||||
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
|
||||
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID);
|
||||
var localBeatmap = beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineID);
|
||||
|
||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
private void load(IBindable<RulesetInfo> ruleset)
|
||||
{
|
||||
// Sanity checks to ensure that PlaylistsPlayer matches the settings for the current PlaylistItem
|
||||
if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineBeatmapID)
|
||||
if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != PlaylistItem.Beatmap.Value.OnlineID)
|
||||
throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap");
|
||||
|
||||
if (ruleset.Value.ID != PlaylistItem.Ruleset.Value.ID)
|
||||
|
@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
||||
/// <param name="pivot">An optional pivot around which the scores were retrieved.</param>
|
||||
private void performSuccessCallback([NotNull] Action<IEnumerable<ScoreInfo>> callback, [NotNull] List<MultiplayerScore> scores, [CanBeNull] MultiplayerScores pivot = null)
|
||||
{
|
||||
var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem)).ToArray();
|
||||
var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem, Beatmap.Value.BeatmapInfo)).ToArray();
|
||||
|
||||
// Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration,
|
||||
// calculate the total scores locally before invoking the success callback.
|
||||
|
@ -32,9 +32,9 @@ namespace osu.Game.Screens.Play.Break
|
||||
}
|
||||
|
||||
public BlurredIcon()
|
||||
: base(cachedFrameBuffer: true)
|
||||
{
|
||||
RelativePositionAxes = Axes.X;
|
||||
CacheDrawnFrameBuffer = true;
|
||||
Child = icon = new SpriteIcon
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
|
@ -18,6 +18,7 @@ using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Spectator;
|
||||
using osu.Game.Overlays.BeatmapListing.Panels;
|
||||
using osu.Game.Overlays.Settings;
|
||||
@ -50,7 +51,6 @@ namespace osu.Game.Screens.Play
|
||||
private Container beatmapPanelContainer;
|
||||
private TriangleButton watchButton;
|
||||
private SettingsCheckbox automaticDownload;
|
||||
private BeatmapSetInfo onlineBeatmap;
|
||||
|
||||
/// <summary>
|
||||
/// The player's immediate online gameplay state.
|
||||
@ -60,6 +60,8 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private GetBeatmapSetRequest onlineBeatmapRequest;
|
||||
|
||||
private APIBeatmapSet beatmapSet;
|
||||
|
||||
public SoloSpectator([NotNull] User targetUser)
|
||||
: base(targetUser.Id)
|
||||
{
|
||||
@ -220,10 +222,10 @@ namespace osu.Game.Screens.Play
|
||||
Debug.Assert(state.BeatmapID != null);
|
||||
|
||||
onlineBeatmapRequest = new GetBeatmapSetRequest(state.BeatmapID.Value, BeatmapSetLookupType.BeatmapId);
|
||||
onlineBeatmapRequest.Success += res => Schedule(() =>
|
||||
onlineBeatmapRequest.Success += beatmapSet => Schedule(() =>
|
||||
{
|
||||
onlineBeatmap = res.ToBeatmapSet(rulesets);
|
||||
beatmapPanelContainer.Child = new GridBeatmapPanel(res);
|
||||
this.beatmapSet = beatmapSet;
|
||||
beatmapPanelContainer.Child = new GridBeatmapPanel(this.beatmapSet);
|
||||
checkForAutomaticDownload();
|
||||
});
|
||||
|
||||
@ -232,16 +234,16 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
private void checkForAutomaticDownload()
|
||||
{
|
||||
if (onlineBeatmap == null)
|
||||
if (beatmapSet == null)
|
||||
return;
|
||||
|
||||
if (!automaticDownload.Current.Value)
|
||||
return;
|
||||
|
||||
if (beatmaps.IsAvailableLocally(onlineBeatmap))
|
||||
if (beatmaps.IsAvailableLocally(new BeatmapSetInfo { OnlineBeatmapSetID = beatmapSet.OnlineID }))
|
||||
return;
|
||||
|
||||
beatmaps.Download(onlineBeatmap);
|
||||
beatmaps.Download(beatmapSet);
|
||||
}
|
||||
|
||||
public override bool OnExiting(IScreen next)
|
||||
|
@ -98,9 +98,8 @@ namespace osu.Game.Screens.Play
|
||||
/// </summary>
|
||||
protected virtual void RecreateGraph()
|
||||
{
|
||||
var newColumns = new BufferedContainer<Column>
|
||||
var newColumns = new BufferedContainer<Column>(cachedFrameBuffer: true)
|
||||
{
|
||||
CacheDrawnFrameBuffer = true,
|
||||
RedrawOnScale = false,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
|
@ -51,13 +51,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
Font = OsuFont.Numeric.With(size: 76),
|
||||
UseFullGlyphHeight = false
|
||||
},
|
||||
superFlash = new BufferedContainer
|
||||
superFlash = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BlurSigma = new Vector2(85),
|
||||
Size = new Vector2(600),
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Alpha = 0,
|
||||
Children = new[]
|
||||
@ -71,14 +70,13 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
|
||||
},
|
||||
},
|
||||
},
|
||||
flash = new BufferedContainer
|
||||
flash = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BlurSigma = new Vector2(35),
|
||||
BypassAutoSizeAxes = Axes.Both,
|
||||
Size = new Vector2(200),
|
||||
CacheDrawnFrameBuffer = true,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Alpha = 0,
|
||||
Scale = new Vector2(1.8f),
|
||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Screens.Select
|
||||
new PopupDialogOkButton
|
||||
{
|
||||
Text = @"Yes. Totally. Delete it.",
|
||||
Action = () => manager.Delete(beatmap),
|
||||
Action = () => manager?.Delete(beatmap),
|
||||
},
|
||||
new PopupDialogCancelButton
|
||||
{
|
||||
|
@ -41,13 +41,13 @@ namespace osu.Game.Screens.Select
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; }
|
||||
|
||||
private BeatmapInfo beatmapInfo;
|
||||
private IBeatmapInfo beatmapInfo;
|
||||
|
||||
private APIFailTimes failTimes;
|
||||
|
||||
private int[] ratings;
|
||||
|
||||
public BeatmapInfo BeatmapInfo
|
||||
public IBeatmapInfo BeatmapInfo
|
||||
{
|
||||
get => beatmapInfo;
|
||||
set
|
||||
@ -56,8 +56,11 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
beatmapInfo = value;
|
||||
|
||||
failTimes = beatmapInfo?.OnlineInfo?.FailTimes;
|
||||
ratings = beatmapInfo?.BeatmapSet?.OnlineInfo?.Ratings;
|
||||
var onlineInfo = beatmapInfo as IBeatmapOnlineInfo;
|
||||
var onlineSetInfo = beatmapInfo.BeatmapSet as IBeatmapSetOnlineInfo;
|
||||
|
||||
failTimes = onlineInfo?.FailTimes;
|
||||
ratings = onlineSetInfo?.Ratings;
|
||||
|
||||
Scheduler.AddOnce(updateStatistics);
|
||||
}
|
||||
@ -178,9 +181,9 @@ namespace osu.Game.Screens.Select
|
||||
private void updateStatistics()
|
||||
{
|
||||
advanced.BeatmapInfo = BeatmapInfo;
|
||||
description.Text = BeatmapInfo?.Version;
|
||||
source.Text = BeatmapInfo?.Metadata?.Source;
|
||||
tags.Text = BeatmapInfo?.Metadata?.Tags;
|
||||
description.Text = BeatmapInfo?.DifficultyName;
|
||||
source.Text = BeatmapInfo?.Metadata.Source;
|
||||
tags.Text = BeatmapInfo?.Metadata.Tags;
|
||||
|
||||
// failTimes may have been previously fetched
|
||||
if (ratings != null && failTimes != null)
|
||||
@ -190,7 +193,7 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
// for now, let's early abort if an OnlineBeatmapID is not present (should have been populated at import time).
|
||||
if (BeatmapInfo?.OnlineBeatmapID == null || api.State.Value == APIState.Offline)
|
||||
if (BeatmapInfo == null || BeatmapInfo.OnlineID <= 0 || api.State.Value == APIState.Offline)
|
||||
{
|
||||
updateMetrics();
|
||||
return;
|
||||
|
@ -27,9 +27,8 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = new BufferedContainer
|
||||
InternalChild = new BufferedContainer(cachedFrameBuffer: true)
|
||||
{
|
||||
CacheDrawnFrameBuffer = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
return string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.Author:
|
||||
return string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase);
|
||||
return string.Compare(BeatmapSet.Metadata.Author?.Username, otherSet.BeatmapSet.Metadata.Author?.Username, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
case SortMode.Source:
|
||||
return string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase);
|
||||
|
@ -142,7 +142,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author.Username}",
|
||||
Text = $"{(beatmapInfo.Metadata ?? beatmapInfo.BeatmapSet.Metadata).Author?.Username ?? string.Empty}",
|
||||
Font = OsuFont.GetFont(italics: true),
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft
|
||||
|
@ -15,8 +15,8 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
public class SetPanelBackground : BufferedContainer
|
||||
{
|
||||
public SetPanelBackground(WorkingBeatmap working)
|
||||
: base(cachedFrameBuffer: true)
|
||||
{
|
||||
CacheDrawnFrameBuffer = true;
|
||||
RedrawOnScale = false;
|
||||
|
||||
Children = new Drawable[]
|
||||
|
@ -70,14 +70,16 @@ namespace osu.Game.Skinning.Editor
|
||||
if (anchor.HasFlagFast(Anchor.x1)) scale.X = 0;
|
||||
if (anchor.HasFlagFast(Anchor.y1)) scale.Y = 0;
|
||||
|
||||
bool shouldAspectLock =
|
||||
// for now aspect lock scale adjustments that occur at corners..
|
||||
(!anchor.HasFlagFast(Anchor.x1) && !anchor.HasFlagFast(Anchor.y1))
|
||||
// ..or if any of the selection have been rotated.
|
||||
// this is to avoid requiring skew logic (which would likely not be the user's expected transform anyway).
|
||||
|| SelectedBlueprints.Any(b => !Precision.AlmostEquals(((Drawable)b.Item).Rotation, 0));
|
||||
|
||||
if (shouldAspectLock)
|
||||
// for now aspect lock scale adjustments that occur at corners..
|
||||
if (!anchor.HasFlagFast(Anchor.x1) && !anchor.HasFlagFast(Anchor.y1))
|
||||
{
|
||||
// project scale vector along diagonal
|
||||
Vector2 diag = (selectionRect.TopLeft - selectionRect.BottomRight).Normalized();
|
||||
scale = Vector2.Dot(scale, diag) * diag;
|
||||
}
|
||||
// ..or if any of the selection have been rotated.
|
||||
// this is to avoid requiring skew logic (which would likely not be the user's expected transform anyway).
|
||||
else if (SelectedBlueprints.Any(b => !Precision.AlmostEquals(((Drawable)b.Item).Rotation, 0)))
|
||||
{
|
||||
if (anchor.HasFlagFast(Anchor.x1))
|
||||
// if dragging from the horizontal centre, only a vertical component is available.
|
||||
|
@ -77,10 +77,14 @@ namespace osu.Game.Storyboards
|
||||
{
|
||||
get
|
||||
{
|
||||
string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile?.ToLowerInvariant();
|
||||
if (backgroundPath == null)
|
||||
string backgroundPath = BeatmapInfo.BeatmapSet?.Metadata?.BackgroundFile;
|
||||
|
||||
if (string.IsNullOrEmpty(backgroundPath))
|
||||
return false;
|
||||
|
||||
// Importantly, do this after the NullOrEmpty because EF may have stored the non-nullable value as null to the database, bypassing compile-time constraints.
|
||||
backgroundPath = backgroundPath.ToLowerInvariant();
|
||||
|
||||
return GetLayer("Background").Elements.Any(e => e.Path.ToLowerInvariant() == backgroundPath);
|
||||
}
|
||||
}
|
||||
@ -93,7 +97,7 @@ namespace osu.Game.Storyboards
|
||||
Drawable drawable = null;
|
||||
string storyboardPath = BeatmapInfo.BeatmapSet?.Files.Find(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.FileInfo.StoragePath;
|
||||
|
||||
if (storyboardPath != null)
|
||||
if (!string.IsNullOrEmpty(storyboardPath))
|
||||
drawable = new Sprite { Texture = textureStore.Get(storyboardPath) };
|
||||
// if the texture isn't available locally in the beatmap, some storyboards choose to source from the underlying skin lookup hierarchy.
|
||||
else if (UseSkinSprites)
|
||||
|
@ -39,16 +39,6 @@ namespace osu.Game.Tests.Beatmaps
|
||||
BeatmapInfo.Length = 75000;
|
||||
BeatmapInfo.OnlineInfo = new APIBeatmap();
|
||||
BeatmapInfo.OnlineBeatmapID = Interlocked.Increment(ref onlineBeatmapID);
|
||||
BeatmapInfo.BeatmapSet.OnlineInfo = new APIBeatmapSet
|
||||
{
|
||||
Status = BeatmapSetOnlineStatus.Ranked,
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/163112/covers/cover.jpg",
|
||||
Card = "https://assets.ppy.sh/beatmaps/163112/covers/card.jpg",
|
||||
List = "https://assets.ppy.sh/beatmaps/163112/covers/list.jpg"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected virtual Beatmap CreateBeatmap() => createTestBeatmap();
|
||||
|
@ -13,6 +13,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
using osu.Game.Online.Rooms;
|
||||
@ -265,18 +266,24 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
||||
return ((IMultiplayerClient)this).LoadRequested();
|
||||
}
|
||||
|
||||
protected override Task<BeatmapSetInfo> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
|
||||
protected override Task<APIBeatmapSet> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Debug.Assert(Room != null);
|
||||
|
||||
var apiRoom = roomManager.ServerSideRooms.Single(r => r.RoomID.Value == Room.RoomID);
|
||||
var set = apiRoom.Playlist.FirstOrDefault(p => p.BeatmapID == beatmapId)?.Beatmap.Value.BeatmapSet
|
||||
?? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId)?.BeatmapSet;
|
||||
IBeatmapSetInfo? set = apiRoom.Playlist.FirstOrDefault(p => p.BeatmapID == beatmapId)?.Beatmap.Value.BeatmapSet
|
||||
?? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId)?.BeatmapSet;
|
||||
|
||||
if (set == null)
|
||||
throw new InvalidOperationException("Beatmap not found.");
|
||||
|
||||
return Task.FromResult(set);
|
||||
var apiSet = new APIBeatmapSet
|
||||
{
|
||||
OnlineID = set.OnlineID,
|
||||
Beatmaps = set.Beatmaps.Select(b => new APIBeatmap { OnlineID = b.OnlineID }).ToArray(),
|
||||
};
|
||||
|
||||
return Task.FromResult(apiSet);
|
||||
}
|
||||
|
||||
private async Task changeMatchType(MatchType type)
|
||||
|
@ -175,27 +175,42 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset);
|
||||
|
||||
protected APIBeatmapSet CreateAPIBeatmapSet(RulesetInfo ruleset)
|
||||
/// <summary>
|
||||
/// Returns a sample API Beatmap with BeatmapSet populated.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The ruleset to create the sample model using. osu! ruleset will be used if not specified.</param>
|
||||
protected APIBeatmap CreateAPIBeatmap(RulesetInfo ruleset = null)
|
||||
{
|
||||
var beatmap = CreateBeatmap(ruleset).BeatmapInfo;
|
||||
var beatmapSet = CreateAPIBeatmapSet(ruleset ?? Ruleset.Value);
|
||||
|
||||
// Avoid circular reference.
|
||||
var beatmap = beatmapSet.Beatmaps.First();
|
||||
beatmapSet.Beatmaps = Array.Empty<APIBeatmap>();
|
||||
|
||||
// Populate the set as that's generally what we expect from the API.
|
||||
beatmap.BeatmapSet = beatmapSet;
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a sample API BeatmapSet with beatmaps populated.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The ruleset to create the sample model using. osu! ruleset will be used if not specified.</param>
|
||||
protected APIBeatmapSet CreateAPIBeatmapSet(RulesetInfo ruleset = null)
|
||||
{
|
||||
var beatmap = CreateBeatmap(ruleset ?? Ruleset.Value).BeatmapInfo;
|
||||
|
||||
return new APIBeatmapSet
|
||||
{
|
||||
Covers = beatmap.BeatmapSet.Covers,
|
||||
OnlineID = beatmap.BeatmapSet.OnlineID,
|
||||
Status = beatmap.BeatmapSet.Status,
|
||||
Preview = beatmap.BeatmapSet.Preview,
|
||||
HasFavourited = beatmap.BeatmapSet.HasFavourited,
|
||||
PlayCount = beatmap.BeatmapSet.PlayCount,
|
||||
FavouriteCount = beatmap.BeatmapSet.FavouriteCount,
|
||||
BPM = beatmap.BeatmapSet.BPM,
|
||||
HasExplicitContent = beatmap.BeatmapSet.HasExplicitContent,
|
||||
HasVideo = beatmap.BeatmapSet.HasVideo,
|
||||
HasStoryboard = beatmap.BeatmapSet.HasStoryboard,
|
||||
Submitted = beatmap.BeatmapSet.Submitted,
|
||||
Ranked = beatmap.BeatmapSet.Ranked,
|
||||
LastUpdated = beatmap.BeatmapSet.LastUpdated,
|
||||
TrackId = beatmap.BeatmapSet.TrackId,
|
||||
Status = BeatmapSetOnlineStatus.Ranked,
|
||||
Covers = new BeatmapSetOnlineCovers
|
||||
{
|
||||
Cover = "https://assets.ppy.sh/beatmaps/163112/covers/cover.jpg",
|
||||
Card = "https://assets.ppy.sh/beatmaps/163112/covers/card.jpg",
|
||||
List = "https://assets.ppy.sh/beatmaps/163112/covers/list.jpg"
|
||||
},
|
||||
Title = beatmap.BeatmapSet.Metadata.Title,
|
||||
TitleUnicode = beatmap.BeatmapSet.Metadata.TitleUnicode,
|
||||
Artist = beatmap.BeatmapSet.Metadata.Artist,
|
||||
@ -203,9 +218,6 @@ namespace osu.Game.Tests.Visual
|
||||
Author = beatmap.BeatmapSet.Metadata.Author,
|
||||
AuthorID = beatmap.BeatmapSet.Metadata.AuthorID,
|
||||
AuthorString = beatmap.BeatmapSet.Metadata.AuthorString,
|
||||
Availability = beatmap.BeatmapSet.Availability,
|
||||
Genre = beatmap.BeatmapSet.Genre,
|
||||
Language = beatmap.BeatmapSet.Language,
|
||||
Source = beatmap.BeatmapSet.Metadata.Source,
|
||||
Tags = beatmap.BeatmapSet.Metadata.Tags,
|
||||
Beatmaps = new[]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user