1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-05 11:42:55 +08:00

Merge branch 'master' into leaderboard-toggle

This commit is contained in:
Dean Herbert 2023-08-16 15:49:55 +09:00
commit 31c2b7f925
18 changed files with 160 additions and 118 deletions

View File

@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk> <EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.812.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2023.815.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged. <!-- Fody does not handle Android build well, and warns when unchanged.

View File

@ -6,7 +6,6 @@ using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using System.Collections.Generic;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps;
@ -24,21 +23,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
Assert.False(testBeatmap.HitObjects.OfType<HoldNote>().Any()); Assert.False(testBeatmap.HitObjects.OfType<HoldNote>().Any());
} }
[Test]
public void TestCorrectNoteValues()
{
var testBeatmap = createRawBeatmap();
var noteValues = new List<double>(testBeatmap.HitObjects.OfType<HoldNote>().Count());
foreach (HoldNote h in testBeatmap.HitObjects.OfType<HoldNote>())
{
noteValues.Add(ManiaModHoldOff.GetNoteDurationInBeatLength(h, testBeatmap));
}
noteValues.Sort();
Assert.AreEqual(noteValues, new List<double> { 0.125, 0.250, 0.500, 1.000, 2.000 });
}
[Test] [Test]
public void TestCorrectObjectCount() public void TestCorrectObjectCount()
{ {
@ -47,25 +31,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
var rawBeatmap = createRawBeatmap(); var rawBeatmap = createRawBeatmap();
var testBeatmap = createModdedBeatmap(); var testBeatmap = createModdedBeatmap();
// Calculate expected number of objects // Both notes and hold notes account for at least one object
int expectedObjectCount = 0; int expectedObjectCount = rawBeatmap.HitObjects.Count;
foreach (ManiaHitObject h in rawBeatmap.HitObjects)
{
// Both notes and hold notes account for at least one object
expectedObjectCount++;
if (h.GetType() == typeof(HoldNote))
{
double noteValue = ManiaModHoldOff.GetNoteDurationInBeatLength((HoldNote)h, rawBeatmap);
if (noteValue >= ManiaModHoldOff.END_NOTE_ALLOW_THRESHOLD)
{
// Should generate an end note if it's longer than the minimum note value
expectedObjectCount++;
}
}
}
Assert.That(testBeatmap.HitObjects.Count == expectedObjectCount); Assert.That(testBeatmap.HitObjects.Count == expectedObjectCount);
} }

View File

@ -117,18 +117,16 @@ namespace osu.Game.Rulesets.Mania.Tests
private void createBarLine(bool major) private void createBarLine(bool major)
{ {
foreach (var stage in stages) var obj = new BarLine
{ {
var obj = new BarLine StartTime = Time.Current + 2000,
{ Major = major,
StartTime = Time.Current + 2000, };
Major = major,
};
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
foreach (var stage in stages)
stage.Add(obj); stage.Add(obj);
}
} }
private ScrollingTestContainer createStage(ScrollingDirection direction, ManiaAction action) private ScrollingTestContainer createStage(ScrollingDirection direction, ManiaAction action)

View File

@ -33,5 +33,6 @@ namespace osu.Game.Rulesets.Mania
HitExplosion, HitExplosion,
StageBackground, StageBackground,
StageForeground, StageForeground,
BarLine
} }
} }

View File

