mirror of
https://github.com/SK-la/Ez2Lazer.git
synced 2026-03-13 11:20:28 +00:00
同步更新,并增加一些TODO
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2025.1209.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2025.1229.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||
|
||||
@@ -50,7 +50,6 @@ using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Edit.Setup;
|
||||
using osu.Game.Screens.Ranking.Statistics;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania
|
||||
{
|
||||
|
||||
@@ -175,6 +175,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
||||
{
|
||||
switch (hitMode)
|
||||
{
|
||||
// TODO: 判定值应该调整,太松了
|
||||
case EzMUGHitMode.O2Jam:
|
||||
if (bpm == 0) bpm = 200;
|
||||
double coolRange = 7500.0 / bpm;
|
||||
|
||||
@@ -13,7 +13,6 @@ using osu.Game.LAsEzExtensions.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Configuration;
|
||||
using osu.Game.Rulesets.Mania.Skinning;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
|
||||
|
||||
@@ -322,7 +322,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
column.RegisterPool<NoComboBreakLNTail, MalodyDrawableLNTail>(10, 50);
|
||||
break;
|
||||
|
||||
// TODO: 暂时先用 EZ2AC 的物件池,以后根据使用反馈单独实现
|
||||
case EzMUGHitMode.IIDX:
|
||||
column.RegisterPool<NoMissLNBody, DrawableHoldNoteBody>(10, 50);
|
||||
column.RegisterPool<Ez2AcLNHead, DrawableHoldNoteHead>(10, 50);
|
||||
column.RegisterPool<NoMissLNBody, DrawableHoldNoteBody>(10, 50);
|
||||
column.RegisterPool<Ez2AcLNTail, Ez2AcDrawableLNTail>(10, 50);
|
||||
break;
|
||||
|
||||
@@ -379,6 +379,25 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
||||
checkMatchedBeatmaps(6);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestScopeToBeatmapWhenDifficultiesGroupedBySet()
|
||||
{
|
||||
ImportBeatmapForRuleset(0);
|
||||
ImportBeatmapForRuleset(0);
|
||||
|
||||
LoadSongSelect();
|
||||
SortBy(SortMode.Artist);
|
||||
checkMatchedBeatmaps(6);
|
||||
|
||||
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
|
||||
WaitForFiltering();
|
||||
checkMatchedBeatmaps(3);
|
||||
|
||||
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
||||
WaitForFiltering();
|
||||
checkMatchedBeatmaps(6);
|
||||
}
|
||||
|
||||
private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType<NoResultsPlaceholder>().FirstOrDefault();
|
||||
|
||||
private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected));
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
{
|
||||
FullName = { Value = @"Japan" },
|
||||
Acronym = { Value = "JPN" },
|
||||
Seed = { Value = "#28" },
|
||||
LastYearPlacing = { Value = "#17-24" },
|
||||
SeedingResults =
|
||||
{
|
||||
new SeedingResult
|
||||
@@ -36,20 +38,38 @@ namespace osu.Game.Tournament.Tests.Screens
|
||||
Seed = { Value = 8 }
|
||||
}
|
||||
}
|
||||
},
|
||||
new TournamentTeam
|
||||
{
|
||||
Acronym = { Value = "USA" },
|
||||
FlagName = { Value = "US" },
|
||||
FullName = { Value = "United States" },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[Test]
|
||||
public void TestBasic()
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddStep("create seeding screen", () => Add(new SeedingScreen
|
||||
Add(new SeedingScreen
|
||||
{
|
||||
FillMode = FillMode.Fit,
|
||||
FillAspectRatio = 16 / 9f
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
AddStep("set team to Japan", () => this.ChildrenOfType<SettingsTeamDropdown>().Single().Current.Value = ladder.Teams.Single());
|
||||
[Test]
|
||||
public void TestBasic()
|
||||
{
|
||||
AddStep("set team to Japan", () =>
|
||||
this.ChildrenOfType<SettingsTeamDropdown>().Single().Current.Value = ladder.Teams.Single(t => t.FullName.Value == "Japan"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoSeed()
|
||||
{
|
||||
AddStep("set team to USA", () =>
|
||||
this.ChildrenOfType<SettingsTeamDropdown>().Single().Current.Value = ladder.Teams.Single(t => t.FullName.Value == "United States"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace osu.Game.Tournament.Tests
|
||||
Acronym = { Value = "JPN" },
|
||||
FlagName = { Value = "JP" },
|
||||
FullName = { Value = "Japan" },
|
||||
LastYearPlacing = { Value = 10 },
|
||||
LastYearPlacing = { Value = "#10" },
|
||||
Seed = { Value = "#12" },
|
||||
SeedingResults =
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Bindables;
|
||||
@@ -49,11 +50,9 @@ namespace osu.Game.Tournament.Models
|
||||
|
||||
public Bindable<string> Seed = new Bindable<string>(string.Empty);
|
||||
|
||||
public Bindable<int> LastYearPlacing = new BindableInt
|
||||
{
|
||||
MinValue = 0,
|
||||
MaxValue = 256
|
||||
};
|
||||
[JsonProperty]
|
||||
[JsonConverter(typeof(LastYearPlacingConverter))]
|
||||
public Bindable<string> LastYearPlacing = new Bindable<string>(@"N/A");
|
||||
|
||||
[JsonProperty]
|
||||
public BindableList<TournamentUser> Players { get; } = new BindableList<TournamentUser>();
|
||||
@@ -76,5 +75,37 @@ namespace osu.Game.Tournament.Models
|
||||
}
|
||||
|
||||
public override string ToString() => FullName.Value ?? Acronym.Value;
|
||||
|
||||
public class LastYearPlacingConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => objectType == typeof(Bindable<string>);
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
=> serializer.Serialize(writer, ((Bindable<string>)value!).Value);
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var lastYearPlacing = existingValue as Bindable<string>;
|
||||
Debug.Assert(lastYearPlacing != null);
|
||||
|
||||
switch (reader.TokenType)
|
||||
{
|
||||
case JsonToken.String:
|
||||
lastYearPlacing.Value = (string?)reader.Value ?? lastYearPlacing.Default;
|
||||
break;
|
||||
|
||||
case JsonToken.Integer:
|
||||
long value = (long)reader.Value!;
|
||||
lastYearPlacing.Value = value > 0 ? $@"#{value}" : lastYearPlacing.Default;
|
||||
break;
|
||||
|
||||
default:
|
||||
reader.Read();
|
||||
break;
|
||||
}
|
||||
|
||||
return lastYearPlacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Tournament.Models;
|
||||
@@ -111,43 +109,43 @@ namespace osu.Game.Tournament.Screens.Editors
|
||||
new SettingsTextBox
|
||||
{
|
||||
LabelText = "Name",
|
||||
Width = 0.2f,
|
||||
Width = 0.33f,
|
||||
Current = Model.FullName
|
||||
},
|
||||
acronymTextBox = new SettingsTextBox
|
||||
{
|
||||
LabelText = "Acronym",
|
||||
Width = 0.2f,
|
||||
Width = 0.25f,
|
||||
Current = Model.Acronym
|
||||
},
|
||||
new SettingsTextBox
|
||||
{
|
||||
LabelText = "Flag",
|
||||
Width = 0.2f,
|
||||
Width = 0.25f,
|
||||
Current = Model.FlagName
|
||||
},
|
||||
new SettingsTextBox
|
||||
{
|
||||
LabelText = "Seed",
|
||||
Width = 0.2f,
|
||||
Current = Model.Seed
|
||||
},
|
||||
new SettingsSlider<int, LastYearPlacementSlider>
|
||||
{
|
||||
LabelText = "Last Year Placement",
|
||||
Width = 0.33f,
|
||||
Current = Model.LastYearPlacing
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Width = 0.2f,
|
||||
Margin = new MarginPadding(10),
|
||||
Width = 0.33f,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Text = "Edit seeding results",
|
||||
Action = () =>
|
||||
{
|
||||
sceneManager?.SetScreen(new SeedingEditorScreen(team, parent));
|
||||
}
|
||||
},
|
||||
new SettingsTextBox
|
||||
{
|
||||
LabelText = "Seed",
|
||||
Width = 0.25f,
|
||||
Current = Model.Seed
|
||||
},
|
||||
new SettingsTextBox
|
||||
{
|
||||
LabelText = "Last Year Placement",
|
||||
Width = 0.25f,
|
||||
Current = Model.LastYearPlacing
|
||||
},
|
||||
playerEditor,
|
||||
new SettingsButton
|
||||
{
|
||||
@@ -200,11 +198,6 @@ namespace osu.Game.Tournament.Screens.Editors
|
||||
}, true);
|
||||
}
|
||||
|
||||
private partial class LastYearPlacementSlider : RoundedSliderBar<int>
|
||||
{
|
||||
public override LocalisableString TooltipText => Current.Value == 0 ? "N/A" : base.TooltipText;
|
||||
}
|
||||
|
||||
public partial class PlayerEditor : CompositeDrawable
|
||||
{
|
||||
private readonly TournamentTeam team;
|
||||
|
||||
@@ -274,7 +274,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
|
||||
new TeamDisplay(team) { Margin = new MarginPadding { Bottom = 30 } },
|
||||
new RowDisplay("Average Rank:", $"#{team.AverageRank:#,0}"),
|
||||
new RowDisplay("Seed:", team.Seed.Value),
|
||||
new RowDisplay("Last year's placing:", team.LastYearPlacing.Value > 0 ? $"#{team.LastYearPlacing:#,0}" : "N/A"),
|
||||
new RowDisplay("Last year's placing:", team.LastYearPlacing.Value),
|
||||
new Container { Margin = new MarginPadding { Bottom = 30 } },
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +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.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum IntroSequence
|
||||
@@ -8,6 +11,8 @@ namespace osu.Game.Configuration
|
||||
Circles,
|
||||
Welcome,
|
||||
Triangles,
|
||||
|
||||
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.IntroRandom))]
|
||||
Random
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,11 +92,12 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Colour = dimColour;
|
||||
Enabled.BindValueChanged(_ => this.FadeColour(dimColour, 200, Easing.OutQuint));
|
||||
Colour = Enabled.Value ? Colour4.White : DimColour;
|
||||
Enabled.BindValueChanged(_ => this.FadeColour(DimColour, 200, Easing.OutQuint), true);
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
private Color4 dimColour => Enabled.Value ? Color4.White : colours.Gray9;
|
||||
protected virtual Colour4 DimColour => colours.Gray9;
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@@ -137,7 +138,7 @@ namespace osu.Game.LAsEzExtensions.Analysis
|
||||
Colour = colour ?? Colour4.White;
|
||||
}
|
||||
|
||||
protected override string DisplayValue(string? value)
|
||||
protected override LocalisableString DisplayValue(string? value)
|
||||
{
|
||||
return value ?? "N/A";
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString HitObjectsAppearEarlier => new TranslatableString(getKey(@"hit_objects_appear_earlier"), @"(hit objects appear earlier)");
|
||||
|
||||
/// <summary>
|
||||
/// "Beatmap offset was adjusted to {0} ms."
|
||||
/// </summary>
|
||||
public static LocalisableString BeatmapOffsetWasAdjustedTo(string offset) => new TranslatableString(getKey(@"beatmap_offset_was_adjusted_to"), @"Beatmap offset was adjusted to {0} ms.", offset);
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
||||
39
osu.Game/Localisation/RankingStatisticsStrings.cs
Normal file
39
osu.Game/Localisation/RankingStatisticsStrings.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class RankingStatisticsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.RankingStatisticsStrings";
|
||||
|
||||
/// <summary>
|
||||
/// "Average Hit Error"
|
||||
/// </summary>
|
||||
public static LocalisableString AverageHitErrorTitle => new TranslatableString(getKey(@"average_hit_error_title"), @"Average Hit Error");
|
||||
|
||||
/// <summary>
|
||||
/// "Unstable Rate"
|
||||
/// </summary>
|
||||
public static LocalisableString UnstableRateTitle => new TranslatableString(getKey(@"unstable_rate_title"), @"Unstable Rate");
|
||||
|
||||
/// <summary>
|
||||
/// "{0:N2} ms early"
|
||||
/// </summary>
|
||||
public static LocalisableString Early(double offset) => new TranslatableString(getKey(@"early"), @"{0:N2} ms early", offset);
|
||||
|
||||
/// <summary>
|
||||
/// "{0:N2} ms late"
|
||||
/// </summary>
|
||||
public static LocalisableString Late(double offset) => new TranslatableString(getKey(@"late"), @"{0:N2} ms late", offset);
|
||||
|
||||
/// <summary>
|
||||
/// "(not available)"
|
||||
/// </summary>
|
||||
public static LocalisableString NotAvailable => new TranslatableString(getKey(@"not_available"), @"(not available)");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"change the way osu! behaves");
|
||||
|
||||
/// <summary>
|
||||
/// "Copy version"
|
||||
/// </summary>
|
||||
public static LocalisableString CopyVersion => new TranslatableString(getKey(@"copy_version"), @"Copy version");
|
||||
|
||||
private static string getKey(string key) => $"{prefix}:{key}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,11 @@ namespace osu.Game.Localisation
|
||||
/// </summary>
|
||||
public static LocalisableString IntroSequence => new TranslatableString(getKey(@"intro_sequence"), @"Intro sequence");
|
||||
|
||||
/// <summary>
|
||||
/// "Random"
|
||||
/// </summary>
|
||||
public static LocalisableString IntroRandom => new TranslatableString(getKey(@"intro_random"), @"Random");
|
||||
|
||||
/// <summary>
|
||||
/// "Background source"
|
||||
/// </summary>
|
||||
|
||||
@@ -224,21 +224,27 @@ namespace osu.Game.Overlays
|
||||
};
|
||||
}
|
||||
|
||||
private double? lastSeekTime;
|
||||
private double? lastSeekGameTime;
|
||||
private double? lastSeekAudioTargetTime;
|
||||
|
||||
private void onSeek(double progress)
|
||||
{
|
||||
if (!musicController.IsPlaying || lastSeekTime == null || Time.Current - lastSeekTime > TRACK_DRAG_SEEK_DEBOUNCE)
|
||||
if (!musicController.IsPlaying || lastSeekGameTime == null || Time.Current - lastSeekGameTime > TRACK_DRAG_SEEK_DEBOUNCE)
|
||||
{
|
||||
musicController.SeekTo(progress);
|
||||
lastSeekTime = Time.Current;
|
||||
lastSeekGameTime = Time.Current;
|
||||
lastSeekAudioTargetTime = progress;
|
||||
}
|
||||
}
|
||||
|
||||
private void onCommit(double progress)
|
||||
{
|
||||
musicController.SeekTo(progress);
|
||||
lastSeekTime = null;
|
||||
// Avoid a second seek to the same location, which could occur when using keyboard navigation from `OnSeek` and subsequent `OnCommit` calls.
|
||||
if (progress != lastSeekAudioTargetTime)
|
||||
musicController.SeekTo(progress);
|
||||
|
||||
lastSeekGameTime = null;
|
||||
lastSeekAudioTargetTime = null;
|
||||
}
|
||||
|
||||
private void togglePlaylist()
|
||||
@@ -518,6 +524,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
private partial class HoverableProgressBar : ProgressBar
|
||||
{
|
||||
public override bool HandleNonPositionalInput => IsHovered;
|
||||
|
||||
public HoverableProgressBar()
|
||||
: base(true)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework;
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
LabelText = GraphicsSettingsStrings.FrameLimiter,
|
||||
Current = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync),
|
||||
Keywords = new[] { @"fps" },
|
||||
Keywords = new[] { @"fps", @"framerate" },
|
||||
},
|
||||
new SettingsEnumDropdown<ExecutionMode>
|
||||
{
|
||||
@@ -54,7 +54,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = GraphicsSettingsStrings.ShowFPS,
|
||||
Current = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay)
|
||||
Current = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay),
|
||||
Keywords = new[] { @"framerate", @"counter" },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
Height = 40,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
MatchingFilter = true,
|
||||
Text = "Save",
|
||||
Text = WebCommonStrings.ButtonsSave,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
@@ -116,7 +117,7 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuMenuItem("Copy version", MenuItemType.Standard, () => game?.CopyToClipboard(version))
|
||||
new OsuMenuItem(SettingsStrings.CopyVersion, MenuItemType.Standard, () => game?.CopyToClipboard(version))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace osu.Game.Overlays.SkinEditor
|
||||
},
|
||||
new SceneButton
|
||||
{
|
||||
Text = "Skin.ini(Null)",
|
||||
Text = "Mania Note Editor(Testing)",
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Action = () =>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes a mod time range that can be updated from editor timeline UI.
|
||||
/// All times are in milliseconds.
|
||||
/// 用于链接循环时间范围的Mod接口。
|
||||
/// 单位是ms。
|
||||
/// </summary>
|
||||
public interface ILoopTimeRangeMod
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates the time range represented by this mod.
|
||||
/// 更新循环时间范围。
|
||||
/// </summary>
|
||||
/// <param name="startTime">Start time in milliseconds.</param>
|
||||
/// <param name="endTime">End time in milliseconds.</param>
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
sample.AddAdjustment(AdjustableProperty.Frequency, SpeedChange);
|
||||
}
|
||||
|
||||
// 供override的速率调整使用
|
||||
public virtual double ApplyToRate(double time, double rate) => rate * SpeedChange.Value;
|
||||
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModTimeRamp), typeof(ModAdaptiveSpeed), typeof(ModRateAdjust) };
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// <summary>
|
||||
/// mania特殊专用,按键事件的未命中结果。
|
||||
/// 禁止用在Judgement覆写上,这不属于note返回的判定结果
|
||||
/// TODO: 这是一个错误拼写,为了突出这是一个临时解决方案。未来应当通过更好的方式实现可切换的空判机制,并改为正确的Poor。
|
||||
/// </summary>
|
||||
[Description(@"Pool")]
|
||||
[EnumMember(Value = "pool")]
|
||||
|
||||
@@ -17,7 +17,6 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
@@ -186,13 +185,13 @@ namespace osu.Game.Screens.Edit.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
// 默认范围:以当前活动光标为 A 起点,向后 8 个 1/4 节拍为 B 终点。
|
||||
// 8 * (1/4 beat) = 2 beats.
|
||||
// 默认范围:以当前活动光标为 A 起点,向后 设置 B 终点。
|
||||
double currentTime = Math.Clamp(editorClock.CurrentTime, 0, editorClock.TrackLength);
|
||||
|
||||
double startTime = editorClock.GetSnappedTime(currentTime);
|
||||
var timingPoint = editorClock.ControlPointInfo.TimingPointAt(startTime);
|
||||
|
||||
// 8 * (4/4 beat) = 8 beats.也就是8根白线。
|
||||
double endTime = startTime + timingPoint.BeatLength * 8;
|
||||
endTime = Math.Min(endTime, editorClock.TrackLength);
|
||||
endTime = editorClock.GetSnappedTime(endTime);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
||||
if (!base.ReceivePositionalInputAt(screenSpacePos))
|
||||
return false;
|
||||
|
||||
// Only allow interaction in the upper half of the timeline.
|
||||
// 改为只在上半部分响应交互,为了配合A-B Loop光标仅下半区的UI交互
|
||||
var localPos = ToLocalSpace(screenSpacePos);
|
||||
return localPos.Y < DrawHeight / 2;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.LAsEzExtensions.Configuration;
|
||||
using osu.Game.LAsEzExtensions.Screens.Edit;
|
||||
using osu.Game.Overlays;
|
||||
@@ -227,8 +226,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
|
||||
applied = true;
|
||||
}
|
||||
|
||||
// If the user returns to song select without restarting, the mod overlay may already be alive.
|
||||
// It only reacts to SelectedMods bindable value changes, so force a value update to propagate the changed settings.
|
||||
// 如果用户在不重启的情况下返回歌曲选择,Mod覆盖可能已经存在。
|
||||
// 它只对 SelectedMods 绑定值的更改做出反应,因此强制值更新以传播更改的设置。
|
||||
if (applied && mods is Bindable<IReadOnlyList<Mod>> writableMods)
|
||||
writableMods.Value = writableMods.Value.ToArray();
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ namespace osu.Game.Screens.Edit
|
||||
|
||||
this.beatDivisor = beatDivisor ?? new BindableBeatDivisor();
|
||||
|
||||
// The editor operates in raw beatmap time. Applying offsets here breaks seek/loop logic
|
||||
// (FramedBeatmapClock seeks in raw time but reports CurrentTime with offsets applied).
|
||||
// 编辑器使用谱面原始时间。若在此应用偏移会破坏寻迹/循环逻辑
|
||||
// (FramedBeatmapClock 在原始时间上进行寻迹,但报告的 CurrentTime 却应用了偏移)。
|
||||
underlyingClock = new FramedBeatmapClock(applyOffsets: false, requireDecoupling: true);
|
||||
AddInternal(underlyingClock);
|
||||
|
||||
@@ -85,8 +85,9 @@ namespace osu.Game.Screens.Edit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <paramref name="time"/> snapped to the currently configured editor beat divisor.
|
||||
/// This matches the displayed editor grid granularity.
|
||||
/// 这个方法返回根据当前编辑器节拍除数配置进行捕捉的<paramref name="time"/>。
|
||||
/// 对其到显示的编辑器网格粒度。
|
||||
/// TODO: 尽管如此,视觉上也依然难以发觉捕捉效果。最好在编辑器顶部的时间轴上同步显示光标位置。
|
||||
/// </summary>
|
||||
public double GetSnappedTime(double time)
|
||||
{
|
||||
|
||||
@@ -102,6 +102,7 @@ namespace osu.Game.Screens.Play
|
||||
private bool isRestarting;
|
||||
private bool skipExitTransition;
|
||||
|
||||
// 公开以供外部检查当前状态。
|
||||
public readonly Bindable<bool> StoryboardReplacesBackground = new Bindable<bool>();
|
||||
|
||||
public IBindable<bool> LocalUserPlaying => localUserPlaying;
|
||||
|
||||
@@ -330,7 +330,7 @@ namespace osu.Game.Screens.Play.PlayerSettings
|
||||
|
||||
if (offsetChanged)
|
||||
{
|
||||
offsetText.AddText($"Beatmap offset was adjusted to {Current.Value.ToStandardFormattedString(1)} ms.", t => t.Font = OsuFont.Style.Caption1);
|
||||
offsetText.AddText(BeatmapOffsetControlStrings.BeatmapOffsetWasAdjustedTo(Current.Value.ToStandardFormattedString(1)), t => t.Font = OsuFont.Style.Caption1);
|
||||
offsetText.NewParagraph();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Statistics
|
||||
{
|
||||
@@ -17,11 +19,19 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// </summary>
|
||||
/// <param name="hitEvents">Sequence of <see cref="HitEvent"/>s to calculate the unstable rate based on.</param>
|
||||
public AverageHitError(IEnumerable<HitEvent> hitEvents)
|
||||
: base("Average Hit Error")
|
||||
: base(RankingStatisticsStrings.AverageHitErrorTitle)
|
||||
{
|
||||
Value = hitEvents.CalculateAverageHitError();
|
||||
}
|
||||
|
||||
protected override string DisplayValue(double? value) => value == null ? "(not available)" : $"{Math.Abs(value.Value):N2} ms {(value.Value < 0 ? "early" : "late")}";
|
||||
protected override LocalisableString DisplayValue(double? value)
|
||||
{
|
||||
return value == null ? RankingStatisticsStrings.NotAvailable : getEarlyLateText(value.Value);
|
||||
|
||||
LocalisableString getEarlyLateText(double offset) =>
|
||||
offset < 0
|
||||
? RankingStatisticsStrings.Early(Math.Abs(offset))
|
||||
: RankingStatisticsStrings.Late(Math.Abs(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
@@ -17,7 +20,7 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// <summary>
|
||||
/// The text to display as the statistic's value.
|
||||
/// </summary>
|
||||
protected string Value
|
||||
protected LocalisableString Value
|
||||
{
|
||||
set => valueText.Text = value;
|
||||
}
|
||||
@@ -41,9 +44,9 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// Creates a new simple statistic item.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the statistic.</param>
|
||||
protected SimpleStatisticItem(string name)
|
||||
protected SimpleStatisticItem(LocalisableString name)
|
||||
{
|
||||
Name = name;
|
||||
Name = name.ToString();
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
@@ -52,7 +55,7 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
{
|
||||
nameText = new OsuSpriteText
|
||||
{
|
||||
Text = Name,
|
||||
Text = name,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: StatisticItem.FONT_SIZE)
|
||||
@@ -91,9 +94,15 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// Used to convert <see cref="Value"/> to a text representation.
|
||||
/// Defaults to using <see cref="object.ToString"/>.
|
||||
/// </summary>
|
||||
protected virtual string DisplayValue(TValue value) => value!.ToString() ?? string.Empty;
|
||||
protected virtual LocalisableString DisplayValue(TValue value)
|
||||
{
|
||||
if (value is IFormattable formattable)
|
||||
return formattable.ToLocalisableString();
|
||||
|
||||
public SimpleStatisticItem(string name)
|
||||
return value!.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
public SimpleStatisticItem(LocalisableString name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Screens.Ranking.Statistics
|
||||
@@ -16,11 +19,11 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
/// </summary>
|
||||
/// <param name="hitEvents">Sequence of <see cref="HitEvent"/>s to calculate the unstable rate based on.</param>
|
||||
public UnstableRate(IReadOnlyList<HitEvent> hitEvents)
|
||||
: base("Unstable Rate")
|
||||
: base(RankingStatisticsStrings.UnstableRateTitle)
|
||||
{
|
||||
Value = hitEvents.CalculateUnstableRate()?.Result;
|
||||
}
|
||||
|
||||
protected override string DisplayValue(double? value) => value?.ToString(@"N2") ?? "(not available)";
|
||||
protected override LocalisableString DisplayValue(double? value) => value?.ToLocalisableString(@"N2") ?? RankingStatisticsStrings.NotAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,6 +532,9 @@ namespace osu.Game.Screens.SelectV2
|
||||
// If a group was selected that is not the one containing the selection, attempt to reselect it.
|
||||
if (groupForReselection != null && grouping.GroupItems.TryGetValue(groupForReselection, out _))
|
||||
setExpandedGroup(groupForReselection);
|
||||
|
||||
foreach (var item in Scroll.Panels.OfType<PanelBeatmapSet>().Where(p => p.Item != null))
|
||||
updateVisibleBeatmaps((GroupedBeatmapSet)item.Item!.Model, item);
|
||||
}
|
||||
|
||||
private void selectRecommendedDifficultyForBeatmapSet(GroupedBeatmapSet set)
|
||||
@@ -959,13 +962,24 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
return beatmapPanelPool.Get();
|
||||
|
||||
case GroupedBeatmapSet:
|
||||
return setPanelPool.Get();
|
||||
case GroupedBeatmapSet groupedBeatmapSet:
|
||||
var setPanel = setPanelPool.Get();
|
||||
updateVisibleBeatmaps(groupedBeatmapSet, setPanel);
|
||||
return setPanel;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private void updateVisibleBeatmaps(GroupedBeatmapSet groupedBeatmapSet, PanelBeatmapSet setPanel)
|
||||
{
|
||||
HashSet<BeatmapInfo> visibleBeatmaps = [];
|
||||
if (grouping.SetItems.TryGetValue(groupedBeatmapSet, out var visibleItems))
|
||||
visibleBeatmaps = visibleItems.Where(i => i.Model is GroupedBeatmap).Select(i => ((GroupedBeatmap)i.Model).Beatmap).ToHashSet();
|
||||
|
||||
setPanel.VisibleBeatmaps.Value = visibleBeatmaps;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Random selection handling
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
private const float corner_radius = 10;
|
||||
|
||||
// 这里存储所选的工作谱面以供全局访问(例如在MOD中无法注入,可以用这个来获取工作谱面)。
|
||||
public static WorkingBeatmap? SelectedWorkingBeatmap;
|
||||
|
||||
[Resolved]
|
||||
|
||||
@@ -255,6 +255,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
localUser.BindValueChanged(_ => updateCriteria());
|
||||
localUserFavouriteBeatmapSets.BindCollectionChanged((_, _) => updateCriteria());
|
||||
ScopedBeatmapSet.BindValueChanged(_ => updateCriteria(clearScopedSet: false));
|
||||
|
||||
csSelector.Current.BindValueChanged(_ => updateCriteria());
|
||||
csSelector.EzKeyModeFilter.SelectionChanged += updateCriteria;
|
||||
@@ -262,6 +263,12 @@ namespace osu.Game.Screens.SelectV2
|
||||
updateCriteria();
|
||||
}
|
||||
|
||||
private void updateCriteria()
|
||||
{
|
||||
currentCriteria = CreateCriteria();
|
||||
CriteriaChanged?.Invoke(currentCriteria);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
@@ -278,6 +285,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
|
||||
var criteria = new FilterCriteria
|
||||
{
|
||||
SelectedBeatmapSet = ScopedBeatmapSet.Value,
|
||||
Sort = sortDropdown.Current.Value,
|
||||
Group = groupDropdown.Current.Value,
|
||||
AllowConvertedBeatmaps = showConvertedBeatmapsButton.Active.Value,
|
||||
@@ -332,8 +340,16 @@ namespace osu.Game.Screens.SelectV2
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCriteria()
|
||||
private void updateCriteria(bool clearScopedSet = true)
|
||||
{
|
||||
if (clearScopedSet && ScopedBeatmapSet.Value != null)
|
||||
{
|
||||
ScopedBeatmapSet.Value = null;
|
||||
// because `ScopedBeatmapSet` has a value change callback bound to it that calls `updateCriteria()` again,
|
||||
// we can just do nothing other than clear it to avoid extra work and duplicated `CriteriaChanged` invocations
|
||||
return;
|
||||
}
|
||||
|
||||
currentCriteria = CreateCriteria();
|
||||
CriteriaChanged?.Invoke(currentCriteria);
|
||||
}
|
||||
|
||||
@@ -212,6 +212,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
Origin = Anchor.CentreLeft,
|
||||
Scale = new Vector2(0.4f)
|
||||
},
|
||||
// TODO: 在此处增加XXY_SR
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "[Notes] ",
|
||||
@@ -413,6 +414,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
ILegacyRuleset legacyRuleset = (ILegacyRuleset)ruleset.Value.CreateInstance();
|
||||
int keyCount = legacyRuleset.GetKeyCount(beatmap, mods.Value);
|
||||
|
||||
// TODO: 当前机制不健全,显示内容可能不准确,怀疑被缓存影响而未能及时更新
|
||||
if (iBeatmap != null)
|
||||
{
|
||||
string keyCountTextValue = EzBeatmapCalculator.GetScratch(iBeatmap, keyCount);
|
||||
|
||||
264
osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs
Normal file
264
osu.Game/Screens/SelectV2/PanelBeatmapSet.SpreadDisplay.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
public partial class PanelBeatmapSet
|
||||
{
|
||||
public partial class SpreadDisplay : OsuAnimatedButton
|
||||
{
|
||||
public Bindable<BeatmapSetInfo?> BeatmapSet { get; } = new Bindable<BeatmapSetInfo?>();
|
||||
public Bindable<HashSet<BeatmapInfo>?> VisibleBeatmaps { get; } = new Bindable<HashSet<BeatmapInfo>?>();
|
||||
|
||||
public BindableBool Expanded { get; } = new BindableBool();
|
||||
|
||||
protected override Colour4 DimColour => Colour4.White;
|
||||
|
||||
private readonly Bindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
||||
private readonly Bindable<bool> showConvertedBeatmaps = new Bindable<bool>();
|
||||
|
||||
private const double transition_duration = 200;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private RulesetStore rulesets { get; set; } = null!;
|
||||
|
||||
private FillFlowContainer flow = null!;
|
||||
private SpriteIcon icon = null!;
|
||||
|
||||
public SpreadDisplay()
|
||||
{
|
||||
AutoSizeAxes = Axes.X;
|
||||
Height = 14;
|
||||
Content.CornerRadius = 5;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(ISongSelect? songSelect, OsuConfigManager configManager)
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5),
|
||||
Padding = new MarginPadding { Horizontal = 5 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
flow = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(1),
|
||||
},
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Size = new Vector2(12),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Icon = FontAwesome.Solid.Eye,
|
||||
Alpha = 0,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (songSelect != null)
|
||||
scopedBeatmapSet.BindTo(songSelect.ScopedBeatmapSet);
|
||||
|
||||
configManager.BindWith(OsuSetting.ShowConvertedBeatmaps, showConvertedBeatmaps);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
BeatmapSet.BindValueChanged(_ => updateBeatmapSet());
|
||||
VisibleBeatmaps.BindValueChanged(_ => updateBeatmapSet());
|
||||
showConvertedBeatmaps.BindValueChanged(_ => updateBeatmapSet(), true);
|
||||
Expanded.BindValueChanged(_ => updateEnabled());
|
||||
scopedBeatmapSet.BindValueChanged(_ => updateEnabled(), true);
|
||||
Enabled.BindValueChanged(_ => updateAppearance(), true);
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
private void updateBeatmapSet()
|
||||
{
|
||||
if (BeatmapSet.Value == null)
|
||||
{
|
||||
this.FadeOut(transition_duration, Easing.OutQuint);
|
||||
return;
|
||||
}
|
||||
|
||||
flow.Clear();
|
||||
|
||||
const int max_difficulties_before_collapsing = 12;
|
||||
|
||||
var beatmaps = BeatmapSet.Value.Beatmaps
|
||||
.Where(b => b.AllowGameplayWithRuleset(ruleset.Value, showConvertedBeatmaps.Value))
|
||||
.ToList();
|
||||
this.FadeTo(beatmaps.Count > 0 ? 1 : 0, transition_duration, Easing.OutQuint);
|
||||
|
||||
if (beatmaps.Count == 0)
|
||||
return;
|
||||
|
||||
bool showVisible = VisibleBeatmaps.Value == null || VisibleBeatmaps.Value?.Count <= max_difficulties_before_collapsing;
|
||||
bool showHidden = beatmaps.Count <= max_difficulties_before_collapsing;
|
||||
|
||||
var beatmapsByRuleset = beatmaps.GroupBy(beatmap => beatmap.Ruleset.OnlineID).OrderBy(group => group.Key);
|
||||
|
||||
foreach (var rulesetGrouping in beatmapsByRuleset)
|
||||
{
|
||||
int rulesetId = rulesetGrouping.Key;
|
||||
var rulesetIcon = rulesets.GetRuleset(rulesetId)?.CreateInstance().CreateIcon() ?? new SpriteIcon { Icon = FontAwesome.Regular.QuestionCircle };
|
||||
flow.Add(rulesetIcon.With(i =>
|
||||
{
|
||||
i.Size = new Vector2(14);
|
||||
i.Anchor = i.Origin = Anchor.CentreLeft;
|
||||
i.Margin = new MarginPadding { Left = flow.Count > 0 ? 9 : 0 };
|
||||
}));
|
||||
|
||||
int overflowVisible = 0;
|
||||
int overflowHidden = 0;
|
||||
bool? lastBeatmapVisible = null;
|
||||
|
||||
foreach (var beatmap in rulesetGrouping.OrderBy(beatmap => beatmap.StarRating))
|
||||
{
|
||||
bool visible = VisibleBeatmaps.Value?.Contains(beatmap) != false;
|
||||
|
||||
if ((visible && showVisible) || (!visible && showHidden))
|
||||
{
|
||||
var circle = new Circle
|
||||
{
|
||||
Size = visible ? new Vector2(7, 12) : new Vector2(5, 10),
|
||||
Alpha = visible ? 1 : 0.5f,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Colour = colours.ForStarDifficulty(beatmap.StarRating),
|
||||
Margin = new MarginPadding { Left = lastBeatmapVisible != null && lastBeatmapVisible != visible ? 1 : 0 }
|
||||
};
|
||||
flow.Add(circle);
|
||||
|
||||
lastBeatmapVisible = visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (visible)
|
||||
overflowVisible++;
|
||||
else
|
||||
overflowHidden++;
|
||||
}
|
||||
}
|
||||
|
||||
if (overflowVisible > 0)
|
||||
{
|
||||
flow.Add(new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.Style.Caption2,
|
||||
Text = overflowVisible.ToLocalisableString(),
|
||||
});
|
||||
}
|
||||
|
||||
if (overflowHidden > 0)
|
||||
{
|
||||
flow.Add(new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.Style.Caption2,
|
||||
Text = LocalisableString.Interpolate($@"+{overflowHidden}"),
|
||||
Alpha = 0.7f,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Action = () => scopedBeatmapSet.Value = BeatmapSet.Value;
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
private void updateEnabled()
|
||||
{
|
||||
Enabled.Value = Expanded.Value && scopedBeatmapSet.Value == null;
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
if (!Enabled.Value)
|
||||
return false;
|
||||
|
||||
base.OnMouseDown(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (!Enabled.Value)
|
||||
return false;
|
||||
|
||||
// this is a crude workaround with an issue with `OsuAnimatedButton` that isn't easily fixable.
|
||||
// the issue is that when wanting to turn off the hover layer upon click, `HoverColour` can be set to a transparent colour,
|
||||
// *but* this has to happen *before* `base.OnClick()`.
|
||||
// this is because `base.OnClick()` uses `FlashColour()` to flash the button on click,
|
||||
// but that `FlashColour()` call implicitly copies `hoverColour` *at the point of call* into the transform that ends the flash.
|
||||
updateAppearance(false);
|
||||
return base.OnClick(e);
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateAppearance();
|
||||
|
||||
if (!Enabled.Value)
|
||||
return false;
|
||||
|
||||
return base.OnHover(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
updateAppearance();
|
||||
|
||||
if (!Enabled.Value)
|
||||
return;
|
||||
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
private void updateAppearance(bool? isInteractable = null)
|
||||
{
|
||||
isInteractable ??= Enabled.Value && IsHovered;
|
||||
|
||||
HoverColour = isInteractable.Value ? Colour4.White.Opacity(0.1f) : Colour4.Transparent;
|
||||
icon.FadeTo(isInteractable.Value ? 1 : 0, transition_duration, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,8 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
public const float HEIGHT = CarouselItem.DEFAULT_HEIGHT * 1.6f;
|
||||
|
||||
public Bindable<HashSet<BeatmapInfo>?> VisibleBeatmaps { get; } = new Bindable<HashSet<BeatmapInfo>?>();
|
||||
|
||||
private Box chevronBackground = null!;
|
||||
private PanelSetBackground setBackground = null!;
|
||||
private ScheduledDelegate? scheduledBackgroundRetrieval;
|
||||
@@ -47,7 +49,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
private Drawable chevronIcon = null!;
|
||||
private PanelUpdateBeatmapButton updateButton = null!;
|
||||
private BeatmapSetOnlineStatusPill statusPill = null!;
|
||||
private DifficultySpectrumDisplay difficultiesDisplay = null!;
|
||||
private SpreadDisplay spreadDisplay = null!;
|
||||
|
||||
[Resolved]
|
||||
private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||
@@ -151,10 +153,12 @@ namespace osu.Game.Screens.SelectV2
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Right = 5f, Top = -2f },
|
||||
},
|
||||
difficultiesDisplay = new DifficultySpectrumDisplay
|
||||
spreadDisplay = new SpreadDisplay
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Expanded = { BindTarget = Expanded },
|
||||
VisibleBeatmaps = { BindTarget = VisibleBeatmaps },
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -200,7 +204,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
artistText.Text = new RomanisableString(beatmapSet.Metadata.ArtistUnicode, beatmapSet.Metadata.Artist);
|
||||
updateButton.BeatmapSet = beatmapSet;
|
||||
statusPill.Status = beatmapSet.Status;
|
||||
difficultiesDisplay.BeatmapSet = beatmapSet;
|
||||
spreadDisplay.BeatmapSet.Value = beatmapSet;
|
||||
}
|
||||
|
||||
protected override void FreeAfterUse()
|
||||
@@ -211,7 +215,7 @@ namespace osu.Game.Screens.SelectV2
|
||||
scheduledBackgroundRetrieval = null;
|
||||
setBackground.Beatmap = null;
|
||||
updateButton.BeatmapSet = null;
|
||||
difficultiesDisplay.BeatmapSet = null;
|
||||
spreadDisplay.BeatmapSet.Value = null;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace osu.Game.Screens.SelectV2
|
||||
public Bindable<BeatmapInfo?> Beatmap { get; } = new Bindable<BeatmapInfo?>();
|
||||
public Bindable<StarDifficulty> StarDifficulty { get; } = new Bindable<StarDifficulty>();
|
||||
|
||||
protected override Colour4 DimColour => Colour4.White;
|
||||
|
||||
private readonly Bindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
||||
private readonly Bindable<bool> showConvertedBeatmaps = new Bindable<bool>();
|
||||
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
<MtouchInterpreter>-all</MtouchInterpreter>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2025.1209.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2025.1229.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -9,7 +9,7 @@ using UIKit;
|
||||
namespace osu.iOS
|
||||
{
|
||||
[Register("AppDelegate")]
|
||||
public class AppDelegate : GameApplicationDelegate
|
||||
public class AppDelegate : GameApplicationDelegate, IUIApplicationDelegate
|
||||
{
|
||||
private UIInterfaceOrientationMask? defaultOrientationsMask;
|
||||
private UIInterfaceOrientationMask? orientations;
|
||||
@@ -41,7 +41,7 @@ namespace osu.iOS
|
||||
|
||||
protected override Framework.Game CreateGame() => new OsuGameIOS(this);
|
||||
|
||||
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
|
||||
public UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
|
||||
{
|
||||
if (orientations != null)
|
||||
return orientations.Value;
|
||||
|
||||
Reference in New Issue
Block a user