mirror of
https://github.com/ppy/osu.git
synced 2025-02-08 09:42:55 +08:00
Merge branch 'master' into friend-notification-samples
This commit is contained in:
commit
9db8e0b7ac
@ -14,6 +14,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Rulesets.Catch.Beatmaps;
|
using osu.Game.Rulesets.Catch.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Difficulty;
|
using osu.Game.Rulesets.Catch.Difficulty;
|
||||||
using osu.Game.Rulesets.Catch.Edit;
|
using osu.Game.Rulesets.Catch.Edit;
|
||||||
|
using osu.Game.Rulesets.Catch.Edit.Setup;
|
||||||
using osu.Game.Rulesets.Catch.Mods;
|
using osu.Game.Rulesets.Catch.Mods;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
@ -228,7 +229,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
public override IEnumerable<Drawable> CreateEditorSetupSections() =>
|
public override IEnumerable<Drawable> CreateEditorSetupSections() =>
|
||||||
[
|
[
|
||||||
new MetadataSection(),
|
new MetadataSection(),
|
||||||
new DifficultySection(),
|
new CatchDifficultySection(),
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
|
125
osu.Game.Rulesets.Catch/Edit/Setup/CatchDifficultySection.cs
Normal file
125
osu.Game.Rulesets.Catch/Edit/Setup/CatchDifficultySection.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Edit.Setup
|
||||||
|
{
|
||||||
|
public partial class CatchDifficultySection : SetupSection
|
||||||
|
{
|
||||||
|
private FormSliderBar<float> circleSizeSlider { get; set; } = null!;
|
||||||
|
private FormSliderBar<float> healthDrainSlider { get; set; } = null!;
|
||||||
|
private FormSliderBar<float> approachRateSlider { get; set; } = null!;
|
||||||
|
private FormSliderBar<double> baseVelocitySlider { get; set; } = null!;
|
||||||
|
private FormSliderBar<double> tickRateSlider { get; set; } = null!;
|
||||||
|
|
||||||
|
public override LocalisableString Title => EditorSetupStrings.DifficultyHeader;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
circleSizeSlider = new FormSliderBar<float>
|
||||||
|
{
|
||||||
|
Caption = BeatmapsetsStrings.ShowStatsCs,
|
||||||
|
HintText = EditorSetupStrings.CircleSizeDescription,
|
||||||
|
Current = new BindableFloat(Beatmap.Difficulty.CircleSize)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
},
|
||||||
|
TransferValueOnCommit = true,
|
||||||
|
TabbableContentContainer = this,
|
||||||
|
},
|
||||||
|
healthDrainSlider = new FormSliderBar<float>
|
||||||
|
{
|
||||||
|
Caption = BeatmapsetsStrings.ShowStatsDrain,
|
||||||
|
HintText = EditorSetupStrings.DrainRateDescription,
|
||||||
|
Current = new BindableFloat(Beatmap.Difficulty.DrainRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
},
|
||||||
|
TransferValueOnCommit = true,
|
||||||
|
TabbableContentContainer = this,
|
||||||
|
},
|
||||||
|
approachRateSlider = new FormSliderBar<float>
|
||||||
|
{
|
||||||
|
Caption = BeatmapsetsStrings.ShowStatsAr,
|
||||||
|
HintText = EditorSetupStrings.ApproachRateDescription,
|
||||||
|
Current = new BindableFloat(Beatmap.Difficulty.ApproachRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
},
|
||||||
|
TransferValueOnCommit = true,
|
||||||
|
TabbableContentContainer = this,
|
||||||
|
},
|
||||||
|
baseVelocitySlider = new FormSliderBar<double>
|
||||||
|
{
|
||||||
|
Caption = EditorSetupStrings.BaseVelocity,
|
||||||
|
HintText = EditorSetupStrings.BaseVelocityDescription,
|
||||||
|
Current = new BindableDouble(Beatmap.Difficulty.SliderMultiplier)
|
||||||
|
{
|
||||||
|
Default = 1.4,
|
||||||
|
MinValue = 0.4,
|
||||||
|
MaxValue = 3.6,
|
||||||
|
Precision = 0.01f,
|
||||||
|
},
|
||||||
|
TransferValueOnCommit = true,
|
||||||
|
TabbableContentContainer = this,
|
||||||
|
},
|
||||||
|
tickRateSlider = new FormSliderBar<double>
|
||||||
|
{
|
||||||
|
Caption = EditorSetupStrings.TickRate,
|
||||||
|
HintText = EditorSetupStrings.TickRateDescription,
|
||||||
|
Current = new BindableDouble(Beatmap.Difficulty.SliderTickRate)
|
||||||
|
{
|
||||||
|
Default = 1,
|
||||||
|
MinValue = 1,
|
||||||
|
MaxValue = 4,
|
||||||
|
Precision = 1,
|
||||||
|
},
|
||||||
|
TransferValueOnCommit = true,
|
||||||
|
TabbableContentContainer = this,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var item in Children.OfType<FormSliderBar<float>>())
|
||||||
|
item.Current.ValueChanged += _ => updateValues();
|
||||||
|
|
||||||
|
foreach (var item in Children.OfType<FormSliderBar<double>>())
|
||||||
|
item.Current.ValueChanged += _ => updateValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues()
|
||||||
|
{
|
||||||
|
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
||||||
|
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
||||||
|
Beatmap.Difficulty.CircleSize = circleSizeSlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.ApproachRate = approachRateSlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.SliderMultiplier = baseVelocitySlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.SliderTickRate = tickRateSlider.Current.Value;
|
||||||
|
|
||||||
|
Beatmap.UpdateAllHitObjects();
|
||||||
|
Beatmap.SaveState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
protected void SortBy(FilterCriteria criteria) => AddStep($"sort by {criteria.Sort}", () => Carousel.Filter(criteria));
|
protected void SortBy(FilterCriteria criteria) => AddStep($"sort by {criteria.Sort}", () => Carousel.Filter(criteria));
|
||||||
|
|
||||||
protected void WaitForDrawablePanels() => AddUntilStep("drawable panels loaded", () => Carousel.ChildrenOfType<BeatmapCarouselPanel>().Count(), () => Is.GreaterThan(0));
|
protected void WaitForDrawablePanels() => AddUntilStep("drawable panels loaded", () => Carousel.ChildrenOfType<ICarouselPanel>().Count(), () => Is.GreaterThan(0));
|
||||||
protected void WaitForSorting() => AddUntilStep("sorting finished", () => Carousel.IsFiltering, () => Is.False);
|
protected void WaitForSorting() => AddUntilStep("sorting finished", () => Carousel.IsFiltering, () => Is.False);
|
||||||
protected void WaitForScrolling() => AddUntilStep("scroll finished", () => Scroll.Current, () => Is.EqualTo(Scroll.Target));
|
protected void WaitForScrolling() => AddUntilStep("scroll finished", () => Scroll.Current, () => Is.EqualTo(Scroll.Target));
|
||||||
|
|
||||||
|
@ -56,16 +56,16 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
WaitForDrawablePanels();
|
WaitForDrawablePanels();
|
||||||
|
|
||||||
AddStep("select middle beatmap", () => Carousel.CurrentSelection = BeatmapSets.ElementAt(BeatmapSets.Count - 2));
|
AddStep("select middle beatmap", () => Carousel.CurrentSelection = BeatmapSets.ElementAt(BeatmapSets.Count - 2));
|
||||||
AddStep("scroll to selected item", () => Scroll.ScrollTo(Scroll.ChildrenOfType<BeatmapCarouselPanel>().Single(p => p.Selected.Value)));
|
AddStep("scroll to selected item", () => Scroll.ScrollTo(Scroll.ChildrenOfType<BeatmapPanel>().Single(p => p.Selected.Value)));
|
||||||
|
|
||||||
WaitForScrolling();
|
WaitForScrolling();
|
||||||
|
|
||||||
AddStep("save selected screen position", () => positionBefore = Carousel.ChildrenOfType<BeatmapCarouselPanel>().FirstOrDefault(p => p.Selected.Value)!.ScreenSpaceDrawQuad);
|
AddStep("save selected screen position", () => positionBefore = Carousel.ChildrenOfType<BeatmapPanel>().FirstOrDefault(p => p.Selected.Value)!.ScreenSpaceDrawQuad);
|
||||||
|
|
||||||
RemoveFirstBeatmap();
|
RemoveFirstBeatmap();
|
||||||
WaitForSorting();
|
WaitForSorting();
|
||||||
|
|
||||||
AddAssert("select screen position unchanged", () => Carousel.ChildrenOfType<BeatmapCarouselPanel>().Single(p => p.Selected.Value).ScreenSpaceDrawQuad,
|
AddAssert("select screen position unchanged", () => Carousel.ChildrenOfType<BeatmapPanel>().Single(p => p.Selected.Value).ScreenSpaceDrawQuad,
|
||||||
() => Is.EqualTo(positionBefore));
|
() => Is.EqualTo(positionBefore));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,11 +83,11 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
WaitForScrolling();
|
WaitForScrolling();
|
||||||
|
|
||||||
AddStep("save selected screen position", () => positionBefore = Carousel.ChildrenOfType<BeatmapCarouselPanel>().FirstOrDefault(p => p.Selected.Value)!.ScreenSpaceDrawQuad);
|
AddStep("save selected screen position", () => positionBefore = Carousel.ChildrenOfType<BeatmapPanel>().FirstOrDefault(p => p.Selected.Value)!.ScreenSpaceDrawQuad);
|
||||||
|
|
||||||
RemoveFirstBeatmap();
|
RemoveFirstBeatmap();
|
||||||
WaitForSorting();
|
WaitForSorting();
|
||||||
AddAssert("select screen position unchanged", () => Carousel.ChildrenOfType<BeatmapCarouselPanel>().Single(p => p.Selected.Value).ScreenSpaceDrawQuad,
|
AddAssert("select screen position unchanged", () => Carousel.ChildrenOfType<BeatmapPanel>().Single(p => p.Selected.Value).ScreenSpaceDrawQuad,
|
||||||
() => Is.EqualTo(positionBefore));
|
() => Is.EqualTo(positionBefore));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddUntilStep("drawable selection restored", () => getSelectedPanel()?.Item?.Model, () => Is.EqualTo(selection));
|
AddUntilStep("drawable selection restored", () => getSelectedPanel()?.Item?.Model, () => Is.EqualTo(selection));
|
||||||
AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
|
AddAssert("drawable selection matches carousel selection", () => selection, () => Is.EqualTo(Carousel.CurrentSelection));
|
||||||
|
|
||||||
BeatmapCarouselPanel? getSelectedPanel() => Carousel.ChildrenOfType<BeatmapCarouselPanel>().SingleOrDefault(p => p.Selected.Value);
|
BeatmapPanel? getSelectedPanel() => Carousel.ChildrenOfType<BeatmapPanel>().SingleOrDefault(p => p.Selected.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -292,7 +292,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
"1407228 II-L - VANGUARD-1.osz",
|
"1407228 II-L - VANGUARD-1.osz",
|
||||||
"1422686 II-L - VANGUARD-2.osz",
|
"1422686 II-L - VANGUARD-2.osz",
|
||||||
"1429217 Street - Phi.osz",
|
"1429217 Street - Phi.osz",
|
||||||
"1442235 2ToneDisco x Cosmicosmo - Shoelaces (feat. Puniden).osz",
|
"1442235 2ToneDisco x Cosmicosmo - Shoelaces (feat. Puniden).osz", // set is not marked as FA, but track is listed in https://osu.ppy.sh/beatmaps/artists/157
|
||||||
"1447478 Cres. - End Time.osz",
|
"1447478 Cres. - End Time.osz",
|
||||||
"1449942 m108 - Crescent Sakura.osz",
|
"1449942 m108 - Crescent Sakura.osz",
|
||||||
"1463778 MuryokuP - A tree without a branch.osz",
|
"1463778 MuryokuP - A tree without a branch.osz",
|
||||||
@ -336,8 +336,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
"1854710 Blaster & Extra Terra - Spacecraft (Cut Ver.).osz",
|
"1854710 Blaster & Extra Terra - Spacecraft (Cut Ver.).osz",
|
||||||
"1859322 Hino Isuka - Delightness Brightness.osz",
|
"1859322 Hino Isuka - Delightness Brightness.osz",
|
||||||
"1884102 Maduk - Go (feat. Lachi) (Cut Ver.).osz",
|
"1884102 Maduk - Go (feat. Lachi) (Cut Ver.).osz",
|
||||||
"1884578 Neko Hacker - People People feat. Nanahira.osz",
|
"1884578 Neko Hacker - People People feat. Nanahira.osz", // set is not marked as FA, but track is listed in https://osu.ppy.sh/beatmaps/artists/266
|
||||||
"1897902 uma vs. Morimori Atsushi - Re: End of a Dream.osz",
|
"1897902 uma vs. Morimori Atsushi - Re: End of a Dream.osz", // set is not marked as FA, but track is listed in https://osu.ppy.sh/beatmaps/artists/108
|
||||||
"1905582 KINEMA106 - Fly Away (Cut Ver.).osz",
|
"1905582 KINEMA106 - Fly Away (Cut Ver.).osz",
|
||||||
"1934686 ARForest - Rainbow Magic!!.osz",
|
"1934686 ARForest - Rainbow Magic!!.osz",
|
||||||
"1963076 METAROOM - S.N.U.F.F.Y.osz",
|
"1963076 METAROOM - S.N.U.F.F.Y.osz",
|
||||||
@ -345,7 +345,6 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
"1971951 James Landino - Shiba Paradise.osz",
|
"1971951 James Landino - Shiba Paradise.osz",
|
||||||
"1972518 Toromaru - Sleight of Hand.osz",
|
"1972518 Toromaru - Sleight of Hand.osz",
|
||||||
"1982302 KINEMA106 - INVITE.osz",
|
"1982302 KINEMA106 - INVITE.osz",
|
||||||
"1983475 KNOWER - The Government Knows.osz",
|
|
||||||
"2010165 Junk - Yellow Smile (bms edit).osz",
|
"2010165 Junk - Yellow Smile (bms edit).osz",
|
||||||
"2022737 Andora - Euphoria (feat. WaMi).osz",
|
"2022737 Andora - Euphoria (feat. WaMi).osz",
|
||||||
"2025023 tephe - Genjitsu Escape.osz",
|
"2025023 tephe - Genjitsu Escape.osz",
|
||||||
|
@ -9,6 +9,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.Toolkit.HighPerformance;
|
using Microsoft.Toolkit.HighPerformance;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using SharpCompress.Archives.Zip;
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
@ -54,12 +55,22 @@ namespace osu.Game.IO.Archives
|
|||||||
if (entry == null)
|
if (entry == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var owner = MemoryAllocator.Default.Allocate<byte>((int)entry.Size);
|
|
||||||
|
|
||||||
using (Stream s = entry.OpenEntryStream())
|
using (Stream s = entry.OpenEntryStream())
|
||||||
s.ReadExactly(owner.Memory.Span);
|
{
|
||||||
|
if (entry.Size > 0)
|
||||||
|
{
|
||||||
|
var owner = MemoryAllocator.Default.Allocate<byte>((int)entry.Size);
|
||||||
|
s.ReadExactly(owner.Memory.Span);
|
||||||
|
return new MemoryOwnerMemoryStream(owner);
|
||||||
|
}
|
||||||
|
|
||||||
return new MemoryOwnerMemoryStream(owner);
|
// due to a sharpcompress bug (https://github.com/adamhathcock/sharpcompress/issues/88),
|
||||||
|
// in rare instances the `ZipArchiveEntry` will not contain a correct `Size` but instead report 0.
|
||||||
|
// this would lead to the block above reading nothing, and the game basically seeing an archive full of empty files.
|
||||||
|
// since the bug is years old now, and this is a rather rare situation anyways (reported once in years),
|
||||||
|
// work around this locally by falling back to reading as many bytes as possible and using a standard non-pooled memory stream.
|
||||||
|
return new MemoryStream(s.ReadAllRemainingBytesToArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
|
@ -35,7 +35,8 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = GameplaySettingsStrings.LightenDuringBreaks,
|
LabelText = GameplaySettingsStrings.LightenDuringBreaks,
|
||||||
Current = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks)
|
Current = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks),
|
||||||
|
Keywords = new[] { "dim", "level" }
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
@ -97,7 +98,17 @@ namespace osu.Game.Screens.Edit.Setup
|
|||||||
if (!source.Exists)
|
if (!source.Exists)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var tagSource = TagLib.File.Create(source.FullName);
|
TagLib.File? tagSource;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tagSource = TagLib.File.Create(source.FullName);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, "The selected audio track appears to be corrupted. Please select another one.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
changeResource(source, applyToAllDifficulties, @"audio",
|
changeResource(source, applyToAllDifficulties, @"audio",
|
||||||
metadata => metadata.AudioFile,
|
metadata => metadata.AudioFile,
|
||||||
@ -192,16 +203,40 @@ namespace osu.Game.Screens.Edit.Setup
|
|||||||
editor?.Save();
|
editor?.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to avoid scaring users, both background & audio choosers use fake `FileInfo`s with user-friendly filenames
|
||||||
|
// when displaying an imported beatmap rather than the actual SHA-named file in storage.
|
||||||
|
// however, that means that when a background or audio file is chosen that is broken or doesn't exist on disk when switching away from the fake files,
|
||||||
|
// the rollback could enter an infinite loop, because the fake `FileInfo`s *also* don't exist on disk - at least not in the fake location they indicate.
|
||||||
|
// to circumvent this issue, just allow rollback to proceed always without actually running any of the change logic to ensure visual consistency.
|
||||||
|
// note that this means that `Change{BackgroundImage,AudioTrack}()` are required to not have made any modifications to the beatmap files
|
||||||
|
// (or at least cleaned them up properly themselves) if they return `false`.
|
||||||
|
private bool rollingBackBackgroundChange;
|
||||||
|
private bool rollingBackAudioChange;
|
||||||
|
|
||||||
private void backgroundChanged(ValueChangedEvent<FileInfo?> file)
|
private void backgroundChanged(ValueChangedEvent<FileInfo?> file)
|
||||||
{
|
{
|
||||||
|
if (rollingBackBackgroundChange)
|
||||||
|
return;
|
||||||
|
|
||||||
if (file.NewValue == null || !ChangeBackgroundImage(file.NewValue, backgroundChooser.ApplyToAllDifficulties.Value))
|
if (file.NewValue == null || !ChangeBackgroundImage(file.NewValue, backgroundChooser.ApplyToAllDifficulties.Value))
|
||||||
|
{
|
||||||
|
rollingBackBackgroundChange = true;
|
||||||
backgroundChooser.Current.Value = file.OldValue;
|
backgroundChooser.Current.Value = file.OldValue;
|
||||||
|
rollingBackBackgroundChange = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void audioTrackChanged(ValueChangedEvent<FileInfo?> file)
|
private void audioTrackChanged(ValueChangedEvent<FileInfo?> file)
|
||||||
{
|
{
|
||||||
|
if (rollingBackAudioChange)
|
||||||
|
return;
|
||||||
|
|
||||||
if (file.NewValue == null || !ChangeAudioTrack(file.NewValue, audioTrackChooser.ApplyToAllDifficulties.Value))
|
if (file.NewValue == null || !ChangeAudioTrack(file.NewValue, audioTrackChooser.ApplyToAllDifficulties.Value))
|
||||||
|
{
|
||||||
|
rollingBackAudioChange = true;
|
||||||
audioTrackChooser.Current.Value = file.OldValue;
|
audioTrackChooser.Current.Value = file.OldValue;
|
||||||
|
rollingBackAudioChange = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,14 +141,28 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
|
|
||||||
#region Drawable pooling
|
#region Drawable pooling
|
||||||
|
|
||||||
private readonly DrawablePool<BeatmapCarouselPanel> carouselPanelPool = new DrawablePool<BeatmapCarouselPanel>(100);
|
private readonly DrawablePool<BeatmapPanel> beatmapPanelPool = new DrawablePool<BeatmapPanel>(100);
|
||||||
|
private readonly DrawablePool<BeatmapSetPanel> setPanelPool = new DrawablePool<BeatmapSetPanel>(100);
|
||||||
|
|
||||||
private void setupPools()
|
private void setupPools()
|
||||||
{
|
{
|
||||||
AddInternal(carouselPanelPool);
|
AddInternal(beatmapPanelPool);
|
||||||
|
AddInternal(setPanelPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable GetDrawableForDisplay(CarouselItem item) => carouselPanelPool.Get();
|
protected override Drawable GetDrawableForDisplay(CarouselItem item)
|
||||||
|
{
|
||||||
|
switch (item.Model)
|
||||||
|
{
|
||||||
|
case BeatmapInfo:
|
||||||
|
return beatmapPanelPool.Get();
|
||||||
|
|
||||||
|
case BeatmapSetInfo:
|
||||||
|
return setPanelPool.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
{
|
{
|
||||||
newItems.Add(new CarouselItem(b.BeatmapSet!)
|
newItems.Add(new CarouselItem(b.BeatmapSet!)
|
||||||
{
|
{
|
||||||
DrawHeight = 80,
|
DrawHeight = BeatmapSetPanel.HEIGHT,
|
||||||
IsGroupSelectionTarget = true
|
IsGroupSelectionTarget = true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -16,22 +16,25 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.SelectV2
|
namespace osu.Game.Screens.SelectV2
|
||||||
{
|
{
|
||||||
public partial class BeatmapCarouselPanel : PoolableDrawable, ICarouselPanel
|
public partial class BeatmapPanel : PoolableDrawable, ICarouselPanel
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapCarousel carousel { get; set; } = null!;
|
private BeatmapCarousel carousel { get; set; } = null!;
|
||||||
|
|
||||||
private Box activationFlash = null!;
|
private Box activationFlash = null!;
|
||||||
private Box background = null!;
|
|
||||||
private OsuSpriteText text = null!;
|
private OsuSpriteText text = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
Size = new Vector2(500, CarouselItem.DEFAULT_HEIGHT);
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
background = new Box
|
new Box
|
||||||
{
|
{
|
||||||
|
Colour = Color4.Aqua.Darken(5),
|
||||||
Alpha = 0.8f,
|
Alpha = 0.8f,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
@ -69,63 +72,40 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FreeAfterUse()
|
|
||||||
{
|
|
||||||
base.FreeAfterUse();
|
|
||||||
Item = null;
|
|
||||||
Selected.Value = false;
|
|
||||||
KeyboardSelected.Value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PrepareForUse()
|
protected override void PrepareForUse()
|
||||||
{
|
{
|
||||||
base.PrepareForUse();
|
base.PrepareForUse();
|
||||||
|
|
||||||
Debug.Assert(Item != null);
|
Debug.Assert(Item != null);
|
||||||
|
var beatmap = (BeatmapInfo)Item.Model;
|
||||||
|
|
||||||
DrawYPosition = Item.CarouselYPosition;
|
text.Text = $"Difficulty: {beatmap.DifficultyName} ({beatmap.StarRating:N1}*)";
|
||||||
|
|
||||||
Size = new Vector2(500, Item.DrawHeight);
|
|
||||||
Masking = true;
|
|
||||||
|
|
||||||
background.Colour = (Item.Model is BeatmapInfo ? Color4.Aqua : Color4.Yellow).Darken(5);
|
|
||||||
text.Text = getTextFor(Item.Model);
|
|
||||||
|
|
||||||
this.FadeInFromZero(500, Easing.OutQuint);
|
this.FadeInFromZero(500, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getTextFor(object item)
|
|
||||||
{
|
|
||||||
switch (item)
|
|
||||||
{
|
|
||||||
case BeatmapInfo bi:
|
|
||||||
return $"Difficulty: {bi.DifficultyName} ({bi.StarRating:N1}*)";
|
|
||||||
|
|
||||||
case BeatmapSetInfo si:
|
|
||||||
return $"{si.Metadata}";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
if (carousel.CurrentSelection == Item!.Model)
|
if (carousel.CurrentSelection != Item!.Model)
|
||||||
carousel.TryActivateSelection();
|
{
|
||||||
else
|
|
||||||
carousel.CurrentSelection = Item!.Model;
|
carousel.CurrentSelection = Item!.Model;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
carousel.TryActivateSelection();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region ICarouselPanel
|
||||||
|
|
||||||
public CarouselItem? Item { get; set; }
|
public CarouselItem? Item { get; set; }
|
||||||
public BindableBool Selected { get; } = new BindableBool();
|
public BindableBool Selected { get; } = new BindableBool();
|
||||||
public BindableBool KeyboardSelected { get; } = new BindableBool();
|
public BindableBool KeyboardSelected { get; } = new BindableBool();
|
||||||
|
|
||||||
public double DrawYPosition { get; set; }
|
public double DrawYPosition { get; set; }
|
||||||
|
|
||||||
public void Activated()
|
public void Activated() => activationFlash.FadeOutFromOne(500, Easing.OutQuint);
|
||||||
{
|
|
||||||
activationFlash.FadeOutFromOne(500, Easing.OutQuint);
|
#endregion
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
101
osu.Game/Screens/SelectV2/BeatmapSetPanel.cs
Normal file
101
osu.Game/Screens/SelectV2/BeatmapSetPanel.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// 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.Diagnostics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Pooling;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.SelectV2
|
||||||
|
{
|
||||||
|
public partial class BeatmapSetPanel : PoolableDrawable, ICarouselPanel
|
||||||
|
{
|
||||||
|
public const float HEIGHT = CarouselItem.DEFAULT_HEIGHT * 2;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapCarousel carousel { get; set; } = null!;
|
||||||
|
|
||||||
|
private OsuSpriteText text = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Size = new Vector2(500, HEIGHT);
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.Yellow.Darken(5),
|
||||||
|
Alpha = 0.8f,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding(5),
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
KeyboardSelected.BindValueChanged(value =>
|
||||||
|
{
|
||||||
|
if (value.NewValue)
|
||||||
|
{
|
||||||
|
BorderThickness = 5;
|
||||||
|
BorderColour = Color4.Pink;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BorderThickness = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PrepareForUse()
|
||||||
|
{
|
||||||
|
base.PrepareForUse();
|
||||||
|
|
||||||
|
Debug.Assert(Item != null);
|
||||||
|
Debug.Assert(Item.IsGroupSelectionTarget);
|
||||||
|
|
||||||
|
var beatmapSetInfo = (BeatmapSetInfo)Item.Model;
|
||||||
|
|
||||||
|
text.Text = $"{beatmapSetInfo.Metadata}";
|
||||||
|
|
||||||
|
this.FadeInFromZero(500, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnClick(ClickEvent e)
|
||||||
|
{
|
||||||
|
carousel.CurrentSelection = Item!.Model;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region ICarouselPanel
|
||||||
|
|
||||||
|
public CarouselItem? Item { get; set; }
|
||||||
|
public BindableBool Selected { get; } = new BindableBool();
|
||||||
|
public BindableBool KeyboardSelected { get; } = new BindableBool();
|
||||||
|
|
||||||
|
public double DrawYPosition { get; set; }
|
||||||
|
|
||||||
|
public void Activated()
|
||||||
|
{
|
||||||
|
// sets should never be activated.
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -540,11 +540,13 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
{
|
{
|
||||||
var c = (ICarouselPanel)panel;
|
var c = (ICarouselPanel)panel;
|
||||||
|
|
||||||
|
// panel in the process of expiring, ignore it.
|
||||||
|
if (c.Item == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (panel.Depth != c.DrawYPosition)
|
if (panel.Depth != c.DrawYPosition)
|
||||||
scroll.Panels.ChangeChildDepth(panel, (float)c.DrawYPosition);
|
scroll.Panels.ChangeChildDepth(panel, (float)c.DrawYPosition);
|
||||||
|
|
||||||
Debug.Assert(c.Item != null);
|
|
||||||
|
|
||||||
if (c.DrawYPosition != c.Item.CarouselYPosition)
|
if (c.DrawYPosition != c.Item.CarouselYPosition)
|
||||||
c.DrawYPosition = Interpolation.DampContinuously(c.DrawYPosition, c.Item.CarouselYPosition, 50, Time.Elapsed);
|
c.DrawYPosition = Interpolation.DampContinuously(c.DrawYPosition, c.Item.CarouselYPosition, 50, Time.Elapsed);
|
||||||
|
|
||||||
@ -631,7 +633,9 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
if (drawable is not ICarouselPanel carouselPanel)
|
if (drawable is not ICarouselPanel carouselPanel)
|
||||||
throw new InvalidOperationException($"Carousel panel drawables must implement {typeof(ICarouselPanel)}");
|
throw new InvalidOperationException($"Carousel panel drawables must implement {typeof(ICarouselPanel)}");
|
||||||
|
|
||||||
|
carouselPanel.DrawYPosition = item.CarouselYPosition;
|
||||||
carouselPanel.Item = item;
|
carouselPanel.Item = item;
|
||||||
|
|
||||||
scroll.Add(drawable);
|
scroll.Add(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,6 +654,12 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
{
|
{
|
||||||
panel.FinishTransforms();
|
panel.FinishTransforms();
|
||||||
panel.Expire();
|
panel.Expire();
|
||||||
|
|
||||||
|
var carouselPanel = (ICarouselPanel)panel;
|
||||||
|
|
||||||
|
carouselPanel.Item = null;
|
||||||
|
carouselPanel.Selected.Value = false;
|
||||||
|
carouselPanel.KeyboardSelected.Value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -153,6 +153,8 @@
|
|||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.music-games</string>
|
<string>public.app-category.music-games</string>
|
||||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
Loading…
Reference in New Issue
Block a user