@ -29,8 +29,6 @@ namespace osu.Game.Rulesets.Mania.Mods
public override Type[] IncompatibleMods => new[] { typeof(ManiaModInvert) }; public override Type[] IncompatibleMods => new[] { typeof(ManiaModInvert) };
public const double END_NOTE_ALLOW_THRESHOLD = 0.5;
public void ApplyToBeatmap(IBeatmap beatmap) public void ApplyToBeatmap(IBeatmap beatmap)
{ {
var maniaBeatmap = (ManiaBeatmap)beatmap; var maniaBeatmap = (ManiaBeatmap)beatmap;
@ -46,28 +44,9 @@ namespace osu.Game.Rulesets.Mania.Mods
StartTime = h.StartTime, StartTime = h.StartTime,
Samples = h.GetNodeSamples(0) Samples = h.GetNodeSamples(0)
}); });
// Don't add an end note if the duration is shorter than the threshold
double noteValue = GetNoteDurationInBeatLength(h, maniaBeatmap); // 1/1, 1/2, 1/4, etc.
if (noteValue >= END_NOTE_ALLOW_THRESHOLD)
{
newObjects.Add(new Note
{
Column = h.Column,
StartTime = h.EndTime,
Samples = h.GetNodeSamples((h.NodeSamples?.Count - 1) ?? 1)
});
}
} }
maniaBeatmap.HitObjects = maniaBeatmap.HitObjects.OfType<Note>().Concat(newObjects).OrderBy(h => h.StartTime).ToList(); maniaBeatmap.HitObjects = maniaBeatmap.HitObjects.OfType<Note>().Concat(newObjects).OrderBy(h => h.StartTime).ToList();
} }
public static double GetNoteDurationInBeatLength(HoldNote holdNote, ManiaBeatmap beatmap)
{
double beatLength = beatmap.ControlPointInfo.TimingPointAt(holdNote.StartTime).BeatLength;
return holdNote.Duration / beatLength;
}
} }
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
@ -8,7 +9,15 @@ namespace osu.Game.Rulesets.Mania.Objects
{ {
public class BarLine : ManiaHitObject, IBarLine public class BarLine : ManiaHitObject, IBarLine
{ {
public bool Major { get; set; } private HitObjectProperty<bool> major;
public Bindable<bool> MajorBindable => major.Bindable;
public bool Major
{
get => major.Value;
set => major.Value = value;
}
public override Judgement CreateJudgement() => new IgnoreJudgement(); public override Judgement CreateJudgement() => new IgnoreJudgement();
} }

View File

@ -1,9 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Mania.Skinning.Default;
using osuTK; using osu.Game.Skinning;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
@ -13,45 +15,41 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
/// </summary> /// </summary>
public partial class DrawableBarLine : DrawableManiaHitObject<BarLine> public partial class DrawableBarLine : DrawableManiaHitObject<BarLine>
{ {
public readonly Bindable<bool> Major = new Bindable<bool>();
public DrawableBarLine()
: this(null!)
{
}
public DrawableBarLine(BarLine barLine) public DrawableBarLine(BarLine barLine)
: base(barLine) : base(barLine)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = barLine.Major ? 1.7f : 1.2f; }
AddInternal(new Box [BackgroundDependencyLoader]
private void load()
{
AddInternal(new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.BarLine), _ => new DefaultBarLine())
{ {
Name = "Bar line", Anchor = Anchor.Centre,
Anchor = Anchor.BottomCentre, Origin = Anchor.Centre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both,
Alpha = barLine.Major ? 0.5f : 0.2f
}); });
if (barLine.Major) Major.BindValueChanged(major => Height = major.NewValue ? 1.7f : 1.2f, true);
{ }
Vector2 size = new Vector2(22, 6);
const float line_offset = 4;
AddInternal(new Circle protected override void OnApply()
{ {
Name = "Left line", base.OnApply();
Anchor = Anchor.CentreLeft, Major.BindTo(HitObject.MajorBindable);
Origin = Anchor.CentreRight, }
Size = size, protected override void OnFree()
X = -line_offset, {
}); base.OnFree();
Major.UnbindFrom(HitObject.MajorBindable);
AddInternal(new Circle
{
Name = "Right line",
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreLeft,
Size = size,
X = line_offset,
});
}
} }
protected override void UpdateStartTimeStateTransforms() => this.FadeOut(150); protected override void UpdateStartTimeStateTransforms() => this.FadeOut(150);

View File

@ -0,0 +1,72 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
namespace osu.Game.Rulesets.Mania.Skinning.Default
{
public partial class DefaultBarLine : CompositeDrawable
{
private Bindable<bool> major = null!;
private Drawable mainLine = null!;
private Drawable leftAnchor = null!;
private Drawable rightAnchor = null!;
[BackgroundDependencyLoader]
private void load(DrawableHitObject drawableHitObject)
{
RelativeSizeAxes = Axes.Both;
AddInternal(mainLine = new Box
{
Name = "Bar line",
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.Both,
});
Vector2 size = new Vector2(22, 6);
const float line_offset = 4;
AddInternal(leftAnchor = new Circle
{
Name = "Left anchor",
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreRight,
Size = size,
X = -line_offset,
});
AddInternal(rightAnchor = new Circle
{
Name = "Right anchor",
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreLeft,
Size = size,
X = line_offset,
});
major = ((DrawableBarLine)drawableHitObject).Major.GetBoundCopy();
}
protected override void LoadComplete()
{
base.LoadComplete();
major.BindValueChanged(updateMajor, true);
}
private void updateMajor(ValueChangedEvent<bool> major)
{
mainLine.Alpha = major.NewValue ? 0.5f : 0.2f;
leftAnchor.Alpha = rightAnchor.Alpha = major.NewValue ? 1 : 0;
}
}
}

View File

@ -119,6 +119,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
case ManiaSkinComponents.StageForeground: case ManiaSkinComponents.StageForeground:
return new LegacyStageForeground(); return new LegacyStageForeground();
case ManiaSkinComponents.BarLine:
return null; // Not yet implemented.
default: default:
throw new UnsupportedSkinComponentException(lookup); throw new UnsupportedSkinComponentException(lookup);
} }

View File

@ -30,15 +30,15 @@ namespace osu.Game.Rulesets.Mania.UI
{ {
get get
{ {
if (Stages.Count == 1) RectangleF totalArea = RectangleF.Empty;
return Stages.First().ScreenSpaceDrawQuad;
RectangleF area = RectangleF.Empty; for (int i = 0; i < Stages.Count; ++i)
{
var stageArea = Stages[i].ScreenSpaceDrawQuad.AABBFloat;
totalArea = i == 0 ? stageArea : RectangleF.Union(totalArea, stageArea);
}
foreach (var stage in Stages) return totalArea;
area = RectangleF.Union(area, stage.ScreenSpaceDrawQuad.AABBFloat);
return area;
} }
} }

