mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 09:27:29 +08:00
Merge branch 'master' into taiko-single-tap
This commit is contained in:
commit
9866321d27
@ -3,15 +3,53 @@
|
|||||||
#
|
#
|
||||||
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
|
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
|
||||||
|
|
||||||
$CSPROJ="osu.Game/osu.Game.csproj"
|
$GAME_CSPROJ="osu.Game/osu.Game.csproj"
|
||||||
|
$ANDROID_PROPS="osu.Android.props"
|
||||||
|
$IOS_PROPS="osu.iOS.props"
|
||||||
$SLN="osu.sln"
|
$SLN="osu.sln"
|
||||||
|
|
||||||
dotnet remove $CSPROJ package ppy.osu.Framework;
|
dotnet remove $GAME_CSPROJ reference ppy.osu.Framework;
|
||||||
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj;
|
dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android;
|
||||||
dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
|
dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS;
|
||||||
|
|
||||||
|
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj `
|
||||||
|
../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj `
|
||||||
|
../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj `
|
||||||
|
../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
|
||||||
|
|
||||||
|
dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj;
|
||||||
|
dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj;
|
||||||
|
dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
|
||||||
|
|
||||||
|
# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
|
||||||
|
(Get-Content "osu.Android.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.Android.props"
|
||||||
|
(Get-Content "osu.iOS.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.iOS.props"
|
||||||
|
|
||||||
|
# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
|
||||||
|
# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
|
||||||
|
(Get-Content "osu.iOS.props") |
|
||||||
|
Foreach-Object {
|
||||||
|
if ($_ -match "</Project>")
|
||||||
|
{
|
||||||
|
" <Import Project=`"`$(MSBuildThisFileDirectory)../osu-framework/osu.Framework.iOS.props`"/>"
|
||||||
|
}
|
||||||
|
|
||||||
|
$_
|
||||||
|
} | Set-Content "osu.iOS.props"
|
||||||
|
|
||||||
|
$TMP=New-TemporaryFile
|
||||||
|
|
||||||
$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json
|
$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json
|
||||||
$TMP=New-TemporaryFile
|
|
||||||
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj")
|
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj")
|
||||||
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
|
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
|
||||||
Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force
|
Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force
|
||||||
|
|
||||||
|
$SLNF=Get-Content "osu.Android.slnf" | ConvertFrom-Json
|
||||||
|
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj")
|
||||||
|
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
|
||||||
|
Move-Item -Path $TMP -Destination "osu.Android.slnf" -Force
|
||||||
|
|
||||||
|
$SLNF=Get-Content "osu.iOS.slnf" | ConvertFrom-Json
|
||||||
|
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj")
|
||||||
|
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
|
||||||
|
Move-Item -Path $TMP -Destination "osu.iOS.slnf" -Force
|
||||||
|
@ -5,14 +5,41 @@
|
|||||||
#
|
#
|
||||||
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
|
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
|
||||||
|
|
||||||
CSPROJ="osu.Game/osu.Game.csproj"
|
GAME_CSPROJ="osu.Game/osu.Game.csproj"
|
||||||
|
ANDROID_PROPS="osu.Android.props"
|
||||||
|
IOS_PROPS="osu.iOS.props"
|
||||||
SLN="osu.sln"
|
SLN="osu.sln"
|
||||||
|
|
||||||
dotnet remove $CSPROJ package ppy.osu.Framework
|
dotnet remove $GAME_CSPROJ reference ppy.osu.Framework
|
||||||
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj
|
dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android
|
||||||
dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
|
dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS
|
||||||
|
|
||||||
|
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj \
|
||||||
|
../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj \
|
||||||
|
../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj \
|
||||||
|
../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
|
||||||
|
|
||||||
|
dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
|
||||||
|
dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj
|
||||||
|
dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
|
||||||
|
|
||||||
|
# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
|
||||||
|
sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.Android.props && rm osu.Android.props.bak
|
||||||
|
sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.iOS.props && rm osu.iOS.props.bak
|
||||||
|
|
||||||
|
# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
|
||||||
|
# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
|
||||||
|
sed -i.bak '/<\/Project>/i\
|
||||||
|
<Import Project=\"$(MSBuildThisFileDirectory)../osu-framework/osu.Framework.iOS.props\"/>\
|
||||||
|
' ./osu.iOS.props && rm osu.iOS.props.bak
|
||||||
|
|
||||||
SLNF="osu.Desktop.slnf"
|
|
||||||
tmp=$(mktemp)
|
tmp=$(mktemp)
|
||||||
|
|
||||||
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp
|
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp
|
||||||
mv -f $tmp $SLNF
|
mv -f $tmp osu.Desktop.slnf
|
||||||
|
|
||||||
|
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj"]' osu.Android.slnf > $tmp
|
||||||
|
mv -f $tmp osu.Android.slnf
|
||||||
|
|
||||||
|
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj"]' osu.iOS.slnf > $tmp
|
||||||
|
mv -f $tmp osu.iOS.slnf
|
||||||
|
@ -8,10 +8,14 @@
|
|||||||
<!-- NullabilityInfoContextSupport is disabled by default for Android -->
|
<!-- NullabilityInfoContextSupport is disabled by default for Android -->
|
||||||
<NullabilityInfoContextSupport>true</NullabilityInfoContextSupport>
|
<NullabilityInfoContextSupport>true</NullabilityInfoContextSupport>
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
|
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.228.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.228.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />
|
||||||
|
</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.
|
||||||
Since Realm objects are not declared directly in Android projects, simply disable Fody. -->
|
Since Realm objects are not declared directly in Android projects, simply disable Fody. -->
|
||||||
|
15
osu.Android/Properties/AndroidManifestOverlay.xml
Normal file
15
osu.Android/Properties/AndroidManifestOverlay.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="mailto" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
</manifest>
|
123
osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
Normal file
123
osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// 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 BenchmarkDotNet.Attributes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
using osu.Game.Screens.Select.Carousel;
|
||||||
|
|
||||||
|
namespace osu.Game.Benchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkCarouselFilter : BenchmarkTest
|
||||||
|
{
|
||||||
|
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo
|
||||||
|
{
|
||||||
|
ShortName = "osu",
|
||||||
|
OnlineID = 0
|
||||||
|
},
|
||||||
|
StarRating = 4.0d,
|
||||||
|
Difficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
ApproachRate = 5.0f,
|
||||||
|
DrainRate = 3.0f,
|
||||||
|
CircleSize = 2.0f,
|
||||||
|
},
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = "The Artist",
|
||||||
|
ArtistUnicode = "check unicode too",
|
||||||
|
Title = "Title goes here",
|
||||||
|
TitleUnicode = "Title goes here",
|
||||||
|
Author = { Username = "The Author" },
|
||||||
|
Source = "unit tests",
|
||||||
|
Tags = "look for tags too",
|
||||||
|
},
|
||||||
|
DifficultyName = "version as well",
|
||||||
|
Length = 2500,
|
||||||
|
BPM = 160,
|
||||||
|
BeatDivisor = 12,
|
||||||
|
Status = BeatmapOnlineStatus.Loved
|
||||||
|
};
|
||||||
|
|
||||||
|
private CarouselBeatmap carouselBeatmap = null!;
|
||||||
|
private FilterCriteria criteria1 = null!;
|
||||||
|
private FilterCriteria criteria2 = null!;
|
||||||
|
private FilterCriteria criteria3 = null!;
|
||||||
|
private FilterCriteria criteria4 = null!;
|
||||||
|
private FilterCriteria criteria5 = null!;
|
||||||
|
private FilterCriteria criteria6 = null!;
|
||||||
|
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
var beatmap = getExampleBeatmap();
|
||||||
|
beatmap.OnlineID = 20201010;
|
||||||
|
beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
|
||||||
|
carouselBeatmap = new CarouselBeatmap(beatmap);
|
||||||
|
criteria1 = new FilterCriteria();
|
||||||
|
criteria2 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { ShortName = "catch" }
|
||||||
|
};
|
||||||
|
criteria3 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||||
|
AllowConvertedBeatmaps = true,
|
||||||
|
BPM = new FilterCriteria.OptionalRange<double>
|
||||||
|
{
|
||||||
|
IsUpperInclusive = false,
|
||||||
|
Max = 160d
|
||||||
|
}
|
||||||
|
};
|
||||||
|
criteria4 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||||
|
AllowConvertedBeatmaps = true,
|
||||||
|
SearchText = "an artist"
|
||||||
|
};
|
||||||
|
criteria5 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Creator = new FilterCriteria.OptionalTextFilter { SearchTerm = "the author AND then something else" }
|
||||||
|
};
|
||||||
|
criteria6 = new FilterCriteria { SearchText = "20201010" };
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CarouselBeatmapFilter()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingSpecificRuleset()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingRangeMax()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingTerms()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingCreator()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingBeatmapIDs()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -167,8 +167,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
if (bodySprite != null)
|
if (bodySprite != null)
|
||||||
{
|
{
|
||||||
bodySprite.Origin = Anchor.BottomCentre;
|
bodySprite.Origin = Anchor.TopCentre;
|
||||||
bodySprite.Scale = new Vector2(bodySprite.Scale.X, Math.Abs(bodySprite.Scale.Y) * -1);
|
bodySprite.Anchor = Anchor.BottomCentre; // needs to be flipped due to scale flip in Update.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light != null)
|
if (light != null)
|
||||||
@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
if (bodySprite != null)
|
if (bodySprite != null)
|
||||||
{
|
{
|
||||||
bodySprite.Origin = Anchor.TopCentre;
|
bodySprite.Origin = Anchor.TopCentre;
|
||||||
bodySprite.Scale = new Vector2(bodySprite.Scale.X, Math.Abs(bodySprite.Scale.Y));
|
bodySprite.Anchor = Anchor.TopCentre;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light != null)
|
if (light != null)
|
||||||
@ -211,11 +211,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
base.Update();
|
base.Update();
|
||||||
missFadeTime.Value ??= holdNote.HoldBrokenTime;
|
missFadeTime.Value ??= holdNote.HoldBrokenTime;
|
||||||
|
|
||||||
|
int scaleDirection = (direction.Value == ScrollingDirection.Down ? 1 : -1);
|
||||||
|
|
||||||
// here we go...
|
// here we go...
|
||||||
switch (bodyStyle)
|
switch (bodyStyle)
|
||||||
{
|
{
|
||||||
case LegacyNoteBodyStyle.Stretch:
|
case LegacyNoteBodyStyle.Stretch:
|
||||||
// this is how lazer works by default. nothing required.
|
// this is how lazer works by default. nothing required.
|
||||||
|
if (bodySprite != null)
|
||||||
|
bodySprite.Scale = new Vector2(1, scaleDirection);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -228,7 +232,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
|
|
||||||
bodySprite.FillMode = FillMode.Stretch;
|
bodySprite.FillMode = FillMode.Stretch;
|
||||||
// i dunno this looks about right??
|
// i dunno this looks about right??
|
||||||
bodySprite.Scale = new Vector2(1, 32800 / sprite.DrawHeight);
|
bodySprite.Scale = new Vector2(1, scaleDirection * 32800 / sprite.DrawHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -73,11 +73,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint
|
beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint
|
||||||
{
|
{
|
||||||
BeatLength = beat_length,
|
BeatLength = beat_length,
|
||||||
TimeSignature = new TimeSignature(time_signature_numerator)
|
TimeSignature = new TimeSignature(time_signature_numerator),
|
||||||
|
OmitFirstBarLine = true
|
||||||
});
|
});
|
||||||
|
|
||||||
beatmap.ControlPointInfo.Add(start_time, new EffectControlPoint { OmitFirstBarLine = true });
|
|
||||||
|
|
||||||
var barlines = new BarLineGenerator<BarLine>(beatmap).BarLines;
|
var barlines = new BarLineGenerator<BarLine>(beatmap).BarLines;
|
||||||
|
|
||||||
AddAssert("first barline ommited", () => barlines.All(b => b.StartTime != start_time));
|
AddAssert("first barline ommited", () => barlines.All(b => b.StartTime != start_time));
|
||||||
|
@ -72,7 +72,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint
|
converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint
|
||||||
{
|
{
|
||||||
KiaiMode = currentEffectPoint.KiaiMode,
|
KiaiMode = currentEffectPoint.KiaiMode,
|
||||||
OmitFirstBarLine = currentEffectPoint.OmitFirstBarLine,
|
|
||||||
ScrollSpeed = lastScrollSpeed = nextScrollSpeed,
|
ScrollSpeed = lastScrollSpeed = nextScrollSpeed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -181,16 +181,19 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(956, timingPoint.Time);
|
Assert.AreEqual(956, timingPoint.Time);
|
||||||
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
Assert.IsFalse(timingPoint.OmitFirstBarLine);
|
||||||
|
|
||||||
timingPoint = controlPoints.TimingPointAt(48428);
|
timingPoint = controlPoints.TimingPointAt(48428);
|
||||||
Assert.AreEqual(956, timingPoint.Time);
|
Assert.AreEqual(956, timingPoint.Time);
|
||||||
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
Assert.IsFalse(timingPoint.OmitFirstBarLine);
|
||||||
|
|
||||||
timingPoint = controlPoints.TimingPointAt(119637);
|
timingPoint = controlPoints.TimingPointAt(119637);
|
||||||
Assert.AreEqual(119637, timingPoint.Time);
|
Assert.AreEqual(119637, timingPoint.Time);
|
||||||
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
|
||||||
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
Assert.AreEqual(TimeSignature.SimpleQuadruple, timingPoint.TimeSignature);
|
||||||
|
Assert.IsFalse(timingPoint.OmitFirstBarLine);
|
||||||
|
|
||||||
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
var difficultyPoint = controlPoints.DifficultyPointAt(0);
|
||||||
Assert.AreEqual(0, difficultyPoint.Time);
|
Assert.AreEqual(0, difficultyPoint.Time);
|
||||||
@ -222,17 +225,14 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
var effectPoint = controlPoints.EffectPointAt(0);
|
var effectPoint = controlPoints.EffectPointAt(0);
|
||||||
Assert.AreEqual(0, effectPoint.Time);
|
Assert.AreEqual(0, effectPoint.Time);
|
||||||
Assert.IsFalse(effectPoint.KiaiMode);
|
Assert.IsFalse(effectPoint.KiaiMode);
|
||||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
|
||||||
|
|
||||||
effectPoint = controlPoints.EffectPointAt(53703);
|
effectPoint = controlPoints.EffectPointAt(53703);
|
||||||
Assert.AreEqual(53703, effectPoint.Time);
|
Assert.AreEqual(53703, effectPoint.Time);
|
||||||
Assert.IsTrue(effectPoint.KiaiMode);
|
Assert.IsTrue(effectPoint.KiaiMode);
|
||||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
|
||||||
|
|
||||||
effectPoint = controlPoints.EffectPointAt(116637);
|
effectPoint = controlPoints.EffectPointAt(116637);
|
||||||
Assert.AreEqual(95901, effectPoint.Time);
|
Assert.AreEqual(95901, effectPoint.Time);
|
||||||
Assert.IsFalse(effectPoint.KiaiMode);
|
Assert.IsFalse(effectPoint.KiaiMode);
|
||||||
Assert.IsFalse(effectPoint.OmitFirstBarLine);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +273,28 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDecodeOmitBarLineEffect()
|
||||||
|
{
|
||||||
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
|
|
||||||
|
using (var resStream = TestResources.OpenResource("omit-barline-control-points.osu"))
|
||||||
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
{
|
||||||
|
var controlPoints = (LegacyControlPointInfo)decoder.Decode(stream).ControlPointInfo;
|
||||||
|
|
||||||
|
Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(6));
|
||||||
|
Assert.That(controlPoints.EffectPoints.Count, Is.EqualTo(0));
|
||||||
|
|
||||||
|
Assert.That(controlPoints.TimingPointAt(500).OmitFirstBarLine, Is.False);
|
||||||
|
Assert.That(controlPoints.TimingPointAt(1500).OmitFirstBarLine, Is.True);
|
||||||
|
Assert.That(controlPoints.TimingPointAt(2500).OmitFirstBarLine, Is.False);
|
||||||
|
Assert.That(controlPoints.TimingPointAt(3500).OmitFirstBarLine, Is.False);
|
||||||
|
Assert.That(controlPoints.TimingPointAt(4500).OmitFirstBarLine, Is.False);
|
||||||
|
Assert.That(controlPoints.TimingPointAt(5500).OmitFirstBarLine, Is.True);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestTimingPointResetsSpeedMultiplier()
|
public void TestTimingPointResetsSpeedMultiplier()
|
||||||
{
|
{
|
||||||
|
125
osu.Game.Tests/Database/LegacyExporterTest.cs
Normal file
125
osu.Game.Tests/Database/LegacyExporterTest.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.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Database
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class LegacyExporterTest
|
||||||
|
{
|
||||||
|
private TestLegacyExporter legacyExporter = null!;
|
||||||
|
private TemporaryNativeStorage storage = null!;
|
||||||
|
|
||||||
|
private const string short_filename = "normal file name";
|
||||||
|
|
||||||
|
private const string long_filename =
|
||||||
|
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
storage = new TemporaryNativeStorage("export-storage");
|
||||||
|
legacyExporter = new TestLegacyExporter(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExportFileWithNormalNameTest()
|
||||||
|
{
|
||||||
|
var item = new TestPathInfo(short_filename);
|
||||||
|
|
||||||
|
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
|
||||||
|
|
||||||
|
exportItemAndAssert(item, short_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExportFileWithNormalNameMultipleTimesTest()
|
||||||
|
{
|
||||||
|
var item = new TestPathInfo(short_filename);
|
||||||
|
|
||||||
|
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
|
||||||
|
|
||||||
|
//Export multiple times
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})";
|
||||||
|
exportItemAndAssert(item, expectedFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExportFileWithSuperLongNameTest()
|
||||||
|
{
|
||||||
|
int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
|
||||||
|
string expectedName = long_filename.Remove(expectedLength);
|
||||||
|
|
||||||
|
var item = new TestPathInfo(long_filename);
|
||||||
|
|
||||||
|
Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
|
||||||
|
exportItemAndAssert(item, expectedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ExportFileWithSuperLongNameMultipleTimesTest()
|
||||||
|
{
|
||||||
|
int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
|
||||||
|
string expectedName = long_filename.Remove(expectedLength);
|
||||||
|
|
||||||
|
var item = new TestPathInfo(long_filename);
|
||||||
|
|
||||||
|
Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
|
||||||
|
|
||||||
|
//Export multiple times
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
string expectedFilename = i == 0 ? expectedName : $"{expectedName} ({i})";
|
||||||
|
exportItemAndAssert(item, expectedFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportItemAndAssert(IHasNamedFiles item, string expectedName)
|
||||||
|
{
|
||||||
|
Assert.DoesNotThrow(() => legacyExporter.Export(item));
|
||||||
|
Assert.That(storage.Exists($"exports/{expectedName}{legacyExporter.GetExtension()}"), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
if (storage.IsNotNull())
|
||||||
|
storage.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestPathInfo : IHasNamedFiles
|
||||||
|
{
|
||||||
|
public string Filename { get; }
|
||||||
|
|
||||||
|
public IEnumerable<INamedFileUsage> Files { get; } = new List<INamedFileUsage>();
|
||||||
|
|
||||||
|
public TestPathInfo(string filename)
|
||||||
|
{
|
||||||
|
Filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestLegacyExporter : LegacyExporter<IHasNamedFiles>
|
||||||
|
{
|
||||||
|
public TestLegacyExporter(Storage storage)
|
||||||
|
: base(storage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetExtension() => FileExtension;
|
||||||
|
|
||||||
|
protected override string FileExtension => ".test";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ using osu.Game.Overlays.Settings;
|
|||||||
namespace osu.Game.Tests.Mods
|
namespace osu.Game.Tests.Mods
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public partial class SettingsSourceAttributeTest
|
public partial class SettingSourceAttributeTest
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestOrdering()
|
public void TestOrdering()
|
@ -43,6 +43,18 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
||||||
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(2));
|
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(2));
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
||||||
|
|
||||||
|
cpi.Add(1200, new TimingControlPoint { OmitFirstBarLine = true }); // is not redundant
|
||||||
|
|
||||||
|
Assert.That(cpi.Groups.Count, Is.EqualTo(3));
|
||||||
|
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(3));
|
||||||
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(3));
|
||||||
|
|
||||||
|
cpi.Add(1500, new TimingControlPoint { OmitFirstBarLine = true }); // is not redundant
|
||||||
|
|
||||||
|
Assert.That(cpi.Groups.Count, Is.EqualTo(4));
|
||||||
|
Assert.That(cpi.TimingPoints.Count, Is.EqualTo(4));
|
||||||
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(4));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -95,12 +107,12 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(0));
|
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(0));
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(0));
|
||||||
|
|
||||||
cpi.Add(1000, new EffectControlPoint { KiaiMode = true, OmitFirstBarLine = true }); // is not redundant
|
cpi.Add(1000, new EffectControlPoint { KiaiMode = true }); // is not redundant
|
||||||
cpi.Add(1400, new EffectControlPoint { KiaiMode = true, OmitFirstBarLine = true }); // same settings, but is not redundant
|
cpi.Add(1400, new EffectControlPoint { KiaiMode = true }); // is redundant
|
||||||
|
|
||||||
Assert.That(cpi.Groups.Count, Is.EqualTo(2));
|
Assert.That(cpi.Groups.Count, Is.EqualTo(1));
|
||||||
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(2));
|
Assert.That(cpi.EffectPoints.Count, Is.EqualTo(1));
|
||||||
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(2));
|
Assert.That(cpi.AllControlPoints.Count(), Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
BIN
osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk
Normal file
BIN
osu.Game.Tests/Resources/Archives/modified-argon-20230305.osk
Normal file
Binary file not shown.
27
osu.Game.Tests/Resources/omit-barline-control-points.osu
Normal file
27
osu.Game.Tests/Resources/omit-barline-control-points.osu
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
osu file format v14
|
||||||
|
|
||||||
|
[TimingPoints]
|
||||||
|
|
||||||
|
// Uninherited: none, inherited: none
|
||||||
|
0,500,4,2,0,100,1,0
|
||||||
|
0,-50,4,3,0,100,0,0
|
||||||
|
|
||||||
|
// Uninherited: omit, inherited: none
|
||||||
|
1000,500,4,2,0,100,1,8
|
||||||
|
1000,-50,4,3,0,100,0,0
|
||||||
|
|
||||||
|
// Uninherited: none, inherited: omit (should be ignored, inheriting cannot omit)
|
||||||
|
2000,500,4,2,0,100,1,0
|
||||||
|
2000,-50,4,3,0,100,0,8
|
||||||
|
|
||||||
|
// Inherited: none, uninherited: none
|
||||||
|
3000,-50,4,3,0,100,0,0
|
||||||
|
3000,500,4,2,0,100,1,0
|
||||||
|
|
||||||
|
// Inherited: omit, uninherited: none (should be ignored, inheriting cannot omit)
|
||||||
|
4000,-50,4,3,0,100,0,8
|
||||||
|
4000,500,4,2,0,100,1,0
|
||||||
|
|
||||||
|
// Inherited: none, uninherited: omit
|
||||||
|
5000,-50,4,3,0,100,0,0
|
||||||
|
5000,500,4,2,0,100,1,8
|
@ -48,7 +48,9 @@ namespace osu.Game.Tests.Skins
|
|||||||
// Covers BPM counter.
|
// Covers BPM counter.
|
||||||
"Archives/modified-default-20221205.osk",
|
"Archives/modified-default-20221205.osk",
|
||||||
// Covers judgement counter.
|
// Covers judgement counter.
|
||||||
"Archives/modified-default-20230117.osk"
|
"Archives/modified-default-20230117.osk",
|
||||||
|
// Covers player avatar and flag.
|
||||||
|
"Archives/modified-argon-20230305.osk",
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Overlays.Settings;
|
|||||||
using osu.Game.Overlays.SkinEditor;
|
using osu.Game.Overlays.SkinEditor;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Screens.Edit.Components;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
using osu.Game.Screens.Play.HUD.HitErrorMeters;
|
||||||
using osu.Game.Tests.Beatmaps.IO;
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
@ -188,6 +189,33 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddUntilStep("mod overlay closed", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
AddUntilStep("mod overlay closed", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChangeToNonSkinnableScreen()
|
||||||
|
{
|
||||||
|
advanceToSongSelect();
|
||||||
|
openSkinEditor();
|
||||||
|
AddAssert("blueprint container present", () => skinEditor.ChildrenOfType<SkinBlueprintContainer>().Count(), () => Is.EqualTo(1));
|
||||||
|
AddAssert("placeholder not present", () => skinEditor.ChildrenOfType<NonSkinnableScreenPlaceholder>().Count(), () => Is.Zero);
|
||||||
|
AddAssert("editor sidebars not empty", () => skinEditor.ChildrenOfType<EditorSidebar>().SelectMany(sidebar => sidebar.Children).Count(), () => Is.GreaterThan(0));
|
||||||
|
|
||||||
|
AddStep("add skinnable component", () =>
|
||||||
|
{
|
||||||
|
skinEditor.ChildrenOfType<SkinComponentToolbox.ToolboxComponentButton>().First().TriggerClick();
|
||||||
|
});
|
||||||
|
AddUntilStep("newly added component selected", () => skinEditor.SelectedComponents, () => Has.Count.EqualTo(1));
|
||||||
|
|
||||||
|
AddStep("exit to main menu", () => Game.ScreenStack.CurrentScreen.Exit());
|
||||||
|
AddAssert("selection cleared", () => skinEditor.SelectedComponents, () => Has.Count.Zero);
|
||||||
|
AddAssert("blueprint container not present", () => skinEditor.ChildrenOfType<SkinBlueprintContainer>().Count(), () => Is.Zero);
|
||||||
|
AddAssert("placeholder present", () => skinEditor.ChildrenOfType<NonSkinnableScreenPlaceholder>().Count(), () => Is.EqualTo(1));
|
||||||
|
AddAssert("editor sidebars empty", () => skinEditor.ChildrenOfType<EditorSidebar>().SelectMany(sidebar => sidebar.Children).Count(), () => Is.Zero);
|
||||||
|
|
||||||
|
advanceToSongSelect();
|
||||||
|
AddAssert("blueprint container present", () => skinEditor.ChildrenOfType<SkinBlueprintContainer>().Count(), () => Is.EqualTo(1));
|
||||||
|
AddAssert("placeholder not present", () => skinEditor.ChildrenOfType<NonSkinnableScreenPlaceholder>().Count(), () => Is.Zero);
|
||||||
|
AddAssert("editor sidebars not empty", () => skinEditor.ChildrenOfType<EditorSidebar>().SelectMany(sidebar => sidebar.Children).Count(), () => Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
private void advanceToSongSelect()
|
private void advanceToSongSelect()
|
||||||
{
|
{
|
||||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||||
|
@ -516,15 +516,20 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
sets.Clear();
|
sets.Clear();
|
||||||
|
|
||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
var set = TestResources.CreateTestBeatmapSetInfo(5);
|
var set = TestResources.CreateTestBeatmapSetInfo(5);
|
||||||
|
|
||||||
if (i >= 2 && i < 10)
|
// A total of 6 sets have date submitted (4 don't)
|
||||||
|
// A total of 5 sets have artist string (3 of which also have date submitted)
|
||||||
|
|
||||||
|
if (i >= 2 && i < 8) // i = 2, 3, 4, 5, 6, 7 have submitted date
|
||||||
set.DateSubmitted = DateTimeOffset.Now.AddMinutes(i);
|
set.DateSubmitted = DateTimeOffset.Now.AddMinutes(i);
|
||||||
if (i < 5)
|
if (i < 5) // i = 0, 1, 2, 3, 4 have matching string
|
||||||
set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string);
|
set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string);
|
||||||
|
|
||||||
|
set.Beatmaps.ForEach(b => b.Metadata.Title = $"submitted: {set.DateSubmitted}");
|
||||||
|
|
||||||
sets.Add(set);
|
sets.Add(set);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -532,15 +537,26 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
loadBeatmaps(sets);
|
loadBeatmaps(sets);
|
||||||
|
|
||||||
AddStep("Sort by date submitted", () => carousel.Filter(new FilterCriteria { Sort = SortMode.DateSubmitted }, false));
|
AddStep("Sort by date submitted", () => carousel.Filter(new FilterCriteria { Sort = SortMode.DateSubmitted }, false));
|
||||||
checkVisibleItemCount(diff: false, count: 8);
|
checkVisibleItemCount(diff: false, count: 10);
|
||||||
checkVisibleItemCount(diff: true, count: 5);
|
checkVisibleItemCount(diff: true, count: 5);
|
||||||
|
|
||||||
|
AddAssert("missing date are at end",
|
||||||
|
() => carousel.Items.OfType<DrawableCarouselBeatmapSet>().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(4));
|
||||||
|
AddAssert("rest are at start", () => carousel.Items.OfType<DrawableCarouselBeatmapSet>().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(),
|
||||||
|
() => Is.EqualTo(6));
|
||||||
|
|
||||||
AddStep("Sort by date submitted and string", () => carousel.Filter(new FilterCriteria
|
AddStep("Sort by date submitted and string", () => carousel.Filter(new FilterCriteria
|
||||||
{
|
{
|
||||||
Sort = SortMode.DateSubmitted,
|
Sort = SortMode.DateSubmitted,
|
||||||
SearchText = zzz_string
|
SearchText = zzz_string
|
||||||
}, false));
|
}, false));
|
||||||
checkVisibleItemCount(diff: false, count: 3);
|
checkVisibleItemCount(diff: false, count: 5);
|
||||||
checkVisibleItemCount(diff: true, count: 5);
|
checkVisibleItemCount(diff: true, count: 5);
|
||||||
|
|
||||||
|
AddAssert("missing date are at end",
|
||||||
|
() => carousel.Items.OfType<DrawableCarouselBeatmapSet>().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(2));
|
||||||
|
AddAssert("rest are at start", () => carousel.Items.OfType<DrawableCarouselBeatmapSet>().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(),
|
||||||
|
() => Is.EqualTo(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -1129,7 +1145,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
// until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet.
|
// until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet.
|
||||||
AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () =>
|
AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () =>
|
||||||
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible), () => Is.EqualTo(count));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSelectionIsCentered()
|
private void checkSelectionIsCentered()
|
||||||
@ -1190,8 +1206,11 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
foreach (var item in Scroll.Children)
|
foreach (var item in Scroll.Children.OrderBy(c => c.Y))
|
||||||
{
|
{
|
||||||
|
if (item.Item?.Visible != true)
|
||||||
|
continue;
|
||||||
|
|
||||||
yield return item;
|
yield return item;
|
||||||
|
|
||||||
if (item is DrawableCarouselBeatmapSet set)
|
if (item is DrawableCarouselBeatmapSet set)
|
||||||
|
@ -61,6 +61,18 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddStep("scroll to 500", () => scroll.ScrollTo(500));
|
AddStep("scroll to 500", () => scroll.ScrollTo(500));
|
||||||
AddUntilStep("scrolled to 500", () => Precision.AlmostEquals(scroll.Current, 500, 0.1f));
|
AddUntilStep("scrolled to 500", () => Precision.AlmostEquals(scroll.Current, 500, 0.1f));
|
||||||
AddAssert("button is visible", () => scroll.Button.State == Visibility.Visible);
|
AddAssert("button is visible", () => scroll.Button.State == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("click button", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(scroll.Button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("button is visible", () => scroll.Button.State == Visibility.Visible);
|
||||||
|
|
||||||
|
AddStep("user scroll down by 1", () => InputManager.ScrollVerticalBy(-1));
|
||||||
|
|
||||||
|
AddAssert("button is hidden", () => scroll.Button.State == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -71,6 +83,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddStep("invoke action", () => scroll.Button.Action.Invoke());
|
AddStep("invoke action", () => scroll.Button.Action.Invoke());
|
||||||
|
|
||||||
AddUntilStep("scrolled back to start", () => Precision.AlmostEquals(scroll.Current, 0, 0.1f));
|
AddUntilStep("scrolled back to start", () => Precision.AlmostEquals(scroll.Current, 0, 0.1f));
|
||||||
|
|
||||||
|
AddStep("invoke action", () => scroll.Button.Action.Invoke());
|
||||||
|
|
||||||
|
AddAssert("scrolled to end", () => scroll.IsScrolledToEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -85,6 +101,14 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("scrolled back to start", () => Precision.AlmostEquals(scroll.Current, 0, 0.1f));
|
AddUntilStep("scrolled back to start", () => Precision.AlmostEquals(scroll.Current, 0, 0.1f));
|
||||||
|
|
||||||
|
AddStep("click button", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(scroll.Button);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("scrolled to end", () => scroll.IsScrolledToEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -97,12 +121,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddStep("hover button", () => InputManager.MoveMouseTo(scroll.Button));
|
AddStep("hover button", () => InputManager.MoveMouseTo(scroll.Button));
|
||||||
AddRepeatStep("click button", () => InputManager.Click(MouseButton.Left), 3);
|
AddRepeatStep("click button", () => InputManager.Click(MouseButton.Left), 3);
|
||||||
|
|
||||||
AddAssert("invocation count is 1", () => invocationCount == 1);
|
AddAssert("invocation count is 3", () => invocationCount == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private partial class TestScrollContainer : OverlayScrollContainer
|
private partial class TestScrollContainer : OverlayScrollContainer
|
||||||
{
|
{
|
||||||
public new ScrollToTopButton Button => base.Button;
|
public new ScrollBackButton Button => base.Button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +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 System.Linq;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -29,10 +29,21 @@ namespace osu.Game.Beatmaps
|
|||||||
return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim());
|
return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
|
public static List<string> GetSearchableTerms(this IBeatmapInfo beatmapInfo)
|
||||||
{
|
{
|
||||||
beatmapInfo.DifficultyName
|
var termsList = new List<string>(BeatmapMetadataInfoExtensions.MAX_SEARCHABLE_TERM_COUNT + 1);
|
||||||
}.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
|
||||||
|
addIfNotNull(beatmapInfo.DifficultyName);
|
||||||
|
|
||||||
|
BeatmapMetadataInfoExtensions.CollectSearchableTerms(beatmapInfo.Metadata, termsList);
|
||||||
|
return termsList;
|
||||||
|
|
||||||
|
void addIfNotNull(string? s)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(s))
|
||||||
|
termsList.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -13,16 +13,31 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An array of all searchable terms provided in contained metadata.
|
/// An array of all searchable terms provided in contained metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo) => new[]
|
public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo)
|
||||||
{
|
{
|
||||||
metadataInfo.Author.Username,
|
var termsList = new List<string>(MAX_SEARCHABLE_TERM_COUNT);
|
||||||
metadataInfo.Artist,
|
CollectSearchableTerms(metadataInfo, termsList);
|
||||||
metadataInfo.ArtistUnicode,
|
return termsList.ToArray();
|
||||||
metadataInfo.Title,
|
}
|
||||||
metadataInfo.TitleUnicode,
|
|
||||||
metadataInfo.Source,
|
internal const int MAX_SEARCHABLE_TERM_COUNT = 7;
|
||||||
metadataInfo.Tags
|
|
||||||
}.Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
internal static void CollectSearchableTerms(IBeatmapMetadataInfo metadataInfo, IList<string> termsList)
|
||||||
|
{
|
||||||
|
addIfNotNull(metadataInfo.Author.Username);
|
||||||
|
addIfNotNull(metadataInfo.Artist);
|
||||||
|
addIfNotNull(metadataInfo.ArtistUnicode);
|
||||||
|
addIfNotNull(metadataInfo.Title);
|
||||||
|
addIfNotNull(metadataInfo.TitleUnicode);
|
||||||
|
addIfNotNull(metadataInfo.Source);
|
||||||
|
addIfNotNull(metadataInfo.Tags);
|
||||||
|
|
||||||
|
void addIfNotNull(string s)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(s))
|
||||||
|
termsList.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A user-presentable display title representing this metadata.
|
/// A user-presentable display title representing this metadata.
|
||||||
|
@ -13,15 +13,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
public static readonly EffectControlPoint DEFAULT = new EffectControlPoint
|
public static readonly EffectControlPoint DEFAULT = new EffectControlPoint
|
||||||
{
|
{
|
||||||
KiaiModeBindable = { Disabled = true },
|
KiaiModeBindable = { Disabled = true },
|
||||||
OmitFirstBarLineBindable = { Disabled = true },
|
|
||||||
ScrollSpeedBindable = { Disabled = true }
|
ScrollSpeedBindable = { Disabled = true }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the first bar line of this control point is ignored.
|
|
||||||
/// </summary>
|
|
||||||
public readonly BindableBool OmitFirstBarLineBindable = new BindableBool();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The relative scroll speed at this control point.
|
/// The relative scroll speed at this control point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -43,15 +37,6 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
|
|
||||||
public override Color4 GetRepresentingColour(OsuColour colours) => colours.Purple;
|
public override Color4 GetRepresentingColour(OsuColour colours) => colours.Purple;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the first bar line of this control point is ignored.
|
|
||||||
/// </summary>
|
|
||||||
public bool OmitFirstBarLine
|
|
||||||
{
|
|
||||||
get => OmitFirstBarLineBindable.Value;
|
|
||||||
set => OmitFirstBarLineBindable.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this control point enables Kiai mode.
|
/// Whether this control point enables Kiai mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -67,16 +52,13 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsRedundant(ControlPoint? existing)
|
public override bool IsRedundant(ControlPoint? existing)
|
||||||
=> !OmitFirstBarLine
|
=> existing is EffectControlPoint existingEffect
|
||||||
&& existing is EffectControlPoint existingEffect
|
|
||||||
&& KiaiMode == existingEffect.KiaiMode
|
&& KiaiMode == existingEffect.KiaiMode
|
||||||
&& OmitFirstBarLine == existingEffect.OmitFirstBarLine
|
|
||||||
&& ScrollSpeed == existingEffect.ScrollSpeed;
|
&& ScrollSpeed == existingEffect.ScrollSpeed;
|
||||||
|
|
||||||
public override void CopyFrom(ControlPoint other)
|
public override void CopyFrom(ControlPoint other)
|
||||||
{
|
{
|
||||||
KiaiMode = ((EffectControlPoint)other).KiaiMode;
|
KiaiMode = ((EffectControlPoint)other).KiaiMode;
|
||||||
OmitFirstBarLine = ((EffectControlPoint)other).OmitFirstBarLine;
|
|
||||||
ScrollSpeed = ((EffectControlPoint)other).ScrollSpeed;
|
ScrollSpeed = ((EffectControlPoint)other).ScrollSpeed;
|
||||||
|
|
||||||
base.CopyFrom(other);
|
base.CopyFrom(other);
|
||||||
@ -88,10 +70,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
|
|
||||||
public bool Equals(EffectControlPoint? other)
|
public bool Equals(EffectControlPoint? other)
|
||||||
=> base.Equals(other)
|
=> base.Equals(other)
|
||||||
&& OmitFirstBarLine == other.OmitFirstBarLine
|
|
||||||
&& ScrollSpeed == other.ScrollSpeed
|
&& ScrollSpeed == other.ScrollSpeed
|
||||||
&& KiaiMode == other.KiaiMode;
|
&& KiaiMode == other.KiaiMode;
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), OmitFirstBarLine, ScrollSpeed, KiaiMode);
|
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), ScrollSpeed, KiaiMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,11 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<TimeSignature> TimeSignatureBindable = new Bindable<TimeSignature>(TimeSignature.SimpleQuadruple);
|
public readonly Bindable<TimeSignature> TimeSignatureBindable = new Bindable<TimeSignature>(TimeSignature.SimpleQuadruple);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the first bar line of this control point is ignored.
|
||||||
|
/// </summary>
|
||||||
|
public readonly BindableBool OmitFirstBarLineBindable = new BindableBool();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
|
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -30,6 +35,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
Value = default_beat_length,
|
Value = default_beat_length,
|
||||||
Disabled = true
|
Disabled = true
|
||||||
},
|
},
|
||||||
|
OmitFirstBarLineBindable = { Disabled = true },
|
||||||
TimeSignatureBindable = { Disabled = true }
|
TimeSignatureBindable = { Disabled = true }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,6 +48,15 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
set => TimeSignatureBindable.Value = value;
|
set => TimeSignatureBindable.Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the first bar line of this control point is ignored.
|
||||||
|
/// </summary>
|
||||||
|
public bool OmitFirstBarLine
|
||||||
|
{
|
||||||
|
get => OmitFirstBarLineBindable.Value;
|
||||||
|
set => OmitFirstBarLineBindable.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
public const double DEFAULT_BEAT_LENGTH = 1000;
|
public const double DEFAULT_BEAT_LENGTH = 1000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -73,6 +88,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
public override void CopyFrom(ControlPoint other)
|
public override void CopyFrom(ControlPoint other)
|
||||||
{
|
{
|
||||||
TimeSignature = ((TimingControlPoint)other).TimeSignature;
|
TimeSignature = ((TimingControlPoint)other).TimeSignature;
|
||||||
|
OmitFirstBarLine = ((TimingControlPoint)other).OmitFirstBarLine;
|
||||||
BeatLength = ((TimingControlPoint)other).BeatLength;
|
BeatLength = ((TimingControlPoint)other).BeatLength;
|
||||||
|
|
||||||
base.CopyFrom(other);
|
base.CopyFrom(other);
|
||||||
@ -85,8 +101,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
public bool Equals(TimingControlPoint? other)
|
public bool Equals(TimingControlPoint? other)
|
||||||
=> base.Equals(other)
|
=> base.Equals(other)
|
||||||
&& TimeSignature.Equals(other.TimeSignature)
|
&& TimeSignature.Equals(other.TimeSignature)
|
||||||
|
&& OmitFirstBarLine == other.OmitFirstBarLine
|
||||||
&& BeatLength.Equals(other.BeatLength);
|
&& BeatLength.Equals(other.BeatLength);
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), TimeSignature, BeatLength);
|
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), TimeSignature, BeatLength, OmitFirstBarLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,6 +431,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
controlPoint.BeatLength = beatLength;
|
controlPoint.BeatLength = beatLength;
|
||||||
controlPoint.TimeSignature = timeSignature;
|
controlPoint.TimeSignature = timeSignature;
|
||||||
|
controlPoint.OmitFirstBarLine = omitFirstBarSignature;
|
||||||
|
|
||||||
addControlPoint(time, controlPoint, true);
|
addControlPoint(time, controlPoint, true);
|
||||||
}
|
}
|
||||||
@ -447,7 +448,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
var effectPoint = new EffectControlPoint
|
var effectPoint = new EffectControlPoint
|
||||||
{
|
{
|
||||||
KiaiMode = kiaiMode,
|
KiaiMode = kiaiMode,
|
||||||
OmitFirstBarLine = omitFirstBarSignature,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments.
|
// osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments.
|
||||||
|
@ -222,6 +222,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
var samplePoint = legacyControlPoints.SamplePointAt(time);
|
var samplePoint = legacyControlPoints.SamplePointAt(time);
|
||||||
var effectPoint = legacyControlPoints.EffectPointAt(time);
|
var effectPoint = legacyControlPoints.EffectPointAt(time);
|
||||||
|
var timingPoint = legacyControlPoints.TimingPointAt(time);
|
||||||
|
|
||||||
// Apply the control point to a hit sample to uncover legacy properties (e.g. suffix)
|
// Apply the control point to a hit sample to uncover legacy properties (e.g. suffix)
|
||||||
HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo(string.Empty));
|
HitSampleInfo tempHitSample = samplePoint.ApplyTo(new ConvertHitObjectParser.LegacyHitSampleInfo(string.Empty));
|
||||||
@ -230,10 +231,10 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
LegacyEffectFlags effectFlags = LegacyEffectFlags.None;
|
LegacyEffectFlags effectFlags = LegacyEffectFlags.None;
|
||||||
if (effectPoint.KiaiMode)
|
if (effectPoint.KiaiMode)
|
||||||
effectFlags |= LegacyEffectFlags.Kiai;
|
effectFlags |= LegacyEffectFlags.Kiai;
|
||||||
if (effectPoint.OmitFirstBarLine)
|
if (timingPoint.OmitFirstBarLine)
|
||||||
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
effectFlags |= LegacyEffectFlags.OmitFirstBarLine;
|
||||||
|
|
||||||
writer.Write(FormattableString.Invariant($"{legacyControlPoints.TimingPointAt(time).TimeSignature.Numerator},"));
|
writer.Write(FormattableString.Invariant($"{timingPoint.TimeSignature.Numerator},"));
|
||||||
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
writer.Write(FormattableString.Invariant($"{(int)toLegacySampleBank(tempHitSample.Bank)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
|
writer.Write(FormattableString.Invariant($"{toLegacyCustomSampleBank(tempHitSample)},"));
|
||||||
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
writer.Write(FormattableString.Invariant($"{tempHitSample.Volume},"));
|
||||||
|
@ -8,12 +8,12 @@ using osu.Game.Overlays.Dialog;
|
|||||||
|
|
||||||
namespace osu.Game.Collections
|
namespace osu.Game.Collections
|
||||||
{
|
{
|
||||||
public partial class DeleteCollectionDialog : DeleteConfirmationDialog
|
public partial class DeleteCollectionDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
public DeleteCollectionDialog(Live<BeatmapCollection> collection, Action deleteAction)
|
public DeleteCollectionDialog(Live<BeatmapCollection> collection, Action deleteAction)
|
||||||
{
|
{
|
||||||
BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})");
|
BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})");
|
||||||
DeleteAction = deleteAction;
|
DangerousAction = deleteAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -19,6 +20,19 @@ namespace osu.Game.Database
|
|||||||
public abstract class LegacyExporter<TModel>
|
public abstract class LegacyExporter<TModel>
|
||||||
where TModel : class, IHasNamedFiles
|
where TModel : class, IHasNamedFiles
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Max length of filename (including extension).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The filename limit for most OSs is 255. This actual usable length is smaller because <see cref="Storage.CreateFileSafely(string)"/> adds an additional "_<see cref="Guid"/>" to the end of the path.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For more information see <see href="https://www.ibm.com/docs/en/spectrum-protect/8.1.9?topic=parameters-file-specification-syntax">file specification syntax</see>, <seealso href="https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits">file systems limitations</seealso>
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2 + 5); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars + account for ' (99)' suffix)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The file extension for exports (including the leading '.').
|
/// The file extension for exports (including the leading '.').
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -44,12 +58,16 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
string itemFilename = GetFilename(item).GetValidFilename();
|
string itemFilename = GetFilename(item).GetValidFilename();
|
||||||
|
|
||||||
|
if (itemFilename.Length > MAX_FILENAME_LENGTH - FileExtension.Length)
|
||||||
|
itemFilename = itemFilename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
|
||||||
|
|
||||||
IEnumerable<string> existingExports =
|
IEnumerable<string> existingExports =
|
||||||
exportStorage
|
exportStorage
|
||||||
.GetFiles(string.Empty, $"{itemFilename}*{FileExtension}")
|
.GetFiles(string.Empty, $"{itemFilename}*{FileExtension}")
|
||||||
.Concat(exportStorage.GetDirectories(string.Empty));
|
.Concat(exportStorage.GetDirectories(string.Empty));
|
||||||
|
|
||||||
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
|
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
|
||||||
|
|
||||||
using (var stream = exportStorage.CreateFileSafely(filename))
|
using (var stream = exportStorage.CreateFileSafely(filename))
|
||||||
ExportModelTo(item, stream);
|
ExportModelTo(item, stream);
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ using osu.Framework.Allocation;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics.Rendering;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Rendering.Vertices;
|
using osu.Framework.Graphics.Rendering.Vertices;
|
||||||
using osu.Framework.Graphics.Colour;
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
@ -259,8 +258,6 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
Vector2Extensions.Transform(triangleQuad.BottomRight * size, DrawInfo.Matrix)
|
Vector2Extensions.Transform(triangleQuad.BottomRight * size, DrawInfo.Matrix)
|
||||||
);
|
);
|
||||||
|
|
||||||
ColourInfo colourInfo = triangleColourInfo(DrawColourInfo.Colour, triangleQuad);
|
|
||||||
|
|
||||||
RectangleF textureCoords = new RectangleF(
|
RectangleF textureCoords = new RectangleF(
|
||||||
triangleQuad.TopLeft.X - topLeft.X,
|
triangleQuad.TopLeft.X - topLeft.X,
|
||||||
triangleQuad.TopLeft.Y - topLeft.Y,
|
triangleQuad.TopLeft.Y - topLeft.Y,
|
||||||
@ -268,23 +265,12 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
triangleQuad.Height
|
triangleQuad.Height
|
||||||
) / relativeSize;
|
) / relativeSize;
|
||||||
|
|
||||||
renderer.DrawQuad(texture, drawQuad, colourInfo, new RectangleF(0, 0, 1, 1), vertexBatch.AddAction, textureCoords: textureCoords);
|
renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour.Interpolate(triangleQuad), new RectangleF(0, 0, 1, 1), vertexBatch.AddAction, textureCoords: textureCoords);
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.Unbind();
|
shader.Unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ColourInfo triangleColourInfo(ColourInfo source, Quad quad)
|
|
||||||
{
|
|
||||||
return new ColourInfo
|
|
||||||
{
|
|
||||||
TopLeft = source.Interpolate(quad.TopLeft),
|
|
||||||
TopRight = source.Interpolate(quad.TopRight),
|
|
||||||
BottomLeft = source.Interpolate(quad.BottomLeft),
|
|
||||||
BottomRight = source.Interpolate(quad.BottomRight)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Quad clampToDrawable(Vector2 topLeft, Vector2 size)
|
private static Quad clampToDrawable(Vector2 topLeft, Vector2 size)
|
||||||
{
|
{
|
||||||
float leftClamped = Math.Clamp(topLeft.X, 0f, 1f);
|
float leftClamped = Math.Clamp(topLeft.X, 0f, 1f);
|
||||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
while (beatLength < MinimumBeatLength)
|
while (beatLength < MinimumBeatLength)
|
||||||
beatLength *= 2;
|
beatLength *= 2;
|
||||||
|
|
||||||
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / beatLength) - (effectPoint.OmitFirstBarLine ? 1 : 0);
|
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / beatLength) - (timingPoint.OmitFirstBarLine ? 1 : 0);
|
||||||
|
|
||||||
// The beats before the start of the first control point are off by 1, this should do the trick
|
// The beats before the start of the first control point are off by 1, this should do the trick
|
||||||
if (currentTrackTime < timingPoint.Time)
|
if (currentTrackTime < timingPoint.Time)
|
||||||
|
@ -249,13 +249,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
private ColourInfo getSegmentColour(SegmentInfo segment)
|
private ColourInfo getSegmentColour(SegmentInfo segment)
|
||||||
{
|
{
|
||||||
var segmentColour = new ColourInfo
|
var segmentColour = DrawColourInfo.Colour.Interpolate(new Quad(segment.Start, 0f, segment.End - segment.Start, 1f));
|
||||||
{
|
|
||||||
TopLeft = DrawColourInfo.Colour.Interpolate(new Vector2(segment.Start, 0f)),
|
|
||||||
TopRight = DrawColourInfo.Colour.Interpolate(new Vector2(segment.End, 0f)),
|
|
||||||
BottomLeft = DrawColourInfo.Colour.Interpolate(new Vector2(segment.Start, 1f)),
|
|
||||||
BottomRight = DrawColourInfo.Colour.Interpolate(new Vector2(segment.End, 1f))
|
|
||||||
};
|
|
||||||
|
|
||||||
var tierColour = segment.Tier >= 0 ? tierColours[segment.Tier] : new Colour4(0, 0, 0, 0);
|
var tierColour = segment.Tier >= 0 ? tierColours[segment.Tier] : new Colour4(0, 0, 0, 0);
|
||||||
segmentColour.ApplyChild(tierColour);
|
segmentColour.ApplyChild(tierColour);
|
||||||
|
@ -39,6 +39,16 @@ namespace osu.Game.Localisation.SkinComponents
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed.");
|
public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Corner radius"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString CornerRadius => new TranslatableString(getKey(@"corner_radius"), "Corner radius");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "How rounded the corners should be."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString CornerRadiusDescription => new TranslatableString(getKey(@"corner_radius_description"), "How rounded the corners should be.");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,12 @@ namespace osu.Game.Localisation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Currently editing"
|
/// "Currently editing"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Currently editing");
|
public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "All layout elements for layers in the current screen will be reset to defaults."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString RevertToDefaultDescription => new TranslatableString(getKey(@"revert_to_default_description"), @"All layout elements for layers in the current screen will be reset to defaults.");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
private const float chatting_text_width = 220;
|
private const float chatting_text_width = 220;
|
||||||
private const float search_icon_width = 40;
|
private const float search_icon_width = 40;
|
||||||
|
private const float padding = 5;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
@ -71,9 +72,10 @@ namespace osu.Game.Overlays.Chat
|
|||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = chatting_text_width,
|
Width = chatting_text_width,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Padding = new MarginPadding { Right = 5 },
|
Padding = new MarginPadding { Horizontal = padding },
|
||||||
Child = chattingText = new OsuSpriteText
|
Child = chattingText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
|
MaxWidth = chatting_text_width - padding * 2,
|
||||||
Font = OsuFont.Torus.With(size: 20),
|
Font = OsuFont.Torus.With(size: 20),
|
||||||
Colour = colourProvider.Background1,
|
Colour = colourProvider.Background1,
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
@ -97,7 +99,7 @@ namespace osu.Game.Overlays.Chat
|
|||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Right = 5 },
|
Padding = new MarginPadding { Right = padding },
|
||||||
Child = chatTextBox = new ChatTextBox
|
Child = chatTextBox = new ChatTextBox
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
|
@ -8,18 +8,22 @@ using osu.Game.Localisation;
|
|||||||
namespace osu.Game.Overlays.Dialog
|
namespace osu.Game.Overlays.Dialog
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base class for various confirmation dialogs that concern deletion actions.
|
/// A dialog which provides confirmation for actions which result in permanent consequences.
|
||||||
/// Differs from <see cref="ConfirmDialog"/> in that the confirmation button is a "dangerous" one
|
/// Differs from <see cref="ConfirmDialog"/> in that the confirmation button is a "dangerous" one
|
||||||
/// (requires the confirm button to be held).
|
/// (requires the confirm button to be held).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract partial class DeleteConfirmationDialog : PopupDialog
|
/// <remarks>
|
||||||
|
/// The default implementation comes with text for a generic deletion operation.
|
||||||
|
/// This can be further customised by specifying custom <see cref="PopupDialog.HeaderText"/>.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract partial class DangerousActionDialog : PopupDialog
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The action which performs the deletion.
|
/// The action which performs the deletion.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Action? DeleteAction { get; set; }
|
protected Action? DangerousAction { get; set; }
|
||||||
|
|
||||||
protected DeleteConfirmationDialog()
|
protected DangerousActionDialog()
|
||||||
{
|
{
|
||||||
HeaderText = DeleteConfirmationDialogStrings.HeaderText;
|
HeaderText = DeleteConfirmationDialogStrings.HeaderText;
|
||||||
|
|
||||||
@ -30,7 +34,7 @@ namespace osu.Game.Overlays.Dialog
|
|||||||
new PopupDialogDangerousButton
|
new PopupDialogDangerousButton
|
||||||
{
|
{
|
||||||
Text = DeleteConfirmationDialogStrings.Confirm,
|
Text = DeleteConfirmationDialogStrings.Confirm,
|
||||||
Action = () => DeleteAction?.Invoke()
|
Action = () => DangerousAction?.Invoke()
|
||||||
},
|
},
|
||||||
new PopupDialogCancelButton
|
new PopupDialogCancelButton
|
||||||
{
|
{
|
@ -7,12 +7,12 @@ using osu.Game.Rulesets.Mods;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.Mods
|
namespace osu.Game.Overlays.Mods
|
||||||
{
|
{
|
||||||
public partial class DeleteModPresetDialog : DeleteConfirmationDialog
|
public partial class DeleteModPresetDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
public DeleteModPresetDialog(Live<ModPreset> modPreset)
|
public DeleteModPresetDialog(Live<ModPreset> modPreset)
|
||||||
{
|
{
|
||||||
BodyText = modPreset.PerformRead(preset => preset.Name);
|
BodyText = modPreset.PerformRead(preset => preset.Name);
|
||||||
DeleteAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true);
|
DangerousAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -21,25 +22,29 @@ using osuTK.Graphics;
|
|||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="UserTrackingScrollContainer"/> which provides <see cref="ScrollToTopButton"/>. Mostly used in <see cref="FullscreenOverlay{T}"/>.
|
/// <see cref="UserTrackingScrollContainer"/> which provides <see cref="ScrollBackButton"/>. Mostly used in <see cref="FullscreenOverlay{T}"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class OverlayScrollContainer : UserTrackingScrollContainer
|
public partial class OverlayScrollContainer : UserTrackingScrollContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scroll position at which the <see cref="ScrollToTopButton"/> will be shown.
|
/// Scroll position at which the <see cref="ScrollBackButton"/> will be shown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int button_scroll_position = 200;
|
private const int button_scroll_position = 200;
|
||||||
|
|
||||||
protected readonly ScrollToTopButton Button;
|
protected ScrollBackButton Button;
|
||||||
|
|
||||||
public OverlayScrollContainer()
|
private readonly Bindable<float?> lastScrollTarget = new Bindable<float?>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
AddInternal(Button = new ScrollToTopButton
|
AddInternal(Button = new ScrollBackButton
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.BottomRight,
|
Origin = Anchor.BottomRight,
|
||||||
Margin = new MarginPadding(20),
|
Margin = new MarginPadding(20),
|
||||||
Action = scrollToTop
|
Action = scrollBack,
|
||||||
|
LastScrollTarget = { BindTarget = lastScrollTarget }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,16 +58,31 @@ namespace osu.Game.Overlays
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button.State = Target > button_scroll_position ? Visibility.Visible : Visibility.Hidden;
|
Button.State = Target > button_scroll_position || lastScrollTarget.Value != null ? Visibility.Visible : Visibility.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollToTop()
|
protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = default)
|
||||||
{
|
{
|
||||||
ScrollToStart();
|
base.OnUserScroll(value, animated, distanceDecay);
|
||||||
Button.State = Visibility.Hidden;
|
|
||||||
|
lastScrollTarget.Value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class ScrollToTopButton : OsuHoverContainer
|
private void scrollBack()
|
||||||
|
{
|
||||||
|
if (lastScrollTarget.Value == null)
|
||||||
|
{
|
||||||
|
lastScrollTarget.Value = Target;
|
||||||
|
ScrollToStart();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScrollTo(lastScrollTarget.Value.Value);
|
||||||
|
lastScrollTarget.Value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ScrollBackButton : OsuHoverContainer
|
||||||
{
|
{
|
||||||
private const int fade_duration = 500;
|
private const int fade_duration = 500;
|
||||||
|
|
||||||
@ -88,8 +108,11 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
private readonly Box background;
|
private readonly Box background;
|
||||||
|
private readonly SpriteIcon spriteIcon;
|
||||||
|
|
||||||
public ScrollToTopButton()
|
public Bindable<float?> LastScrollTarget = new Bindable<float?>();
|
||||||
|
|
||||||
|
public ScrollBackButton()
|
||||||
: base(HoverSampleSet.ScrollToTop)
|
: base(HoverSampleSet.ScrollToTop)
|
||||||
{
|
{
|
||||||
Size = new Vector2(50);
|
Size = new Vector2(50);
|
||||||
@ -113,7 +136,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
new SpriteIcon
|
spriteIcon = new SpriteIcon
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -134,6 +157,17 @@ namespace osu.Game.Overlays
|
|||||||
flashColour = colourProvider.Light1;
|
flashColour = colourProvider.Light1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
LastScrollTarget.BindValueChanged(target =>
|
||||||
|
{
|
||||||
|
spriteIcon.RotateTo(target.NewValue != null ? 180 : 0, fade_duration, Easing.OutQuint);
|
||||||
|
TooltipText = target.NewValue != null ? CommonStrings.ButtonsBackToPrevious : CommonStrings.ButtonsBackToTop;
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
background.FlashColour(flashColour, 800, Easing.OutQuint);
|
background.FlashColour(flashColour, 800, Easing.OutQuint);
|
||||||
|
@ -6,12 +6,12 @@ using osu.Game.Overlays.Dialog;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||||
{
|
{
|
||||||
public partial class MassDeleteConfirmationDialog : DeleteConfirmationDialog
|
public partial class MassDeleteConfirmationDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
public MassDeleteConfirmationDialog(Action deleteAction)
|
public MassDeleteConfirmationDialog(Action deleteAction)
|
||||||
{
|
{
|
||||||
BodyText = "Everything?";
|
BodyText = "Everything?";
|
||||||
DeleteAction = deleteAction;
|
DangerousAction = deleteAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
osu.Game/Overlays/Settings/SettingsPercentageSlider.cs
Normal file
20
osu.Game/Overlays/Settings/SettingsPercentageSlider.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="SettingsSlider{TValue,TSlider}"/> that displays its value as a percentage by default.
|
||||||
|
/// Mostly provided for convenience of use with <see cref="SettingSourceAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
public partial class SettingsPercentageSlider<TValue> : SettingsSlider<TValue>
|
||||||
|
where TValue : struct, IEquatable<TValue>, IComparable<TValue>, IConvertible
|
||||||
|
{
|
||||||
|
protected override Drawable CreateControl() => ((RoundedSliderBar<TValue>)base.CreateControl()).With(sliderBar => sliderBar.DisplayAsPercentage = true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.SkinEditor
|
||||||
|
{
|
||||||
|
public partial class NonSkinnableScreenPlaceholder : CompositeDrawable
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private SkinEditorOverlay? skinEditorOverlay { get; set; }
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colourProvider)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = colourProvider.Dark6,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0.95f,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Spacing = new Vector2(0, 5),
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Icon = FontAwesome.Solid.ExclamationCircle,
|
||||||
|
Size = new Vector2(24),
|
||||||
|
Y = -5,
|
||||||
|
},
|
||||||
|
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 18))
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
TextAnchor = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Text = "Please navigate to a skinnable screen using the scene library",
|
||||||
|
},
|
||||||
|
new RoundedButton
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Width = 200,
|
||||||
|
Margin = new MarginPadding { Top = 20 },
|
||||||
|
Action = () => skinEditorOverlay?.Hide(),
|
||||||
|
Text = "Return to game"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,15 +7,7 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
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.Input.Events;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -26,16 +18,16 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
{
|
{
|
||||||
public partial class SkinBlueprintContainer : BlueprintContainer<ISerialisableDrawable>
|
public partial class SkinBlueprintContainer : BlueprintContainer<ISerialisableDrawable>
|
||||||
{
|
{
|
||||||
private readonly Drawable target;
|
private readonly ISerialisableDrawableContainer targetContainer;
|
||||||
|
|
||||||
private readonly List<BindableList<ISerialisableDrawable>> targetComponents = new List<BindableList<ISerialisableDrawable>>();
|
private readonly List<BindableList<ISerialisableDrawable>> targetComponents = new List<BindableList<ISerialisableDrawable>>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinEditor editor { get; set; } = null!;
|
private SkinEditor editor { get; set; } = null!;
|
||||||
|
|
||||||
public SkinBlueprintContainer(Drawable target)
|
public SkinBlueprintContainer(ISerialisableDrawableContainer targetContainer)
|
||||||
{
|
{
|
||||||
this.target = target;
|
this.targetContainer = targetContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -44,23 +36,11 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
|
|
||||||
SelectedItems.BindTo(editor.SelectedComponents);
|
SelectedItems.BindTo(editor.SelectedComponents);
|
||||||
|
|
||||||
// track each target container on the current screen.
|
|
||||||
var targetContainers = target.ChildrenOfType<ISerialisableDrawableContainer>().ToArray();
|
|
||||||
|
|
||||||
if (targetContainers.Length == 0)
|
|
||||||
{
|
|
||||||
AddInternal(new NonSkinnableScreenPlaceholder());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var targetContainer in targetContainers)
|
|
||||||
{
|
|
||||||
var bindableList = new BindableList<ISerialisableDrawable> { BindTarget = targetContainer.Components };
|
var bindableList = new BindableList<ISerialisableDrawable> { BindTarget = targetContainer.Components };
|
||||||
bindableList.BindCollectionChanged(componentsChanged, true);
|
bindableList.BindCollectionChanged(componentsChanged, true);
|
||||||
|
|
||||||
targetComponents.Add(bindableList);
|
targetComponents.Add(bindableList);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void componentsChanged(object? sender, NotifyCollectionChangedEventArgs e) => Schedule(() =>
|
private void componentsChanged(object? sender, NotifyCollectionChangedEventArgs e) => Schedule(() =>
|
||||||
{
|
{
|
||||||
@ -160,65 +140,5 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
foreach (var list in targetComponents)
|
foreach (var list in targetComponents)
|
||||||
list.UnbindAll();
|
list.UnbindAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class NonSkinnableScreenPlaceholder : CompositeDrawable
|
|
||||||
{
|
|
||||||
[Resolved]
|
|
||||||
private SkinEditorOverlay? skinEditorOverlay { get; set; }
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OverlayColourProvider colourProvider)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Colour = colourProvider.Dark6,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0.95f,
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Spacing = new Vector2(0, 5),
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new SpriteIcon
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Icon = FontAwesome.Solid.ExclamationCircle,
|
|
||||||
Size = new Vector2(24),
|
|
||||||
Y = -5,
|
|
||||||
},
|
|
||||||
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 18))
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
TextAnchor = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Text = "Please navigate to a skinnable screen using the scene library",
|
|
||||||
},
|
|
||||||
new RoundedButton
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Width = 200,
|
|
||||||
Margin = new MarginPadding { Top = 20 },
|
|
||||||
Action = () => skinEditorOverlay?.Hide(),
|
|
||||||
Text = "Return to game"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Input;
|
|||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using Web = osu.Game.Resources.Localisation.Web;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -24,6 +25,7 @@ using osu.Game.Graphics.Containers;
|
|||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
using osu.Game.Overlays.OSD;
|
using osu.Game.Overlays.OSD;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
@ -97,6 +99,9 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OnScreenDisplay? onScreenDisplay { get; set; }
|
private OnScreenDisplay? onScreenDisplay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
public SkinEditor()
|
public SkinEditor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -147,8 +152,8 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
{
|
{
|
||||||
Items = new[]
|
Items = new[]
|
||||||
{
|
{
|
||||||
new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()),
|
new EditorMenuItem(Web.CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()),
|
||||||
new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert),
|
new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, () => dialogOverlay?.Push(new RevertConfirmDialog(revert))),
|
||||||
new EditorMenuItemSpacer(),
|
new EditorMenuItemSpacer(),
|
||||||
new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()),
|
new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()),
|
||||||
},
|
},
|
||||||
@ -304,7 +309,8 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
changeHandler?.Dispose();
|
changeHandler?.Dispose();
|
||||||
|
|
||||||
// Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target.
|
// Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target.
|
||||||
content?.Clear();
|
if (content?.Child is SkinBlueprintContainer)
|
||||||
|
content.Clear();
|
||||||
|
|
||||||
Scheduler.AddOnce(loadBlueprintContainer);
|
Scheduler.AddOnce(loadBlueprintContainer);
|
||||||
Scheduler.AddOnce(populateSettings);
|
Scheduler.AddOnce(populateSettings);
|
||||||
@ -323,17 +329,18 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
foreach (var toolbox in componentsSidebar.OfType<SkinComponentToolbox>())
|
foreach (var toolbox in componentsSidebar.OfType<SkinComponentToolbox>())
|
||||||
toolbox.Expire();
|
toolbox.Expire();
|
||||||
|
|
||||||
if (target.NewValue == null)
|
componentsSidebar.Clear();
|
||||||
return;
|
SelectedComponents.Clear();
|
||||||
|
|
||||||
Debug.Assert(content != null);
|
Debug.Assert(content != null);
|
||||||
|
|
||||||
SelectedComponents.Clear();
|
|
||||||
|
|
||||||
var skinComponentsContainer = getTarget(target.NewValue);
|
var skinComponentsContainer = getTarget(target.NewValue);
|
||||||
|
|
||||||
if (skinComponentsContainer == null)
|
if (target.NewValue == null || skinComponentsContainer == null)
|
||||||
|
{
|
||||||
|
content.Child = new NonSkinnableScreenPlaceholder();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
changeHandler = new SkinEditorChangeHandler(skinComponentsContainer);
|
changeHandler = new SkinEditorChangeHandler(skinComponentsContainer);
|
||||||
changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
|
changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
|
||||||
@ -668,6 +675,16 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public partial class RevertConfirmDialog : DangerousActionDialog
|
||||||
|
{
|
||||||
|
public RevertConfirmDialog(Action revert)
|
||||||
|
{
|
||||||
|
HeaderText = CommonStrings.RevertToDefault;
|
||||||
|
BodyText = SkinEditorStrings.RevertToDefaultDescription;
|
||||||
|
DangerousAction = revert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Delegation of IEditorChangeHandler
|
#region Delegation of IEditorChangeHandler
|
||||||
|
|
||||||
public event Action? OnStateChange
|
public event Action? OnStateChange
|
||||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -33,7 +32,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public override string SettingDescription => base.SettingDescription.Replace(MinimumAccuracy.ToString(), MinimumAccuracy.Value.ToString("##%", NumberFormatInfo.InvariantInfo));
|
public override string SettingDescription => base.SettingDescription.Replace(MinimumAccuracy.ToString(), MinimumAccuracy.Value.ToString("##%", NumberFormatInfo.InvariantInfo));
|
||||||
|
|
||||||
[SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsSlider<double, PercentSlider>))]
|
[SettingSource("Minimum accuracy", "Trigger a failure if your accuracy goes below this value.", SettingControlType = typeof(SettingsPercentageSlider<double>))]
|
||||||
public BindableNumber<double> MinimumAccuracy { get; } = new BindableDouble
|
public BindableNumber<double> MinimumAccuracy { get; } = new BindableDouble
|
||||||
{
|
{
|
||||||
MinValue = 0.60,
|
MinValue = 0.60,
|
||||||
@ -69,12 +68,4 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
return scoreProcessor.ComputeAccuracy(score);
|
return scoreProcessor.ComputeAccuracy(score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class PercentSlider : RoundedSliderBar<double>
|
|
||||||
{
|
|
||||||
public PercentSlider()
|
|
||||||
{
|
|
||||||
DisplayAsPercentage = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
for (int i = 0; i < timingPoints.Count; i++)
|
for (int i = 0; i < timingPoints.Count; i++)
|
||||||
{
|
{
|
||||||
TimingControlPoint currentTimingPoint = timingPoints[i];
|
TimingControlPoint currentTimingPoint = timingPoints[i];
|
||||||
EffectControlPoint currentEffectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTimingPoint.Time);
|
|
||||||
int currentBeat = 0;
|
int currentBeat = 0;
|
||||||
|
|
||||||
// Don't generate barlines before the hit object or t=0 (whichever is earliest). Some beatmaps use very unrealistic values here (although none are ranked).
|
// Don't generate barlines before the hit object or t=0 (whichever is earliest). Some beatmaps use very unrealistic values here (although none are ranked).
|
||||||
@ -66,7 +65,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
startTime = currentTimingPoint.Time + barCount * barLength;
|
startTime = currentTimingPoint.Time + barCount * barLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentEffectPoint.OmitFirstBarLine)
|
if (currentTimingPoint.OmitFirstBarLine)
|
||||||
{
|
{
|
||||||
startTime += barLength;
|
startTime += barLength;
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,12 @@ using osu.Game.Overlays.Dialog;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Edit
|
namespace osu.Game.Screens.Edit
|
||||||
{
|
{
|
||||||
public partial class DeleteDifficultyConfirmationDialog : DeleteConfirmationDialog
|
public partial class DeleteDifficultyConfirmationDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction)
|
public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction)
|
||||||
{
|
{
|
||||||
BodyText = $"\"{beatmapInfo.DifficultyName}\" difficulty";
|
BodyText = $"\"{beatmapInfo.DifficultyName}\" difficulty";
|
||||||
DeleteAction = deleteAction;
|
DangerousAction = deleteAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private EditorClock clock { get; set; } = null!;
|
private EditorClock clock { get; set; } = null!;
|
||||||
|
|
||||||
public const float TIMING_COLUMN_WIDTH = 230;
|
public const float TIMING_COLUMN_WIDTH = 300;
|
||||||
|
|
||||||
public IEnumerable<ControlPointGroup> ControlGroups
|
public IEnumerable<ControlPointGroup> ControlGroups
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
internal partial class EffectSection : Section<EffectControlPoint>
|
internal partial class EffectSection : Section<EffectControlPoint>
|
||||||
{
|
{
|
||||||
private LabelledSwitchButton kiai = null!;
|
private LabelledSwitchButton kiai = null!;
|
||||||
private LabelledSwitchButton omitBarLine = null!;
|
|
||||||
|
|
||||||
private SliderWithTextBoxInput<double> scrollSpeedSlider = null!;
|
private SliderWithTextBoxInput<double> scrollSpeedSlider = null!;
|
||||||
|
|
||||||
@ -24,7 +23,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
Flow.AddRange(new Drawable[]
|
Flow.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
kiai = new LabelledSwitchButton { Label = "Kiai Time" },
|
kiai = new LabelledSwitchButton { Label = "Kiai Time" },
|
||||||
omitBarLine = new LabelledSwitchButton { Label = "Skip Bar Line" },
|
|
||||||
scrollSpeedSlider = new SliderWithTextBoxInput<double>("Scroll Speed")
|
scrollSpeedSlider = new SliderWithTextBoxInput<double>("Scroll Speed")
|
||||||
{
|
{
|
||||||
Current = new EffectControlPoint().ScrollSpeedBindable,
|
Current = new EffectControlPoint().ScrollSpeedBindable,
|
||||||
@ -38,7 +36,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
kiai.Current.BindValueChanged(_ => saveChanges());
|
kiai.Current.BindValueChanged(_ => saveChanges());
|
||||||
omitBarLine.Current.BindValueChanged(_ => saveChanges());
|
|
||||||
scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges());
|
scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges());
|
||||||
|
|
||||||
var drawableRuleset = Beatmap.BeatmapInfo.Ruleset.CreateInstance().CreateDrawableRulesetWith(Beatmap.PlayableBeatmap);
|
var drawableRuleset = Beatmap.BeatmapInfo.Ruleset.CreateInstance().CreateDrawableRulesetWith(Beatmap.PlayableBeatmap);
|
||||||
@ -60,7 +57,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
isRebinding = true;
|
isRebinding = true;
|
||||||
|
|
||||||
kiai.Current = point.NewValue.KiaiModeBindable;
|
kiai.Current = point.NewValue.KiaiModeBindable;
|
||||||
omitBarLine.Current = point.NewValue.OmitFirstBarLineBindable;
|
|
||||||
scrollSpeedSlider.Current = point.NewValue.ScrollSpeedBindable;
|
scrollSpeedSlider.Current = point.NewValue.ScrollSpeedBindable;
|
||||||
|
|
||||||
isRebinding = false;
|
isRebinding = false;
|
||||||
@ -74,7 +70,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
return new EffectControlPoint
|
return new EffectControlPoint
|
||||||
{
|
{
|
||||||
KiaiMode = reference.KiaiMode,
|
KiaiMode = reference.KiaiMode,
|
||||||
OmitFirstBarLine = reference.OmitFirstBarLine,
|
|
||||||
ScrollSpeed = reference.ScrollSpeed,
|
ScrollSpeed = reference.ScrollSpeed,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,15 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
public partial class EffectRowAttribute : RowAttribute
|
public partial class EffectRowAttribute : RowAttribute
|
||||||
{
|
{
|
||||||
private readonly Bindable<bool> kiaiMode;
|
private readonly Bindable<bool> kiaiMode;
|
||||||
private readonly Bindable<bool> omitBarLine;
|
|
||||||
private readonly BindableNumber<double> scrollSpeed;
|
private readonly BindableNumber<double> scrollSpeed;
|
||||||
|
|
||||||
private AttributeText kiaiModeBubble = null!;
|
private AttributeText kiaiModeBubble = null!;
|
||||||
private AttributeText omitBarLineBubble = null!;
|
|
||||||
private AttributeText text = null!;
|
private AttributeText text = null!;
|
||||||
|
|
||||||
public EffectRowAttribute(EffectControlPoint effect)
|
public EffectRowAttribute(EffectControlPoint effect)
|
||||||
: base(effect, "effect")
|
: base(effect, "effect")
|
||||||
{
|
{
|
||||||
kiaiMode = effect.KiaiModeBindable.GetBoundCopy();
|
kiaiMode = effect.KiaiModeBindable.GetBoundCopy();
|
||||||
omitBarLine = effect.OmitFirstBarLineBindable.GetBoundCopy();
|
|
||||||
scrollSpeed = effect.ScrollSpeedBindable.GetBoundCopy();
|
scrollSpeed = effect.ScrollSpeedBindable.GetBoundCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,11 +34,9 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
},
|
},
|
||||||
text = new AttributeText(Point) { Width = 45 },
|
text = new AttributeText(Point) { Width = 45 },
|
||||||
kiaiModeBubble = new AttributeText(Point) { Text = "kiai" },
|
kiaiModeBubble = new AttributeText(Point) { Text = "kiai" },
|
||||||
omitBarLineBubble = new AttributeText(Point) { Text = "no barline" },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
kiaiMode.BindValueChanged(enabled => kiaiModeBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
kiaiMode.BindValueChanged(enabled => kiaiModeBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
||||||
omitBarLine.BindValueChanged(enabled => omitBarLineBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
|
||||||
scrollSpeed.BindValueChanged(_ => updateText(), true);
|
scrollSpeed.BindValueChanged(_ => updateText(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -14,24 +15,32 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
public partial class TimingRowAttribute : RowAttribute
|
public partial class TimingRowAttribute : RowAttribute
|
||||||
{
|
{
|
||||||
private readonly BindableNumber<double> beatLength;
|
private readonly BindableNumber<double> beatLength;
|
||||||
|
private readonly Bindable<bool> omitBarLine;
|
||||||
private readonly Bindable<TimeSignature> timeSignature;
|
private readonly Bindable<TimeSignature> timeSignature;
|
||||||
|
private AttributeText omitBarLineBubble = null!;
|
||||||
private OsuSpriteText text = null!;
|
private OsuSpriteText text = null!;
|
||||||
|
|
||||||
public TimingRowAttribute(TimingControlPoint timing)
|
public TimingRowAttribute(TimingControlPoint timing)
|
||||||
: base(timing, "timing")
|
: base(timing, "timing")
|
||||||
{
|
{
|
||||||
timeSignature = timing.TimeSignatureBindable.GetBoundCopy();
|
timeSignature = timing.TimeSignatureBindable.GetBoundCopy();
|
||||||
|
omitBarLine = timing.OmitFirstBarLineBindable.GetBoundCopy();
|
||||||
beatLength = timing.BeatLengthBindable.GetBoundCopy();
|
beatLength = timing.BeatLengthBindable.GetBoundCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
Content.Add(text = new AttributeText(Point));
|
Content.AddRange(new[]
|
||||||
|
{
|
||||||
|
text = new AttributeText(Point),
|
||||||
|
omitBarLineBubble = new AttributeText(Point) { Text = "no barline" },
|
||||||
|
});
|
||||||
|
|
||||||
Background.Colour = colourProvider.Background4;
|
Background.Colour = colourProvider.Background4;
|
||||||
|
|
||||||
timeSignature.BindValueChanged(_ => updateText());
|
timeSignature.BindValueChanged(_ => updateText());
|
||||||
|
omitBarLine.BindValueChanged(enabled => omitBarLineBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
||||||
beatLength.BindValueChanged(_ => updateText(), true);
|
beatLength.BindValueChanged(_ => updateText(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
internal partial class TimingSection : Section<TimingControlPoint>
|
internal partial class TimingSection : Section<TimingControlPoint>
|
||||||
{
|
{
|
||||||
private LabelledTimeSignature timeSignature = null!;
|
private LabelledTimeSignature timeSignature = null!;
|
||||||
|
private LabelledSwitchButton omitBarLine = null!;
|
||||||
private BPMTextBox bpmTextEntry = null!;
|
private BPMTextBox bpmTextEntry = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -24,7 +25,8 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
timeSignature = new LabelledTimeSignature
|
timeSignature = new LabelledTimeSignature
|
||||||
{
|
{
|
||||||
Label = "Time Signature"
|
Label = "Time Signature"
|
||||||
}
|
},
|
||||||
|
omitBarLine = new LabelledSwitchButton { Label = "Skip Bar Line" },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
bpmTextEntry.Current.BindValueChanged(_ => saveChanges());
|
bpmTextEntry.Current.BindValueChanged(_ => saveChanges());
|
||||||
|
omitBarLine.Current.BindValueChanged(_ => saveChanges());
|
||||||
timeSignature.Current.BindValueChanged(_ => saveChanges());
|
timeSignature.Current.BindValueChanged(_ => saveChanges());
|
||||||
|
|
||||||
void saveChanges()
|
void saveChanges()
|
||||||
@ -51,6 +54,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
|
|
||||||
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
||||||
timeSignature.Current = point.NewValue.TimeSignatureBindable;
|
timeSignature.Current = point.NewValue.TimeSignatureBindable;
|
||||||
|
omitBarLine.Current = point.NewValue.OmitFirstBarLineBindable;
|
||||||
|
|
||||||
isRebinding = false;
|
isRebinding = false;
|
||||||
}
|
}
|
||||||
@ -63,7 +67,8 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
return new TimingControlPoint
|
return new TimingControlPoint
|
||||||
{
|
{
|
||||||
BeatLength = reference.BeatLength,
|
BeatLength = reference.BeatLength,
|
||||||
TimeSignature = reference.TimeSignature
|
TimeSignature = reference.TimeSignature,
|
||||||
|
OmitFirstBarLine = reference.OmitFirstBarLine,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
osu.Game/Screens/Play/HUD/PlayerAvatar.cs
Normal file
58
osu.Game/Screens/Play/HUD/PlayerAvatar.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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.Game.Configuration;
|
||||||
|
using osu.Game.Localisation.SkinComponents;
|
||||||
|
using osu.Game.Overlays.Settings;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osu.Game.Users.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.HUD
|
||||||
|
{
|
||||||
|
public partial class PlayerAvatar : CompositeDrawable, ISerialisableDrawable
|
||||||
|
{
|
||||||
|
[SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.CornerRadius), nameof(SkinnableComponentStrings.CornerRadiusDescription),
|
||||||
|
SettingControlType = typeof(SettingsPercentageSlider<float>))]
|
||||||
|
public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0.25f)
|
||||||
|
{
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 0.5f,
|
||||||
|
Precision = 0.01f
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly UpdateableAvatar avatar;
|
||||||
|
|
||||||
|
private const float default_size = 80f;
|
||||||
|
|
||||||
|
public PlayerAvatar()
|
||||||
|
{
|
||||||
|
Size = new Vector2(default_size);
|
||||||
|
|
||||||
|
InternalChild = avatar = new UpdateableAvatar(isInteractive: false)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(GameplayState gameplayState)
|
||||||
|
{
|
||||||
|
avatar.User = gameplayState.Score.ScoreInfo.User;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue * default_size, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
}
|
||||||
|
}
|
36
osu.Game/Screens/Play/HUD/PlayerFlag.cs
Normal file
36
osu.Game/Screens/Play/HUD/PlayerFlag.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osu.Game.Users.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.HUD
|
||||||
|
{
|
||||||
|
public partial class PlayerFlag : CompositeDrawable, ISerialisableDrawable
|
||||||
|
{
|
||||||
|
private readonly UpdateableFlag flag;
|
||||||
|
|
||||||
|
private const float default_size = 40f;
|
||||||
|
|
||||||
|
public PlayerFlag()
|
||||||
|
{
|
||||||
|
Size = new Vector2(default_size, default_size / 1.4f);
|
||||||
|
InternalChild = flag = new UpdateableFlag
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(GameplayState gameplayState)
|
||||||
|
{
|
||||||
|
flag.CountryCode = gameplayState.Score.ScoreInfo.User.CountryCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool UsesFixedAnchor { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ using osu.Game.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Select
|
namespace osu.Game.Screens.Select
|
||||||
{
|
{
|
||||||
public partial class BeatmapClearScoresDialog : DeleteConfirmationDialog
|
public partial class BeatmapClearScoresDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private ScoreManager scoreManager { get; set; } = null!;
|
private ScoreManager scoreManager { get; set; } = null!;
|
||||||
@ -18,7 +18,7 @@ namespace osu.Game.Screens.Select
|
|||||||
public BeatmapClearScoresDialog(BeatmapInfo beatmapInfo, Action onCompletion)
|
public BeatmapClearScoresDialog(BeatmapInfo beatmapInfo, Action onCompletion)
|
||||||
{
|
{
|
||||||
BodyText = $"All local scores on {beatmapInfo.GetDisplayTitle()}";
|
BodyText = $"All local scores on {beatmapInfo.GetDisplayTitle()}";
|
||||||
DeleteAction = () =>
|
DangerousAction = () =>
|
||||||
{
|
{
|
||||||
Task.Run(() => scoreManager.Delete(beatmapInfo))
|
Task.Run(() => scoreManager.Delete(beatmapInfo))
|
||||||
.ContinueWith(_ => onCompletion);
|
.ContinueWith(_ => onCompletion);
|
||||||
|
@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Select
|
namespace osu.Game.Screens.Select
|
||||||
{
|
{
|
||||||
public partial class BeatmapDeleteDialog : DeleteConfirmationDialog
|
public partial class BeatmapDeleteDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
private readonly BeatmapSetInfo beatmapSet;
|
private readonly BeatmapSetInfo beatmapSet;
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(BeatmapManager beatmapManager)
|
private void load(BeatmapManager beatmapManager)
|
||||||
{
|
{
|
||||||
DeleteAction = () => beatmapManager.Delete(beatmapSet);
|
DangerousAction = () => beatmapManager.Delete(beatmapSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,11 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
{
|
{
|
||||||
base.Filter(criteria);
|
base.Filter(criteria);
|
||||||
|
|
||||||
|
Filtered.Value = !checkMatch(criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkMatch(FilterCriteria criteria)
|
||||||
|
{
|
||||||
bool match =
|
bool match =
|
||||||
criteria.Ruleset == null ||
|
criteria.Ruleset == null ||
|
||||||
BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName ||
|
BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName ||
|
||||||
@ -34,8 +39,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
|
if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
|
||||||
{
|
{
|
||||||
// only check ruleset equality or convertability for selected beatmap
|
// only check ruleset equality or convertability for selected beatmap
|
||||||
Filtered.Value = !match;
|
return match;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
||||||
@ -49,18 +53,38 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor);
|
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor);
|
||||||
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status);
|
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status);
|
||||||
|
|
||||||
|
if (!match) return false;
|
||||||
|
|
||||||
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username);
|
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username);
|
||||||
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) ||
|
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) ||
|
||||||
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);
|
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);
|
||||||
|
|
||||||
match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
||||||
|
|
||||||
if (match && criteria.SearchTerms.Length > 0)
|
if (!match) return false;
|
||||||
|
|
||||||
|
if (criteria.SearchTerms.Length > 0)
|
||||||
{
|
{
|
||||||
string[] terms = BeatmapInfo.GetSearchableTerms();
|
var terms = BeatmapInfo.GetSearchableTerms();
|
||||||
|
|
||||||
foreach (string criteriaTerm in criteria.SearchTerms)
|
foreach (string criteriaTerm in criteria.SearchTerms)
|
||||||
match &= terms.Any(term => term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase));
|
{
|
||||||
|
bool any = false;
|
||||||
|
|
||||||
|
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
|
||||||
|
foreach (string term in terms)
|
||||||
|
{
|
||||||
|
if (!term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase)) continue;
|
||||||
|
|
||||||
|
any = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any) continue;
|
||||||
|
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs.
|
// if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs.
|
||||||
// this should be done after text matching so we can prioritise matching numbers in metadata.
|
// this should be done after text matching so we can prioritise matching numbers in metadata.
|
||||||
@ -71,13 +95,14 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match)
|
if (!match) return false;
|
||||||
|
|
||||||
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
||||||
|
|
||||||
if (match && criteria.RulesetCriteria != null)
|
if (match && criteria.RulesetCriteria != null)
|
||||||
match &= criteria.RulesetCriteria.Matches(BeatmapInfo);
|
match &= criteria.RulesetCriteria.Matches(BeatmapInfo);
|
||||||
|
|
||||||
Filtered.Value = !match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int CompareTo(FilterCriteria criteria, CarouselItem other)
|
public override int CompareTo(FilterCriteria criteria, CarouselItem other)
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
if (!(other is CarouselBeatmapSet otherSet))
|
if (!(other is CarouselBeatmapSet otherSet))
|
||||||
return base.CompareTo(criteria, other);
|
return base.CompareTo(criteria, other);
|
||||||
|
|
||||||
int comparison = 0;
|
int comparison;
|
||||||
|
|
||||||
switch (criteria.Sort)
|
switch (criteria.Sort)
|
||||||
{
|
{
|
||||||
@ -87,11 +87,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SortMode.DateRanked:
|
case SortMode.DateRanked:
|
||||||
// Beatmaps which have no ranked date should already be filtered away in this mode.
|
comparison = Nullable.Compare(otherSet.BeatmapSet.DateRanked, BeatmapSet.DateRanked);
|
||||||
if (BeatmapSet.DateRanked == null || otherSet.BeatmapSet.DateRanked == null)
|
|
||||||
break;
|
|
||||||
|
|
||||||
comparison = otherSet.BeatmapSet.DateRanked.Value.CompareTo(BeatmapSet.DateRanked.Value);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SortMode.LastPlayed:
|
case SortMode.LastPlayed:
|
||||||
@ -111,11 +107,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SortMode.DateSubmitted:
|
case SortMode.DateSubmitted:
|
||||||
// Beatmaps which have no submitted date should already be filtered away in this mode.
|
comparison = Nullable.Compare(otherSet.BeatmapSet.DateSubmitted, BeatmapSet.DateSubmitted);
|
||||||
if (BeatmapSet.DateSubmitted == null || otherSet.BeatmapSet.DateSubmitted == null)
|
|
||||||
break;
|
|
||||||
|
|
||||||
comparison = otherSet.BeatmapSet.DateSubmitted.Value.CompareTo(BeatmapSet.DateSubmitted.Value);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,12 +145,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
{
|
{
|
||||||
base.Filter(criteria);
|
base.Filter(criteria);
|
||||||
|
|
||||||
bool filtered = Items.All(i => i.Filtered.Value);
|
Filtered.Value = Items.All(i => i.Filtered.Value);
|
||||||
|
|
||||||
filtered |= criteria.Sort == SortMode.DateRanked && BeatmapSet.DateRanked == null;
|
|
||||||
filtered |= criteria.Sort == SortMode.DateSubmitted && BeatmapSet.DateSubmitted == null;
|
|
||||||
|
|
||||||
Filtered.Value = filtered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => BeatmapSet.ToString();
|
public override string ToString() => BeatmapSet.ToString();
|
||||||
|
@ -8,14 +8,14 @@ using osu.Game.Localisation;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Select.Carousel
|
namespace osu.Game.Screens.Select.Carousel
|
||||||
{
|
{
|
||||||
public partial class UpdateLocalConfirmationDialog : DeleteConfirmationDialog
|
public partial class UpdateLocalConfirmationDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
public UpdateLocalConfirmationDialog(Action onConfirm)
|
public UpdateLocalConfirmationDialog(Action onConfirm)
|
||||||
{
|
{
|
||||||
HeaderText = PopupDialogStrings.UpdateLocallyModifiedText;
|
HeaderText = PopupDialogStrings.UpdateLocallyModifiedText;
|
||||||
BodyText = PopupDialogStrings.UpdateLocallyModifiedDescription;
|
BodyText = PopupDialogStrings.UpdateLocallyModifiedDescription;
|
||||||
Icon = FontAwesome.Solid.ExclamationTriangle;
|
Icon = FontAwesome.Solid.ExclamationTriangle;
|
||||||
DeleteAction = onConfirm;
|
DangerousAction = onConfirm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ using osu.Game.Beatmaps;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Select
|
namespace osu.Game.Screens.Select
|
||||||
{
|
{
|
||||||
public partial class LocalScoreDeleteDialog : DeleteConfirmationDialog
|
public partial class LocalScoreDeleteDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
private readonly ScoreInfo score;
|
private readonly ScoreInfo score;
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Select
|
|||||||
BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})";
|
BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})";
|
||||||
|
|
||||||
Icon = FontAwesome.Regular.TrashAlt;
|
Icon = FontAwesome.Regular.TrashAlt;
|
||||||
DeleteAction = () => scoreManager.Delete(score);
|
DangerousAction = () => scoreManager.Delete(score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Select
|
namespace osu.Game.Screens.Select
|
||||||
{
|
{
|
||||||
public partial class SkinDeleteDialog : DeleteConfirmationDialog
|
public partial class SkinDeleteDialog : DangerousActionDialog
|
||||||
{
|
{
|
||||||
private readonly Skin skin;
|
private readonly Skin skin;
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(SkinManager manager)
|
private void load(SkinManager manager)
|
||||||
{
|
{
|
||||||
DeleteAction = () =>
|
DangerousAction = () =>
|
||||||
{
|
{
|
||||||
manager.Delete(skin.SkinInfo.Value);
|
manager.Delete(skin.SkinInfo.Value);
|
||||||
manager.CurrentSkinInfo.SetDefault();
|
manager.CurrentSkinInfo.SetDefault();
|
||||||
|
@ -58,7 +58,11 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
using (drawableVideo.BeginAbsoluteSequence(Video.StartTime))
|
using (drawableVideo.BeginAbsoluteSequence(Video.StartTime))
|
||||||
{
|
{
|
||||||
Schedule(() => drawableVideo.PlaybackPosition = Time.Current - Video.StartTime);
|
Schedule(() => drawableVideo.PlaybackPosition = Time.Current - Video.StartTime);
|
||||||
|
|
||||||
drawableVideo.FadeIn(500);
|
drawableVideo.FadeIn(500);
|
||||||
|
|
||||||
|
using (drawableVideo.BeginDelayedSequence(drawableVideo.Duration - 500))
|
||||||
|
drawableVideo.FadeOut(500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -30,14 +28,14 @@ namespace osu.Game.Users.Drawables
|
|||||||
/// Perform an action in addition to showing the country ranking.
|
/// Perform an action in addition to showing the country ranking.
|
||||||
/// This should be used to perform auxiliary tasks and not as a primary action for clicking a flag (to maintain a consistent UX).
|
/// This should be used to perform auxiliary tasks and not as a primary action for clicking a flag (to maintain a consistent UX).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action Action;
|
public Action? Action;
|
||||||
|
|
||||||
public UpdateableFlag(CountryCode countryCode = CountryCode.Unknown)
|
public UpdateableFlag(CountryCode countryCode = CountryCode.Unknown)
|
||||||
{
|
{
|
||||||
CountryCode = countryCode;
|
CountryCode = countryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateDrawable(CountryCode countryCode)
|
protected override Drawable? CreateDrawable(CountryCode countryCode)
|
||||||
{
|
{
|
||||||
if (countryCode == CountryCode.Unknown && !ShowPlaceholderOnUnknown)
|
if (countryCode == CountryCode.Unknown && !ShowPlaceholderOnUnknown)
|
||||||
return null;
|
return null;
|
||||||
@ -56,8 +54,8 @@ namespace osu.Game.Users.Drawables
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private RankingsOverlay rankingsOverlay { get; set; }
|
private RankingsOverlay? rankingsOverlay { get; set; }
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user