View File

@ -136,6 +136,8 @@ namespace osu.Game.Rulesets.Mania.UI
columnFlow.SetContentForColumn(i, column); columnFlow.SetContentForColumn(i, column);
AddNested(column); AddNested(column);
} }
RegisterPool<BarLine, DrawableBarLine>(50, 200);
} }
private ISkinSource currentSkin; private ISkinSource currentSkin;
@ -186,7 +188,7 @@ namespace osu.Game.Rulesets.Mania.UI
public override bool Remove(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column - firstColumnIndex).Remove(h); public override bool Remove(DrawableHitObject h) => Columns.ElementAt(((ManiaHitObject)h.HitObject).Column - firstColumnIndex).Remove(h);
public void Add(BarLine barLine) => base.Add(new DrawableBarLine(barLine)); public void Add(BarLine barLine) => base.Add(barLine);
internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result) internal void OnNewResult(DrawableHitObject judgedObject, JudgementResult result)
{ {

View File

@ -49,6 +49,18 @@ namespace osu.Game.Graphics
this.maxDuration = maxDuration; this.maxDuration = maxDuration;
} }
protected override void LoadComplete()
{
base.LoadComplete();
Active.BindValueChanged(active =>
{
// ensure that particles can be spawned immediately after the spewer becomes active.
if (active.NewValue)
lastParticleAdded = null;
});
}
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -56,12 +68,8 @@ namespace osu.Game.Graphics
Invalidate(Invalidation.DrawNode); Invalidate(Invalidation.DrawNode);
if (!Active.Value || !CanSpawnParticles) if (!Active.Value || !CanSpawnParticles)
{
lastParticleAdded = null;
return; return;
}
// Always want to spawn the first particle in an activation immediately.
if (lastParticleAdded == null) if (lastParticleAdded == null)
{ {
lastParticleAdded = Time.Current; lastParticleAdded = Time.Current;

View File

@ -213,7 +213,7 @@ namespace osu.Game.Graphics.UserInterface
requestDisplay(); requestDisplay();
else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000 && !IsHovered) else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000 && !IsHovered)
{ {
mainContent.FadeTo(0, 300, Easing.OutQuint); mainContent.FadeTo(0.7f, 300, Easing.OutQuint);
isDisplayed = false; isDisplayed = false;
} }
} }

View File

@ -20,7 +20,7 @@ namespace osu.Game.Online.API
public Bindable<APIUser> LocalUser { get; } = new Bindable<APIUser>(new APIUser public Bindable<APIUser> LocalUser { get; } = new Bindable<APIUser>(new APIUser
{ {
Username = @"Dummy", Username = @"Local user",
Id = DUMMY_USER_ID, Id = DUMMY_USER_ID,
}); });

View File

@ -104,9 +104,11 @@ namespace osu.Game.Rulesets.Difficulty
public virtual void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo) public virtual void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
{ {
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO]; MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
LegacyAccuracyScore = (int)values[ATTRIB_ID_LEGACY_ACCURACY_SCORE];
LegacyComboScore = (int)values[ATTRIB_ID_LEGACY_COMBO_SCORE]; // Temporarily allow these attributes to not exist so as to not block releases of server-side components while these attributes aren't populated/used yet.
LegacyBonusScoreRatio = (int)values[ATTRIB_ID_LEGACY_BONUS_SCORE_RATIO]; LegacyAccuracyScore = (int)values.GetValueOrDefault(ATTRIB_ID_LEGACY_ACCURACY_SCORE);
LegacyComboScore = (int)values.GetValueOrDefault(ATTRIB_ID_LEGACY_COMBO_SCORE);
LegacyBonusScoreRatio = values.GetValueOrDefault(ATTRIB_ID_LEGACY_BONUS_SCORE_RATIO);
} }
} }
} }

View File

@ -810,10 +810,13 @@ namespace osu.Game.Screens.Play
if (!canShowResults && !forceImport) if (!canShowResults && !forceImport)
return Task.FromResult<ScoreInfo>(null); return Task.FromResult<ScoreInfo>(null);
// Clone score before beginning any async processing.
// - Must be run synchronously as the score may potentially be mutated in the background.
// - Must be cloned for the same reason.
Score scoreCopy = Score.DeepClone();
return prepareScoreForDisplayTask = Task.Run(async () => return prepareScoreForDisplayTask = Task.Run(async () =>
{ {
var scoreCopy = Score.DeepClone();
try try
{ {
await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false); await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Realm" Version="11.1.2" /> <PackageReference Include="Realm" Version="11.1.2" />
<PackageReference Include="ppy.osu.Framework" Version="2023.812.0" /> <PackageReference Include="ppy.osu.Framework" Version="2023.815.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.719.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2023.719.0" />
<PackageReference Include="Sentry" Version="3.28.1" /> <PackageReference Include="Sentry" Version="3.28.1" />
<PackageReference Include="SharpCompress" Version="0.32.2" /> <PackageReference Include="SharpCompress" Version="0.32.2" />

View File

@ -23,6 +23,6 @@
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier> <RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.812.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2023.815.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>