mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 17:35:10 +08:00
Merge branch 'refactor-osd' into music-controller-hotkeys
This commit is contained in:
commit
8c630b4f4c
@ -1,5 +1,5 @@
|
||||
<p align="center">
|
||||
<img width="256" height="256" src="assets/lazer.png">
|
||||
<img width="500px" src="assets/lazer.png">
|
||||
</p>
|
||||
|
||||
# osu!
|
||||
@ -100,7 +100,7 @@ Before starting, please make sure you are familiar with the [development and tes
|
||||
|
||||
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as pain-free as possible.
|
||||
|
||||
For those interested, we love to reward quality contributions via bounties, paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
|
||||
For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via paypal or osu! supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
|
||||
|
||||
## Licence
|
||||
|
||||
|
BIN
assets/lazer.png
BIN
assets/lazer.png
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 187 KiB |
@ -63,6 +63,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.704.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.726.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 38 KiB |
@ -29,29 +29,36 @@ namespace osu.Desktop
|
||||
|
||||
if (!host.IsPrimaryInstance)
|
||||
{
|
||||
var importer = new ArchiveImportIPCChannel(host);
|
||||
// Restore the cwd so relative paths given at the command line work correctly
|
||||
Directory.SetCurrentDirectory(cwd);
|
||||
|
||||
foreach (var file in args)
|
||||
if (args.Length > 0 && args[0].Contains('.')) // easy way to check for a file import in args
|
||||
{
|
||||
Console.WriteLine(@"Importing {0}", file);
|
||||
if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
|
||||
throw new TimeoutException(@"IPC took too long to send");
|
||||
var importer = new ArchiveImportIPCChannel(host);
|
||||
// Restore the cwd so relative paths given at the command line work correctly
|
||||
Directory.SetCurrentDirectory(cwd);
|
||||
|
||||
foreach (var file in args)
|
||||
{
|
||||
Console.WriteLine(@"Importing {0}", file);
|
||||
if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
|
||||
throw new TimeoutException(@"IPC took too long to send");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we want to allow multiple instances to be started when in debug.
|
||||
if (!DebugUtils.IsDebugBuild)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (args.FirstOrDefault() ?? string.Empty)
|
||||
{
|
||||
default:
|
||||
host.Run(new OsuGameDesktop(args));
|
||||
break;
|
||||
|
||||
case "--tournament":
|
||||
host.Run(new TournamentGame());
|
||||
break;
|
||||
}
|
||||
switch (args.FirstOrDefault() ?? string.Empty)
|
||||
{
|
||||
default:
|
||||
host.Run(new OsuGameDesktop(args));
|
||||
break;
|
||||
|
||||
case "--tournament":
|
||||
host.Run(new TournamentGame());
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
BIN
osu.Desktop/lazer.ico
Normal file → Executable file
BIN
osu.Desktop/lazer.ico
Normal file → Executable file
Binary file not shown.
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 85 KiB |
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -3,12 +3,10 @@
|
||||
|
||||
using System;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@ -60,16 +58,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
|
||||
}
|
||||
protected override bool UseTransformStateManagement => false;
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
// TODO: update to use new state management.
|
||||
using (BeginAbsoluteSequence(HitObject.StartTime - HitObject.TimePreempt))
|
||||
this.FadeIn(200);
|
||||
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
@ -27,16 +26,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
private void load()
|
||||
{
|
||||
AddInternal(pulp = new Pulp { Size = Size });
|
||||
}
|
||||
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
{
|
||||
base.AccentColour = value;
|
||||
pulp.AccentColour = AccentColour;
|
||||
}
|
||||
AccentColour.BindValueChanged(colour => { pulp.AccentColour = colour.NewValue; }, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
private void load()
|
||||
{
|
||||
// todo: this should come from the skin.
|
||||
AccentColour = colourForRepresentation(HitObject.VisualRepresentation);
|
||||
AccentColour.Value = colourForRepresentation(HitObject.VisualRepresentation);
|
||||
|
||||
AddRangeInternal(new[]
|
||||
{
|
||||
@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
Hollow = !HitObject.HyperDash,
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 4 * radius_adjust,
|
||||
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
|
||||
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Value.Darken(1).Opacity(0.6f)
|
||||
},
|
||||
Size = new Vector2(Height),
|
||||
Anchor = Anchor.Centre,
|
||||
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
new Box
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Colour = AccentColour,
|
||||
Colour = AccentColour.Value,
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
@ -115,32 +115,32 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.34f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(0, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(90, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(180, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_4),
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Position = positionAt(270, distance_from_centre_4),
|
||||
},
|
||||
}
|
||||
@ -154,32 +154,32 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.3f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(45, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(135, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4),
|
||||
Position = positionAt(225, distance_from_centre_4),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_4),
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Position = positionAt(315, distance_from_centre_4),
|
||||
},
|
||||
}
|
||||
@ -193,26 +193,26 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.33f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(60, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(180, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_3),
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Position = positionAt(300, distance_from_centre_3),
|
||||
},
|
||||
}
|
||||
@ -226,26 +226,26 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.25f,
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(0, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_3),
|
||||
Position = positionAt(120, distance_from_centre_3),
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
Size = new Vector2(large_pulp_3),
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Position = positionAt(240, distance_from_centre_3),
|
||||
},
|
||||
}
|
||||
@ -259,13 +259,13 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
{
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(small_pulp),
|
||||
Y = -0.3f
|
||||
},
|
||||
new Pulp
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
AccentColour = AccentColour.Value,
|
||||
Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
|
||||
Y = 0.05f,
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Child = drawableObject = new DrawableHoldNote(holdNote)
|
||||
{
|
||||
Height = 300,
|
||||
AccentColour = OsuColour.Gray(0.3f)
|
||||
AccentColour = { Value = OsuColour.Gray(0.3f) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new NoteContainer(direction, $"note {identifier}, scrolling {direction.ToString().ToLowerInvariant()}")
|
||||
{
|
||||
Child = hitObject = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
|
||||
Child = hitObject = new DrawableNote(note) { AccentColour = { Value = Color4.OrangeRed } }
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Child = hitObject = new DrawableHoldNote(note)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
AccentColour = Color4.OrangeRed,
|
||||
AccentColour = { Value = Color4.OrangeRed },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -6,7 +6,6 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -36,11 +35,10 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
private bool hasBroken;
|
||||
|
||||
private readonly Container<DrawableHoldNoteTick> tickContainer;
|
||||
|
||||
public DrawableHoldNote(HoldNote hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
Container<DrawableHoldNoteTick> tickContainer;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
@ -74,6 +72,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
AddNested(Head);
|
||||
AddNested(Tail);
|
||||
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
bodyPiece.AccentColour = colour.NewValue;
|
||||
Head.AccentColour.Value = colour.NewValue;
|
||||
Tail.AccentColour.Value = colour.NewValue;
|
||||
tickContainer.ForEach(t => t.AccentColour.Value = colour.NewValue);
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
||||
@ -83,20 +89,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
bodyPiece.Anchor = bodyPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft;
|
||||
}
|
||||
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
{
|
||||
base.AccentColour = value;
|
||||
|
||||
bodyPiece.AccentColour = value;
|
||||
Head.AccentColour = value;
|
||||
Tail.AccentColour = value;
|
||||
tickContainer.ForEach(t => t.AccentColour = value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (Tail.AllJudged)
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -23,11 +22,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
/// </summary>
|
||||
public Func<double?> HoldStartTime;
|
||||
|
||||
private readonly Container glowContainer;
|
||||
|
||||
public DrawableHoldNoteTick(HoldNoteTick hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
Container glowContainer;
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
@ -53,23 +52,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
base.AccentColour = value;
|
||||
|
||||
glowContainer.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Radius = 2f,
|
||||
Roundness = 15f,
|
||||
Colour = value.Opacity(0.3f)
|
||||
Colour = colour.NewValue.Opacity(0.3f)
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
|
@ -58,8 +58,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
HitObject = hitObject;
|
||||
}
|
||||
|
||||
protected override bool UseTransformStateManagement => false;
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
// TODO: update to use new state management.
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Miss:
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osuTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Input.Bindings;
|
||||
@ -30,6 +29,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
Masking = true;
|
||||
|
||||
AddInternal(headPiece = new NotePiece());
|
||||
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
headPiece.AccentColour = colour.NewValue;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = colour.NewValue.Lighten(1f).Opacity(0.6f),
|
||||
Radius = 10,
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
||||
@ -39,23 +50,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
headPiece.Anchor = headPiece.Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
|
||||
}
|
||||
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
{
|
||||
base.AccentColour = value;
|
||||
headPiece.AccentColour = AccentColour;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = AccentColour.Lighten(1f).Opacity(0.6f),
|
||||
Radius = 10,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!userTriggered)
|
||||
|
@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
/// <param name="hitObject">The DrawableHitObject to add.</param>
|
||||
public override void Add(DrawableHitObject hitObject)
|
||||
{
|
||||
hitObject.AccentColour = AccentColour;
|
||||
hitObject.AccentColour.Value = AccentColour;
|
||||
hitObject.OnNewResult += OnNewResult;
|
||||
|
||||
HitObjectContainer.Add(hitObject);
|
||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour, Color4.White, 0, 1),
|
||||
Colour = Interpolation.ValueAt(0.1f, judgedObject.AccentColour.Value, Color4.White, 0, 1),
|
||||
Radius = 100,
|
||||
},
|
||||
Child = new Box
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||
|
||||
[TestCase(6.931145117263422, "diffcalc-test")]
|
||||
[TestCase(1.0736587013228804d, "zero-length-sliders")]
|
||||
public void Test(double expected, string name)
|
||||
=> base.Test(expected, name);
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
|
||||
this.hitCircle = hitCircle;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
Scale = new Vector2(hitCircle.Scale);
|
||||
CornerRadius = Size.X / 2;
|
||||
|
||||
|
@ -24,7 +24,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
InternalChild = body = new ManualSliderBody
|
||||
{
|
||||
AccentColour = Color4.Transparent,
|
||||
PathRadius = slider.Scale * 64
|
||||
};
|
||||
}
|
||||
|
||||
@ -34,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
body.BorderColour = colours.Yellow;
|
||||
|
||||
PositionBindable.BindValueChanged(_ => updatePosition(), true);
|
||||
ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * 64, true);
|
||||
ScaleBindable.BindValueChanged(scale => body.PathRadius = scale.NewValue * OsuHitObject.OBJECT_RADIUS, true);
|
||||
}
|
||||
|
||||
private void updatePosition() => Position = slider.StackedPosition;
|
||||
|
@ -13,13 +13,11 @@ using static osu.Game.Input.Handlers.ReplayInputHandler;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Mods
|
||||
{
|
||||
public class OsuModRelax : ModRelax, IApplicableFailOverride, IUpdatableByPlayfield, IApplicableToDrawableRuleset<OsuHitObject>
|
||||
public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset<OsuHitObject>
|
||||
{
|
||||
public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things.";
|
||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
|
||||
|
||||
public bool AllowFail => false;
|
||||
|
||||
public void Update(Playfield playfield)
|
||||
{
|
||||
bool requiresHold = false;
|
||||
|
@ -11,6 +11,8 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public override string Acronym => "TD";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override ModType Type => ModType.System;
|
||||
|
||||
public override bool Ranked => true;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||
using osuTK;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@ -98,19 +97,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
positionBindable.BindTo(HitObject.PositionBindable);
|
||||
stackHeightBindable.BindTo(HitObject.StackHeightBindable);
|
||||
scaleBindable.BindTo(HitObject.ScaleBindable);
|
||||
}
|
||||
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
base.AccentColour = value;
|
||||
explode.Colour = AccentColour;
|
||||
glow.Colour = AccentColour;
|
||||
circle.Colour = AccentColour;
|
||||
ApproachCircle.Colour = AccentColour;
|
||||
}
|
||||
explode.Colour = colour.NewValue;
|
||||
glow.Colour = colour.NewValue;
|
||||
circle.Colour = colour.NewValue;
|
||||
ApproachCircle.Colour = colour.NewValue;
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
@ -134,16 +128,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ApplyResult(r => r.Type = result);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
base.UpdatePreemptState();
|
||||
base.UpdateInitialTransforms();
|
||||
|
||||
ApproachCircle.FadeIn(Math.Min(HitObject.TimeFadeIn * 2, HitObject.TimePreempt));
|
||||
ApproachCircle.ScaleTo(1.1f, HitObject.TimePreempt);
|
||||
ApproachCircle.Expire(true);
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
glow.FadeOut(400);
|
||||
|
||||
|
@ -1,15 +1,10 @@
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
@ -29,6 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ShakeDuration = 30,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
});
|
||||
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
@ -38,47 +34,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren);
|
||||
protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable);
|
||||
|
||||
protected sealed override void UpdateState(ArmedState state)
|
||||
{
|
||||
double transformTime = HitObject.StartTime - HitObject.TimePreempt;
|
||||
protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
|
||||
|
||||
base.ApplyTransformsAt(transformTime, true);
|
||||
base.ClearTransformsAfter(transformTime, true);
|
||||
|
||||
using (BeginAbsoluteSequence(transformTime, true))
|
||||
{
|
||||
UpdatePreemptState();
|
||||
|
||||
var judgementOffset = Math.Min(HitObject.HitWindows.HalfWindowFor(HitResult.Miss), Result?.TimeOffset ?? 0);
|
||||
|
||||
using (BeginDelayedSequence(HitObject.TimePreempt + judgementOffset, true))
|
||||
UpdateCurrentState(state);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
|
||||
}
|
||||
|
||||
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
|
||||
|
||||
protected virtual void UpdateCurrentState(ArmedState state)
|
||||
{
|
||||
}
|
||||
|
||||
// Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply
|
||||
// transforms in the same way and don't rely on them not being cleared
|
||||
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ApplyTransformsAt(double time, bool propagateChildren = false)
|
||||
{
|
||||
}
|
||||
protected override void UpdateInitialTransforms() => this.FadeIn(HitObject.TimeFadeIn);
|
||||
|
||||
private OsuInputManager osuActionInputManager;
|
||||
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? HitResult.Great : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
animDuration = Math.Min(150, repeatPoint.SpanDuration / 2);
|
||||
|
||||
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
);
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
Body = new SnakingSliderBody(s)
|
||||
{
|
||||
PathRadius = s.Scale * 64,
|
||||
PathRadius = s.Scale * OsuHitObject.OBJECT_RADIUS,
|
||||
},
|
||||
ticks = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
|
||||
repeatPoints = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
|
||||
@ -114,20 +114,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
pathBindable.BindTo(slider.PathBindable);
|
||||
|
||||
pathBindable.BindValueChanged(_ => Body.Refresh());
|
||||
}
|
||||
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get => base.AccentColour;
|
||||
set
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
base.AccentColour = value;
|
||||
Body.AccentColour = AccentColour;
|
||||
Ball.AccentColour = AccentColour;
|
||||
Body.AccentColour = colour.NewValue;
|
||||
Ball.AccentColour = colour.NewValue;
|
||||
|
||||
foreach (var drawableHitObject in NestedHitObjects)
|
||||
drawableHitObject.AccentColour = AccentColour;
|
||||
}
|
||||
drawableHitObject.AccentColour.Value = colour.NewValue;
|
||||
}, true);
|
||||
}
|
||||
|
||||
public readonly Bindable<bool> Tracking = new Bindable<bool>();
|
||||
@ -156,14 +151,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnKilled()
|
||||
{
|
||||
base.OnKilled();
|
||||
Body.RecyclePath();
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
Body.BorderSize = skin.GetValue<SkinConfiguration, float?>(s => s.SliderBorderSize) ?? SliderBody.DEFAULT_BORDER_SIZE;
|
||||
Body.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : (Color4?)null) ?? AccentColour;
|
||||
Body.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : (Color4?)null) ?? AccentColour.Value;
|
||||
Body.BorderColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : (Color4?)null) ?? Color4.White;
|
||||
Ball.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? AccentColour;
|
||||
Ball.AccentColour = skin.GetValue<SkinConfiguration, Color4?>(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : (Color4?)null) ?? AccentColour.Value;
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
@ -189,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
Ball.FadeIn();
|
||||
Ball.ScaleTo(HitObject.Scale);
|
||||
|
@ -34,14 +34,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Origin = Anchor.Centre,
|
||||
CornerRadius = Size.X / 2,
|
||||
|
||||
BorderThickness = 2,
|
||||
BorderColour = Color4.White,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Colour = AccentColour.Value,
|
||||
Alpha = 0.3f,
|
||||
}
|
||||
}, restrictSize: false)
|
||||
@ -54,13 +52,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
this.FadeOut().FadeIn(ANIM_DURATION);
|
||||
this.ScaleTo(0.5f).ScaleTo(1f, ANIM_DURATION * 4, Easing.OutElasticHalf);
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
|
@ -196,9 +196,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
symbol.RotateTo(Disc.Rotation / 2, 500, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
protected override void UpdateInitialTransforms()
|
||||
{
|
||||
base.UpdatePreemptState();
|
||||
base.UpdateInitialTransforms();
|
||||
|
||||
circleContainer.ScaleTo(Spinner.Scale * 0.3f);
|
||||
circleContainer.ScaleTo(Spinner.Scale, HitObject.TimePreempt / 1.4f, Easing.OutQuint);
|
||||
@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
.ScaleTo(1, 500, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
protected override void UpdateStateTransforms(ArmedState state)
|
||||
{
|
||||
var sequence = this.Delay(Spinner.Duration).FadeOut(160);
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
public CirclePiece()
|
||||
{
|
||||
Size = new Vector2((float)OsuHitObject.OBJECT_RADIUS * 2);
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
Masking = true;
|
||||
CornerRadius = Size.X / 2;
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public ExplodePiece()
|
||||
{
|
||||
Size = new Vector2(128);
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public FlashPiece()
|
||||
{
|
||||
Size = new Vector2(128);
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public RingPiece()
|
||||
{
|
||||
Size = new Vector2(128);
|
||||
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public class SliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition
|
||||
{
|
||||
private const float width = 128;
|
||||
|
||||
private Color4 accentColour = Color4.Black;
|
||||
|
||||
public Func<OsuAction?> GetInitialHitAction;
|
||||
@ -57,8 +55,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Width = width,
|
||||
Height = width,
|
||||
Width = OsuHitObject.OBJECT_RADIUS * 2,
|
||||
Height = OsuHitObject.OBJECT_RADIUS * 2,
|
||||
Alpha = 0,
|
||||
Child = new SkinnableDrawable("Play/osu/sliderfollowcircle", _ => new CircularContainer
|
||||
{
|
||||
@ -84,8 +82,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
Alpha = 1,
|
||||
Child = new Container
|
||||
{
|
||||
Width = width,
|
||||
Height = width,
|
||||
Width = OsuHitObject.OBJECT_RADIUS * 2,
|
||||
Height = OsuHitObject.OBJECT_RADIUS * 2,
|
||||
// TODO: support skin filename animation (sliderb0, sliderb1...)
|
||||
Child = new SkinnableDrawable("Play/osu/sliderb", _ => new CircularContainer
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Lines;
|
||||
@ -13,7 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
{
|
||||
public const float DEFAULT_BORDER_SIZE = 1;
|
||||
|
||||
private readonly SliderPath path;
|
||||
private SliderPath path;
|
||||
|
||||
protected Path Path => path;
|
||||
|
||||
public float PathRadius
|
||||
@ -74,7 +76,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
protected SliderBody()
|
||||
{
|
||||
InternalChild = path = new SliderPath();
|
||||
RecyclePath();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialises a new <see cref="SliderPath"/>, releasing all resources retained by the old one.
|
||||
/// </summary>
|
||||
public virtual void RecyclePath()
|
||||
{
|
||||
InternalChild = path = new SliderPath
|
||||
{
|
||||
Position = path?.Position ?? Vector2.Zero,
|
||||
PathRadius = path?.PathRadius ?? 10,
|
||||
AccentColour = path?.AccentColour ?? Color4.White,
|
||||
BorderColour = path?.BorderColour ?? Color4.White,
|
||||
BorderSize = path?.BorderSize ?? DEFAULT_BORDER_SIZE,
|
||||
Vertices = path?.Vertices ?? Array.Empty<Vector2>()
|
||||
};
|
||||
}
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osuTK;
|
||||
|
||||
@ -78,9 +79,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
slider.Path.GetPathToProgress(CurrentCurve, 0, 1);
|
||||
SetVertices(CurrentCurve);
|
||||
|
||||
// The body is sized to the full path size to avoid excessive autosize computations
|
||||
// Force the body to be the final path size to avoid excessive autosize computations
|
||||
Path.AutoSizeAxes = Axes.Both;
|
||||
Size = Path.Size;
|
||||
|
||||
updatePathSize();
|
||||
|
||||
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
|
||||
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
|
||||
|
||||
@ -93,6 +97,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
setRange(lastSnakedStart, lastSnakedEnd);
|
||||
}
|
||||
|
||||
public override void RecyclePath()
|
||||
{
|
||||
base.RecyclePath();
|
||||
updatePathSize();
|
||||
}
|
||||
|
||||
private void updatePathSize()
|
||||
{
|
||||
// Force the path to its final size to avoid excessive framebuffer resizes
|
||||
Path.AutoSizeAxes = Axes.None;
|
||||
Path.Size = Size;
|
||||
}
|
||||
|
||||
private void setRange(double p0, double p1)
|
||||
{
|
||||
if (p0 > p1)
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
||||
{
|
||||
public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition
|
||||
{
|
||||
public const double OBJECT_RADIUS = 64;
|
||||
public const float OBJECT_RADIUS = 64;
|
||||
|
||||
public double TimePreempt = 600;
|
||||
public double TimeFadeIn = 400;
|
||||
|
@ -138,6 +138,12 @@ namespace osu.Game.Rulesets.Osu
|
||||
new MultiMod(new ModWindUp<OsuHitObject>(), new ModWindDown<OsuHitObject>()),
|
||||
};
|
||||
|
||||
case ModType.System:
|
||||
return new Mod[]
|
||||
{
|
||||
new OsuModTouchDevice(),
|
||||
};
|
||||
|
||||
default:
|
||||
return new Mod[] { };
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
osu file format v14
|
||||
|
||||
[Difficulty]
|
||||
HPDrainRate:3
|
||||
CircleSize:3
|
||||
OverallDifficulty:3
|
||||
ApproachRate:4.5
|
||||
SliderMultiplier:0.799999999999999
|
||||
SliderTickRate:1
|
||||
|
||||
[TimingPoints]
|
||||
800,260.869565217391,3,2,10,60,1,0
|
||||
|
||||
[HitObjects]
|
||||
// Linear
|
||||
78,193,2365,2,0,L|330:193,1,0
|
||||
78,193,3669,2,0,L|330:193,1,0
|
||||
78,193,4973,2,0,L|330:193,1,0
|
||||
|
||||
// Perfect-curve
|
||||
151,206,6278,2,0,P|293:75|345:204,1,0
|
||||
151,206,8104,2,0,P|293:75|345:204,1,0
|
||||
151,206,9930,2,0,P|293:75|345:204,1,0
|
||||
|
||||
// Bezier
|
||||
76,191,11756,2,0,B|176:59|358:340|438:190,1,0
|
||||
76,191,13582,2,0,B|176:59|358:340|438:190,1,0
|
||||
76,191,15408,2,0,B|176:59|358:340|438:190,1,0
|
@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
private readonly TrailPart[] parts = new TrailPart[max_sprites];
|
||||
private Vector2 size;
|
||||
|
||||
private readonly VertexBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
||||
private readonly TrailBatch vertexBatch = new TrailBatch(max_sprites, 1);
|
||||
|
||||
public TrailDrawNode(CursorTrail source)
|
||||
: base(source)
|
||||
@ -196,21 +196,16 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
for (int i = 0; i < parts.Length; ++i)
|
||||
{
|
||||
vertexBatch.DrawTime = parts[i].Time;
|
||||
|
||||
Vector2 pos = parts[i].Position;
|
||||
float localTime = parts[i].Time;
|
||||
|
||||
DrawQuad(
|
||||
texture,
|
||||
new Quad(pos.X - size.X / 2, pos.Y - size.Y / 2, size.X, size.Y),
|
||||
DrawColourInfo.Colour,
|
||||
null,
|
||||
v => vertexBatch.Add(new TexturedTrailVertex
|
||||
{
|
||||
Position = v.Position,
|
||||
TexturePosition = v.TexturePosition,
|
||||
Time = localTime + 1,
|
||||
Colour = v.Colour,
|
||||
}));
|
||||
vertexBatch.AddAction);
|
||||
}
|
||||
|
||||
shader.Unbind();
|
||||
@ -222,6 +217,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
vertexBatch.Dispose();
|
||||
}
|
||||
|
||||
// Todo: This shouldn't exist, but is currently used to reduce allocations by caching variable-capturing closures.
|
||||
private class TrailBatch : QuadBatch<TexturedTrailVertex>
|
||||
{
|
||||
public new readonly Action<TexturedVertex2D> AddAction;
|
||||
public float DrawTime;
|
||||
|
||||
public TrailBatch(int size, int maxBuffers)
|
||||
: base(size, maxBuffers)
|
||||
{
|
||||
AddAction = v => Add(new TexturedTrailVertex
|
||||
{
|
||||
Position = v.Position,
|
||||
TexturePosition = v.TexturePosition,
|
||||
Time = DrawTime + 1,
|
||||
Colour = v.Colour,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Rulesets.UI;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.UI.Cursor;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
@ -39,7 +40,13 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = 1,
|
||||
},
|
||||
HitObjectContainer,
|
||||
// Todo: This should not exist, but currently helps to reduce LOH allocations due to unbinding skin source events on judgement disposal
|
||||
// Todo: Remove when hitobjects are properly pooled
|
||||
new LocalSkinOverrideContainer(null)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = HitObjectContainer,
|
||||
},
|
||||
approachCircles = new ApproachCircleProxyContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Import Project="..\osu.TestProject.props" />
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
// TODO: update to use new state management.
|
||||
var circlePiece = MainPiece as CirclePiece;
|
||||
circlePiece?.FlashBox.FinishTransforms();
|
||||
|
||||
|
@ -121,6 +121,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool UseTransformStateManagement => false;
|
||||
|
||||
// Normal and clap samples are handled by the drum
|
||||
protected override IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP);
|
||||
|
||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Tests.iOS
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
UIApplication.Main(args, null, "AppDelegate");
|
||||
UIApplication.Main(args, "GameUIApplication", "AppDelegate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Replays;
|
||||
@ -9,7 +10,7 @@ using osu.Game.Rulesets.Replays;
|
||||
namespace osu.Game.Tests.NonVisual
|
||||
{
|
||||
[TestFixture]
|
||||
public class FramedReplayinputHandlerTest
|
||||
public class FramedReplayInputHandlerTest
|
||||
{
|
||||
private Replay replay;
|
||||
private TestInputHandler handler;
|
||||
@ -160,10 +161,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
[Test]
|
||||
public void TestRewindInsideImportantSection()
|
||||
{
|
||||
// fast forward to important section
|
||||
while (handler.SetFrameFromTime(3000) != null)
|
||||
{
|
||||
}
|
||||
fastForwardToPoint(3000);
|
||||
|
||||
setTime(4000, 4000);
|
||||
confirmCurrentFrame(4);
|
||||
@ -205,10 +203,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
[Test]
|
||||
public void TestRewindOutOfImportantSection()
|
||||
{
|
||||
// fast forward to important section
|
||||
while (handler.SetFrameFromTime(3500) != null)
|
||||
{
|
||||
}
|
||||
fastForwardToPoint(3500);
|
||||
|
||||
confirmCurrentFrame(3);
|
||||
confirmNextFrame(4);
|
||||
@ -227,6 +222,15 @@ namespace osu.Game.Tests.NonVisual
|
||||
confirmNextFrame(2);
|
||||
}
|
||||
|
||||
private void fastForwardToPoint(double destination)
|
||||
{
|
||||
for (int i = 0; i < 1000; i++)
|
||||
if (handler.SetFrameFromTime(destination) == null)
|
||||
return;
|
||||
|
||||
throw new TimeoutException("Seek was never fulfilled");
|
||||
}
|
||||
|
||||
private void setTime(double set, double? expect)
|
||||
{
|
||||
Assert.AreEqual(expect, handler.SetFrameFromTime(set));
|
||||
@ -274,6 +278,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
public TestInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
FrameAccuratePlayback = true;
|
||||
}
|
||||
|
||||
protected override double AllowedImportantTimeSpan => 1000;
|
@ -10,6 +10,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Platform;
|
||||
@ -36,7 +37,7 @@ using osuTK.Graphics;
|
||||
namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneBackgroundScreenBeatmap : ManualInputManagerTestScene
|
||||
public class TestSceneUserDimContainer : ManualInputManagerTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
@ -137,14 +138,14 @@ namespace osu.Game.Tests.Visual.Background
|
||||
player.StoryboardEnabled.Value = true;
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible());
|
||||
AddAssert("Background is invisible, storyboard is visible", () => songSelect.IsBackgroundInvisible() && player.IsStoryboardVisible);
|
||||
AddStep("Storyboard Disabled", () =>
|
||||
{
|
||||
player.ReplacesBackground.Value = false;
|
||||
player.StoryboardEnabled.Value = false;
|
||||
});
|
||||
waitForDim();
|
||||
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && player.IsStoryboardInvisible());
|
||||
AddAssert("Background is visible, storyboard is invisible", () => songSelect.IsBackgroundVisible() && !player.IsStoryboardVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -241,14 +242,15 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
player.StoryboardEnabled.Value = false;
|
||||
player.ReplacesBackground.Value = false;
|
||||
player.CurrentStoryboardContainer.Add(new OsuSpriteText
|
||||
player.DimmableStoryboard.Add(new OsuSpriteText
|
||||
{
|
||||
Size = new Vector2(250, 50),
|
||||
Size = new Vector2(500, 50),
|
||||
Alpha = 1,
|
||||
Colour = Color4.Tomato,
|
||||
Colour = Color4.White,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = "THIS IS A STORYBOARD",
|
||||
Font = new FontUsage(size: 50)
|
||||
});
|
||||
});
|
||||
|
||||
@ -300,7 +302,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
public bool IsBackgroundUndimmed() => ((FadeAccessibleBackground)Background).CurrentColour == Color4.White;
|
||||
|
||||
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * 25);
|
||||
public bool IsUserBlurApplied() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2((float)BlurLevel.Value * BackgroundScreenBeatmap.USER_BLUR_FACTOR);
|
||||
|
||||
public bool IsUserBlurDisabled() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(0);
|
||||
|
||||
@ -333,17 +335,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
|
||||
|
||||
protected override UserDimContainer CreateStoryboardContainer()
|
||||
{
|
||||
return new TestUserDimContainer(true)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 1,
|
||||
EnableUserDim = { Value = true }
|
||||
};
|
||||
}
|
||||
|
||||
public UserDimContainer CurrentStoryboardContainer => StoryboardContainer;
|
||||
public new DimmableStoryboard DimmableStoryboard => base.DimmableStoryboard;
|
||||
|
||||
// Whether or not the player should be allowed to load.
|
||||
public bool BlockLoad;
|
||||
@ -357,9 +349,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsStoryboardVisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha == 1;
|
||||
|
||||
public bool IsStoryboardInvisible() => ((TestUserDimContainer)CurrentStoryboardContainer).CurrentAlpha <= 1;
|
||||
public bool IsStoryboardVisible => DimmableStoryboard.ContentDisplayed;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config, CancellationToken token)
|
||||
@ -392,15 +382,15 @@ namespace osu.Game.Tests.Visual.Background
|
||||
|
||||
private class FadeAccessibleBackground : BackgroundScreenBeatmap
|
||||
{
|
||||
protected override UserDimContainer CreateFadeContainer() => fadeContainer = new TestUserDimContainer { RelativeSizeAxes = Axes.Both };
|
||||
protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both };
|
||||
|
||||
public Color4 CurrentColour => fadeContainer.CurrentColour;
|
||||
public Color4 CurrentColour => dimmable.CurrentColour;
|
||||
|
||||
public float CurrentAlpha => fadeContainer.CurrentAlpha;
|
||||
public float CurrentAlpha => dimmable.CurrentAlpha;
|
||||
|
||||
public Vector2 CurrentBlur => Background.BlurSigma;
|
||||
|
||||
private TestUserDimContainer fadeContainer;
|
||||
private TestDimmableBackground dimmable;
|
||||
|
||||
public FadeAccessibleBackground(WorkingBeatmap beatmap)
|
||||
: base(beatmap)
|
||||
@ -408,15 +398,10 @@ namespace osu.Game.Tests.Visual.Background
|
||||
}
|
||||
}
|
||||
|
||||
private class TestUserDimContainer : UserDimContainer
|
||||
private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground
|
||||
{
|
||||
public Color4 CurrentColour => DimContainer.Colour;
|
||||
public float CurrentAlpha => DimContainer.Alpha;
|
||||
|
||||
public TestUserDimContainer(bool isStoryboard = false)
|
||||
: base(isStoryboard)
|
||||
{
|
||||
}
|
||||
public Color4 CurrentColour => Content.Colour;
|
||||
public float CurrentAlpha => Content.Alpha;
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
@ -16,12 +17,13 @@ using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestScenePlayerLoader : ManualInputManagerTestScene
|
||||
{
|
||||
private PlayerLoader loader;
|
||||
private TestPlayerLoader loader;
|
||||
private OsuScreenStack stack;
|
||||
|
||||
[SetUp]
|
||||
@ -31,19 +33,29 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestBlockLoadViaMouseMovement()
|
||||
{
|
||||
AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => new TestPlayer(false, false))));
|
||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||
AddRepeatStep("move mouse", () => InputManager.MoveMouseTo(loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) * RNG.NextSingle()), 20);
|
||||
AddAssert("loader still active", () => loader.IsCurrentScreen());
|
||||
AddUntilStep("loads after idle", () => !loader.IsCurrentScreen());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoadContinuation()
|
||||
{
|
||||
Player player = null;
|
||||
SlowLoadPlayer slowPlayer = null;
|
||||
|
||||
AddStep("load dummy beatmap", () => stack.Push(loader = new PlayerLoader(() => player = new TestPlayer(false, false))));
|
||||
AddStep("load dummy beatmap", () => stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer(false, false))));
|
||||
AddUntilStep("wait for current", () => loader.IsCurrentScreen());
|
||||
AddStep("mouse in centre", () => InputManager.MoveMouseTo(loader.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("wait for player to be current", () => player.IsCurrentScreen());
|
||||
AddStep("load slow dummy beatmap", () =>
|
||||
{
|
||||
stack.Push(loader = new PlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
|
||||
stack.Push(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
|
||||
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000);
|
||||
});
|
||||
|
||||
@ -61,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("load player", () =>
|
||||
{
|
||||
Mods.Value = new[] { gameMod = new TestMod() };
|
||||
stack.Push(loader = new PlayerLoader(() => player = new TestPlayer()));
|
||||
stack.Push(loader = new TestPlayerLoader(() => player = new TestPlayer()));
|
||||
});
|
||||
|
||||
AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
|
||||
@ -85,6 +97,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddAssert("player mods applied", () => playerMod2.Applied);
|
||||
}
|
||||
|
||||
private class TestPlayerLoader : PlayerLoader
|
||||
{
|
||||
public new VisualSettings VisualSettings => base.VisualSettings;
|
||||
|
||||
public TestPlayerLoader(Func<Player> createPlayer)
|
||||
: base(createPlayer)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class TestMod : Mod, IApplicableToScoreProcessor
|
||||
{
|
||||
public override string Name => string.Empty;
|
||||
|
@ -1,19 +1,88 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneSkipOverlay : OsuTestScene
|
||||
public class TestSceneSkipOverlay : ManualInputManagerTestScene
|
||||
{
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
private SkipOverlay skip;
|
||||
private int requestCount;
|
||||
|
||||
Add(new SkipOverlay(Clock.CurrentTime + 5000));
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
requestCount = 0;
|
||||
Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = new FramedOffsetClock(Clock)
|
||||
{
|
||||
Offset = -Clock.CurrentTime,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
skip = new SkipOverlay(6000)
|
||||
{
|
||||
RequestSeek = _ => requestCount++
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestFadeOnIdle()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(Vector2.Zero));
|
||||
AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
|
||||
AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
|
||||
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("fully visible", () => skip.Children.First().Alpha == 1);
|
||||
AddUntilStep("wait for fade", () => skip.Children.First().Alpha < 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClickableAfterFade()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddUntilStep("wait for fade", () => skip.Children.First().Alpha == 0);
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
checkRequestCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClickOnlyActuatesOnce()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
AddStep("click", () => InputManager.Click(MouseButton.Left));
|
||||
checkRequestCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDoesntFadeOnMouseDown()
|
||||
{
|
||||
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
|
||||
AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
|
||||
AddUntilStep("wait for overlay disapper", () => !skip.IsAlive);
|
||||
AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
|
||||
AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
checkRequestCount(0);
|
||||
}
|
||||
|
||||
private void checkRequestCount(int expected) =>
|
||||
AddAssert($"request count is {expected}", () => requestCount == expected);
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
StarDifficulty = 9.99,
|
||||
Version = @"TEST",
|
||||
Length = 456000,
|
||||
Ruleset = maniaRuleset,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
@ -118,7 +119,6 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 456000,
|
||||
CircleCount = 111,
|
||||
SliderCount = 12,
|
||||
PlayCount = 222,
|
||||
@ -181,6 +181,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
StarDifficulty = 5.67,
|
||||
Version = @"ANOTHER TEST",
|
||||
Length = 123000,
|
||||
Ruleset = taikoRuleset,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
@ -191,7 +192,6 @@ namespace osu.Game.Tests.Visual.Online
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 123000,
|
||||
CircleCount = 123,
|
||||
SliderCount = 45,
|
||||
PlayCount = 567,
|
||||
|
@ -24,6 +24,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(ChangelogListing),
|
||||
typeof(ChangelogSingleBuild),
|
||||
typeof(ChangelogBuild),
|
||||
typeof(Comments),
|
||||
};
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
});
|
||||
|
||||
channelTabControl.OnRequestLeave += channel => channelTabControl.RemoveChannel(channel);
|
||||
channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue.ToString();
|
||||
channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue;
|
||||
|
||||
AddStep("Add random private channel", addRandomPrivateChannel);
|
||||
AddAssert("There is only one channels", () => channelTabControl.Items.Count() == 2);
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
typeof(HistoricalSection),
|
||||
typeof(PaginatedMostPlayedBeatmapContainer),
|
||||
typeof(DrawableMostPlayedRow),
|
||||
typeof(DrawableMostPlayedBeatmap),
|
||||
typeof(DrawableProfileRow)
|
||||
};
|
||||
|
||||
|
@ -3,19 +3,18 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays.BeatmapSet.Scores;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
@ -30,11 +29,9 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(ScoreTableRowBackground),
|
||||
};
|
||||
|
||||
private readonly Box background;
|
||||
|
||||
public TestSceneScoresContainer()
|
||||
{
|
||||
ScoresContainer scoresContainer;
|
||||
TestScoresContainer scoresContainer;
|
||||
|
||||
Child = new Container
|
||||
{
|
||||
@ -44,108 +41,137 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Width = 0.8f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box { RelativeSizeAxes = Axes.Both },
|
||||
scoresContainer = new ScoresContainer(),
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
scoresContainer = new TestScoresContainer(),
|
||||
}
|
||||
};
|
||||
|
||||
var scores = new List<ScoreInfo>
|
||||
var allScores = new APILegacyScores
|
||||
{
|
||||
new ScoreInfo
|
||||
Scores = new List<APILegacyScoreInfo>
|
||||
{
|
||||
User = new User
|
||||
new APILegacyScoreInfo
|
||||
{
|
||||
Id = 6602580,
|
||||
Username = @"waaiiru",
|
||||
Country = new Country
|
||||
User = new User
|
||||
{
|
||||
FullName = @"Spain",
|
||||
FlagName = @"ES",
|
||||
Id = 6602580,
|
||||
Username = @"waaiiru",
|
||||
Country = new Country
|
||||
{
|
||||
FullName = @"Spain",
|
||||
FlagName = @"ES",
|
||||
},
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
new OsuModHardRock(),
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
},
|
||||
new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 4608074,
|
||||
Username = @"Skycries",
|
||||
Country = new Country
|
||||
Mods = new Mod[]
|
||||
{
|
||||
FullName = @"Brazil",
|
||||
FlagName = @"BR",
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
new OsuModHardRock(),
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
},
|
||||
Mods = new Mod[]
|
||||
new APILegacyScoreInfo
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
},
|
||||
Rank = ScoreRank.S,
|
||||
PP = 190,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234789,
|
||||
Accuracy = 0.9997,
|
||||
},
|
||||
new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 1014222,
|
||||
Username = @"eLy",
|
||||
Country = new Country
|
||||
User = new User
|
||||
{
|
||||
FullName = @"Japan",
|
||||
FlagName = @"JP",
|
||||
Id = 4608074,
|
||||
Username = @"Skycries",
|
||||
Country = new Country
|
||||
{
|
||||
FullName = @"Brazil",
|
||||
FlagName = @"BR",
|
||||
},
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
},
|
||||
Rank = ScoreRank.B,
|
||||
PP = 180,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 12345678,
|
||||
Accuracy = 0.9854,
|
||||
},
|
||||
new ScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 1541390,
|
||||
Username = @"Toukai",
|
||||
Country = new Country
|
||||
Mods = new Mod[]
|
||||
{
|
||||
FullName = @"Canada",
|
||||
FlagName = @"CA",
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
},
|
||||
Rank = ScoreRank.S,
|
||||
PP = 190,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234789,
|
||||
Accuracy = 0.9997,
|
||||
},
|
||||
Mods = new Mod[]
|
||||
new APILegacyScoreInfo
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
User = new User
|
||||
{
|
||||
Id = 1014222,
|
||||
Username = @"eLy",
|
||||
Country = new Country
|
||||
{
|
||||
FullName = @"Japan",
|
||||
FlagName = @"JP",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
},
|
||||
Rank = ScoreRank.B,
|
||||
PP = 180,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 12345678,
|
||||
Accuracy = 0.9854,
|
||||
},
|
||||
Rank = ScoreRank.C,
|
||||
PP = 170,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234567,
|
||||
Accuracy = 0.8765,
|
||||
},
|
||||
new ScoreInfo
|
||||
new APILegacyScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 1541390,
|
||||
Username = @"Toukai",
|
||||
Country = new Country
|
||||
{
|
||||
FullName = @"Canada",
|
||||
FlagName = @"CA",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
},
|
||||
Rank = ScoreRank.C,
|
||||
PP = 170,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234567,
|
||||
Accuracy = 0.8765,
|
||||
},
|
||||
new APILegacyScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 7151382,
|
||||
Username = @"Mayuri Hana",
|
||||
Country = new Country
|
||||
{
|
||||
FullName = @"Thailand",
|
||||
FlagName = @"TH",
|
||||
},
|
||||
},
|
||||
Rank = ScoreRank.D,
|
||||
PP = 160,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 123456,
|
||||
Accuracy = 0.6543,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
var myBestScore = new APILegacyUserTopScoreInfo
|
||||
{
|
||||
Score = new APILegacyScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
@ -163,9 +189,42 @@ namespace osu.Game.Tests.Visual.Online
|
||||
TotalScore = 123456,
|
||||
Accuracy = 0.6543,
|
||||
},
|
||||
Position = 1337,
|
||||
};
|
||||
|
||||
foreach (var s in scores)
|
||||
var oneScore = new APILegacyScores
|
||||
{
|
||||
Scores = new List<APILegacyScoreInfo>
|
||||
{
|
||||
new APILegacyScoreInfo
|
||||
{
|
||||
User = new User
|
||||
{
|
||||
Id = 6602580,
|
||||
Username = @"waaiiru",
|
||||
Country = new Country
|
||||
{
|
||||
FullName = @"Spain",
|
||||
FlagName = @"ES",
|
||||
},
|
||||
},
|
||||
Mods = new Mod[]
|
||||
{
|
||||
new OsuModDoubleTime(),
|
||||
new OsuModHidden(),
|
||||
new OsuModFlashlight(),
|
||||
new OsuModHardRock(),
|
||||
},
|
||||
Rank = ScoreRank.XH,
|
||||
PP = 200,
|
||||
MaxCombo = 1234,
|
||||
TotalScore = 1234567890,
|
||||
Accuracy = 1,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var s in allScores.Scores)
|
||||
{
|
||||
s.Statistics.Add(HitResult.Great, RNG.Next(2000));
|
||||
s.Statistics.Add(HitResult.Good, RNG.Next(2000));
|
||||
@ -173,15 +232,26 @@ namespace osu.Game.Tests.Visual.Online
|
||||
s.Statistics.Add(HitResult.Miss, RNG.Next(2000));
|
||||
}
|
||||
|
||||
AddStep("Load all scores", () => scoresContainer.Scores = scores);
|
||||
AddStep("Load all scores", () =>
|
||||
{
|
||||
allScores.UserScore = null;
|
||||
scoresContainer.Scores = allScores;
|
||||
});
|
||||
AddStep("Load null scores", () => scoresContainer.Scores = null);
|
||||
AddStep("Load only one score", () => scoresContainer.Scores = new[] { scores.First() });
|
||||
AddStep("Load only one score", () => scoresContainer.Scores = oneScore);
|
||||
AddStep("Load scores with my best", () =>
|
||||
{
|
||||
allScores.UserScore = myBestScore;
|
||||
scoresContainer.Scores = allScores;
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private class TestScoresContainer : ScoresContainer
|
||||
{
|
||||
background.Colour = colours.Gray2;
|
||||
public new APILegacyScores Scores
|
||||
{
|
||||
set => base.Scores = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Users;
|
||||
@ -27,8 +24,6 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
typeof(RetrievalFailurePlaceholder),
|
||||
};
|
||||
|
||||
private RulesetStore rulesets;
|
||||
|
||||
private readonly FailableLeaderboard leaderboard;
|
||||
|
||||
public TestSceneLeaderboard()
|
||||
@ -47,13 +42,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter));
|
||||
AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn));
|
||||
AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable));
|
||||
AddStep(@"Real beatmap", realBeatmap);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(RulesetStore rulesets)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
|
||||
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
|
||||
}
|
||||
|
||||
private void newScores()
|
||||
@ -245,34 +235,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
leaderboard.Scores = scores;
|
||||
}
|
||||
|
||||
private void realBeatmap()
|
||||
private void showBeatmapWithStatus(BeatmapSetOnlineStatus status)
|
||||
{
|
||||
leaderboard.Beatmap = new BeatmapInfo
|
||||
{
|
||||
StarDifficulty = 1.36,
|
||||
Version = @"BASIC",
|
||||
OnlineBeatmapID = 1113057,
|
||||
Ruleset = rulesets.GetRuleset(0),
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
CircleSize = 4,
|
||||
DrainRate = 6.5f,
|
||||
OverallDifficulty = 6.5f,
|
||||
ApproachRate = 5,
|
||||
},
|
||||
OnlineInfo = new BeatmapOnlineInfo
|
||||
{
|
||||
Length = 115000,
|
||||
CircleCount = 265,
|
||||
SliderCount = 71,
|
||||
PlayCount = 47906,
|
||||
PassCount = 19899,
|
||||
},
|
||||
Metrics = new BeatmapMetrics
|
||||
{
|
||||
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
|
||||
},
|
||||
Status = status,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -133,6 +133,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
|
||||
AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
|
||||
AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
|
||||
AddStep(@"Sort by DateAdded", delegate { songSelect.FilterControl.Sort = SortMode.DateAdded; });
|
||||
AddStep(@"Sort by BPM", delegate { songSelect.FilterControl.Sort = SortMode.BPM; });
|
||||
AddStep(@"Sort by Length", delegate { songSelect.FilterControl.Sort = SortMode.Length; });
|
||||
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
||||
}
|
||||
|
||||
@ -265,16 +268,21 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
int beatmapId = setId * 10 + i;
|
||||
|
||||
int length = RNG.Next(30000, 200000);
|
||||
double bpm = RNG.NextSingle(80, 200);
|
||||
|
||||
beatmaps.Add(new BeatmapInfo
|
||||
{
|
||||
Ruleset = getRuleset(),
|
||||
OnlineBeatmapID = beatmapId,
|
||||
Path = "normal.osu",
|
||||
Version = $"{beatmapId}",
|
||||
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||
Length = length,
|
||||
BPM = bpm,
|
||||
BaseDifficulty = new BeatmapDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -286,10 +294,11 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
// Create random metadata, then we can check if sorting works based on these
|
||||
Artist = "Some Artist " + RNG.Next(0, 9),
|
||||
Title = $"Some Song (set id {setId})",
|
||||
Title = $"Some Song (set id {setId}, max bpm {beatmaps.Max(b => b.BPM):0.#})",
|
||||
AuthorString = "Some Guy " + RNG.Next(0, 9),
|
||||
},
|
||||
Beatmaps = beatmaps
|
||||
Beatmaps = beatmaps,
|
||||
DateAdded = DateTimeOffset.UtcNow,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneBackButton : OsuTestScene
|
||||
{
|
||||
private readonly BackButton button;
|
||||
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(TwoLayerButton)
|
||||
@ -23,6 +21,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
public TestSceneBackButton()
|
||||
{
|
||||
BackButton button;
|
||||
|
||||
Child = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@ -40,11 +40,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Action = () => button.Hide(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
button.Action = () => button.Hide();
|
||||
|
||||
AddStep("show button", () => button.Show());
|
||||
AddStep("hide button", () => button.Hide());
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
@ -23,11 +24,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
typeof(Button)
|
||||
};
|
||||
|
||||
public TestSceneButtonSystem()
|
||||
{
|
||||
OsuLogo logo;
|
||||
ButtonSystem buttons;
|
||||
private OsuLogo logo;
|
||||
private ButtonSystem buttons;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
@ -36,13 +38,47 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
buttons = new ButtonSystem(),
|
||||
logo = new OsuLogo { RelativePositionAxes = Axes.Both }
|
||||
logo = new OsuLogo
|
||||
{
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Position = new Vector2(0.5f)
|
||||
}
|
||||
};
|
||||
|
||||
buttons.SetOsuLogo(logo);
|
||||
});
|
||||
|
||||
[Test]
|
||||
public void TestAllStates()
|
||||
{
|
||||
foreach (var s in Enum.GetValues(typeof(ButtonSystemState)).OfType<ButtonSystemState>().Skip(1))
|
||||
AddStep($"State to {s}", () => buttons.State = s);
|
||||
|
||||
AddStep("Enter mode", performEnterMode);
|
||||
|
||||
AddStep("Return to menu", () =>
|
||||
{
|
||||
buttons.State = ButtonSystemState.Play;
|
||||
buttons.FadeIn(MainMenu.FADE_IN_DURATION, Easing.OutQuint);
|
||||
buttons.MoveTo(new Vector2(0), MainMenu.FADE_IN_DURATION, Easing.OutQuint);
|
||||
logo.FadeColour(Color4.White, 100, Easing.OutQuint);
|
||||
logo.FadeIn(100, Easing.OutQuint);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSmoothExit()
|
||||
{
|
||||
AddStep("Enter mode", performEnterMode);
|
||||
}
|
||||
|
||||
private void performEnterMode()
|
||||
{
|
||||
buttons.State = ButtonSystemState.EnteringMode;
|
||||
buttons.FadeOut(MainMenu.FADE_OUT_DURATION, Easing.InSine);
|
||||
buttons.MoveTo(new Vector2(-800, 0), MainMenu.FADE_OUT_DURATION, Easing.InSine);
|
||||
logo.FadeOut(300, Easing.InSine)
|
||||
.ScaleTo(0.2f, 300, Easing.InSine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
},
|
||||
};
|
||||
|
||||
breadcrumbs.Current.ValueChanged += screen => titleText.Text = $"Changed to {screen.NewValue.ToString()}";
|
||||
breadcrumbs.Current.ValueChanged += screen => titleText.Text = $"Changed to {screen.NewValue}";
|
||||
breadcrumbs.Current.TriggerChange();
|
||||
|
||||
waitForCurrent();
|
||||
|
@ -3,7 +3,7 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
|
@ -5,9 +5,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.10.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
@ -159,7 +159,7 @@ namespace osu.Game.Tournament.Components
|
||||
}
|
||||
|
||||
var bpm = beatmap.BeatmapSet.OnlineInfo.BPM;
|
||||
var length = beatmap.OnlineInfo.Length;
|
||||
var length = beatmap.Length;
|
||||
string hardRockExtra = "";
|
||||
string srExtra = "";
|
||||
|
||||
@ -180,7 +180,7 @@ namespace osu.Game.Tournament.Components
|
||||
|
||||
panelContents.Children = new Drawable[]
|
||||
{
|
||||
new DiffPiece(("Length", TimeSpan.FromSeconds(length).ToString(@"mm\:ss")))
|
||||
new DiffPiece(("Length", TimeSpan.FromMilliseconds(length).ToString(@"mm\:ss")))
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
|
@ -47,8 +47,8 @@ namespace osu.Game.Tournament.Screens.MapPool
|
||||
mapFlows = new FillFlowContainer<FillFlowContainer<TournamentBeatmapPanel>>
|
||||
{
|
||||
Y = 100,
|
||||
Spacing = new Vector2(10, 20),
|
||||
Padding = new MarginPadding(50),
|
||||
Spacing = new Vector2(10, 10),
|
||||
Padding = new MarginPadding(25),
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
@ -218,7 +218,7 @@ namespace osu.Game.Tournament.Screens.MapPool
|
||||
{
|
||||
mapFlows.Add(currentFlow = new FillFlowContainer<TournamentBeatmapPanel>
|
||||
{
|
||||
Spacing = new Vector2(10, 20),
|
||||
Spacing = new Vector2(10, 5),
|
||||
Direction = FillDirection.Full,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Tournament.Screens.Showcase
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
AddInternal(new TournamentLogo());
|
||||
AddInternal(new TournamentLogo(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Screens.TeamWin
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Loop = true,
|
||||
},
|
||||
new TournamentLogo
|
||||
new TournamentLogo(false)
|
||||
{
|
||||
Y = 40,
|
||||
},
|
||||
|
@ -51,6 +51,16 @@ namespace osu.Game.Beatmaps
|
||||
[NotMapped]
|
||||
public BeatmapOnlineInfo OnlineInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The playable length in milliseconds of this beatmap.
|
||||
/// </summary>
|
||||
public double Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The most common BPM of this beatmap.
|
||||
/// </summary>
|
||||
public double BPM { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
[JsonProperty("file_sha2")]
|
||||
|
@ -23,6 +23,7 @@ using osu.Game.IO.Archives;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@ -180,19 +181,18 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
lock (workingCache)
|
||||
{
|
||||
var cached = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
|
||||
var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == beatmapInfo.ID);
|
||||
|
||||
if (cached != null)
|
||||
return cached;
|
||||
if (working == null)
|
||||
{
|
||||
if (beatmapInfo.Metadata == null)
|
||||
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
|
||||
|
||||
if (beatmapInfo.Metadata == null)
|
||||
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
|
||||
|
||||
WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(Files.Store, new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager);
|
||||
workingCache.Add(working = new BeatmapManagerWorkingBeatmap(Files.Store,
|
||||
new LargeTextureStore(host?.CreateTextureLoaderStore(Files.Store)), beatmapInfo, audioManager));
|
||||
}
|
||||
|
||||
previous?.TransferTo(working);
|
||||
workingCache.Add(working);
|
||||
|
||||
return working;
|
||||
}
|
||||
}
|
||||
@ -302,6 +302,8 @@ namespace osu.Game.Beatmaps
|
||||
beatmap.BeatmapInfo.Ruleset = ruleset;
|
||||
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
||||
beatmap.BeatmapInfo.StarDifficulty = ruleset?.CreateInstance().CreateDifficultyCalculator(new DummyConversionBeatmap(beatmap)).Calculate().StarRating ?? 0;
|
||||
beatmap.BeatmapInfo.Length = calculateLength(beatmap);
|
||||
beatmap.BeatmapInfo.BPM = beatmap.ControlPointInfo.BPMMode;
|
||||
|
||||
beatmapInfos.Add(beatmap.BeatmapInfo);
|
||||
}
|
||||
@ -310,6 +312,19 @@ namespace osu.Game.Beatmaps
|
||||
return beatmapInfos;
|
||||
}
|
||||
|
||||
private double calculateLength(IBeatmap b)
|
||||
{
|
||||
if (!b.HitObjects.Any())
|
||||
return 0;
|
||||
|
||||
var lastObject = b.HitObjects.Last();
|
||||
|
||||
double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
|
||||
double startTime = b.HitObjects.First().StartTime;
|
||||
|
||||
return endTime - startTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dummy WorkingBeatmap for the purpose of retrieving a beatmap for star difficulty calculation.
|
||||
/// </summary>
|
||||
@ -371,7 +386,7 @@ namespace osu.Game.Beatmaps
|
||||
beatmap.OnlineBeatmapID = res.OnlineBeatmapID;
|
||||
};
|
||||
|
||||
req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap}", e); };
|
||||
req.Failure += e => { LogForModel(set, $"Online retrieval failed for {beatmap} ({e.Message})"); };
|
||||
|
||||
// intentionally blocking to limit web request concurrency
|
||||
req.Perform(api);
|
||||
|
@ -8,11 +8,6 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public class BeatmapOnlineInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The length in milliseconds of this beatmap's song.
|
||||
/// </summary>
|
||||
public double Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of circles in this beatmap.
|
||||
/// </summary>
|
||||
|
@ -35,8 +35,21 @@ namespace osu.Game.Beatmaps
|
||||
[NotMapped]
|
||||
public BeatmapSetMetrics Metrics { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum star difficulty of all beatmaps in this set.
|
||||
/// </summary>
|
||||
public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum playable length in milliseconds of all beatmaps in this set.
|
||||
/// </summary>
|
||||
public double MaxLength => Beatmaps?.Max(b => b.Length) ?? 0;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum BPM of all beatmaps in this set.
|
||||
/// </summary>
|
||||
public double MaxBPM => Beatmaps?.Max(b => b.BPM) ?? 0;
|
||||
|
||||
[NotMapped]
|
||||
public bool DeletePending { get; set; }
|
||||
|
||||
|
@ -66,6 +66,11 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public int FavouriteCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this beatmap set has been favourited by the current user.
|
||||
/// </summary>
|
||||
public bool HasFavourited { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The availability of this beatmap set.
|
||||
/// </summary>
|
||||
|
@ -35,15 +35,15 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Func<Drawable> createContentFunc, double timeBeforeLoad)
|
||||
=> new DelayedLoadUnloadWrapper(createContentFunc, timeBeforeLoad, UnloadDelay);
|
||||
|
||||
protected override double TransformDuration => 400;
|
||||
|
||||
protected override Drawable CreateDrawable(BeatmapInfo model)
|
||||
{
|
||||
Drawable drawable = getDrawableForModel(model);
|
||||
|
||||
var drawable = getDrawableForModel(model);
|
||||
drawable.RelativeSizeAxes = Axes.Both;
|
||||
drawable.Anchor = Anchor.Centre;
|
||||
drawable.Origin = Anchor.Centre;
|
||||
drawable.FillMode = FillMode.Fill;
|
||||
drawable.OnLoadComplete += d => d.FadeInFromZero(400);
|
||||
|
||||
return drawable;
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
// cancelling the beatmap load is safe for now since the retrieval is a synchronous
|
||||
// operation. if we add an async retrieval method this may need to be reconsidered.
|
||||
beatmapCancellation.Cancel();
|
||||
beatmapCancellation?.Cancel();
|
||||
total_count.Value--;
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,7 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
|
||||
|
||||
Set(OsuSetting.ShowInterface, true);
|
||||
Set(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||
Set(OsuSetting.KeyOverlay, false);
|
||||
|
||||
Set(OsuSetting.FloatingComments, false);
|
||||
@ -131,6 +132,7 @@ namespace osu.Game.Configuration
|
||||
KeyOverlay,
|
||||
FloatingComments,
|
||||
ShowInterface,
|
||||
ShowHealthDisplayWhenCantFail,
|
||||
MouseDisableButtons,
|
||||
MouseDisableWheel,
|
||||
AudioOffset,
|
||||
|
@ -41,6 +41,9 @@ namespace osu.Game.Database
|
||||
{
|
||||
// required to initialise native SQLite libraries on some platforms.
|
||||
SQLitePCL.Batteries_V2.Init();
|
||||
|
||||
// https://github.com/aspnet/EntityFrameworkCore/issues/9994#issuecomment-508588678
|
||||
SQLitePCL.raw.sqlite3_config(2 /*SQLITE_CONFIG_MULTITHREAD*/);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
/// </summary>
|
||||
public class Background : CompositeDrawable
|
||||
{
|
||||
public Sprite Sprite;
|
||||
public readonly Sprite Sprite;
|
||||
|
||||
private readonly string textureName;
|
||||
|
||||
@ -51,7 +51,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
|
||||
public void BlurTo(Vector2 newBlurSigma, double duration = 0, Easing easing = Easing.None)
|
||||
{
|
||||
if (bufferedContainer == null)
|
||||
if (bufferedContainer == null && newBlurSigma != Vector2.Zero)
|
||||
{
|
||||
RemoveInternal(Sprite);
|
||||
|
||||
@ -63,7 +63,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
});
|
||||
}
|
||||
|
||||
bufferedContainer.BlurTo(newBlurSigma, duration, easing);
|
||||
bufferedContainer?.BlurTo(newBlurSigma, duration, easing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ using osuTK.Graphics;
|
||||
using System;
|
||||
using osu.Framework.Graphics.Shaders;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osuTK.Graphics.ES30;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
using osu.Framework.Allocation;
|
||||
@ -137,11 +136,13 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
}
|
||||
}
|
||||
|
||||
protected int AimCount;
|
||||
|
||||
private void addTriangles(bool randomY)
|
||||
{
|
||||
int aimTriangleCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
|
||||
AimCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio);
|
||||
|
||||
for (int i = 0; i < aimTriangleCount - parts.Count; i++)
|
||||
for (int i = 0; i < AimCount - parts.Count; i++)
|
||||
parts.Add(createTriangle(randomY));
|
||||
}
|
||||
|
||||
@ -190,7 +191,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
||||
private Vector2 size;
|
||||
|
||||
private readonly LinearBatch<TexturedVertex2D> vertexBatch = new LinearBatch<TexturedVertex2D>(100 * 3, 10, PrimitiveType.Triangles);
|
||||
private TriangleBatch<TexturedVertex2D> vertexBatch;
|
||||
|
||||
public TrianglesDrawNode(Triangles source)
|
||||
: base(source)
|
||||
@ -213,6 +214,12 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
base.Draw(vertexAction);
|
||||
|
||||
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
|
||||
{
|
||||
vertexBatch?.Dispose();
|
||||
vertexBatch = new TriangleBatch<TexturedVertex2D>(Source.AimCount, 1);
|
||||
}
|
||||
|
||||
shader.Bind();
|
||||
|
||||
Vector2 localInflationAmount = edge_smoothness * DrawInfo.MatrixInverse.ExtractScale().Xy;
|
||||
@ -246,7 +253,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
||||
vertexBatch.Dispose();
|
||||
vertexBatch?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,26 @@
|
||||
// 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.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Screens.Play;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// A container that applies user-configured visual settings to its contents.
|
||||
/// This container specifies behavior that applies to both Storyboards and Backgrounds.
|
||||
/// </summary>
|
||||
public class UserDimContainer : Container
|
||||
public abstract class UserDimContainer : Container
|
||||
{
|
||||
private const float background_fade_duration = 800;
|
||||
protected const float BACKGROUND_FADE_DURATION = 800;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not user-configured dim levels should be applied to the container.
|
||||
/// </summary>
|
||||
public readonly Bindable<bool> EnableUserDim = new Bindable<bool>();
|
||||
public readonly Bindable<bool> EnableUserDim = new Bindable<bool>(true);
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the storyboard loaded should completely hide the background behind it.
|
||||
@ -33,103 +28,58 @@ namespace osu.Game.Graphics.Containers
|
||||
public readonly Bindable<bool> StoryboardReplacesBackground = new Bindable<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// The amount of blur to be applied to the background in addition to user-specified blur.
|
||||
/// Whether the content of this container is currently being displayed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used in contexts where there can potentially be both user and screen-specified blurring occuring at the same time, such as in <see cref="PlayerLoader"/>
|
||||
/// </remarks>
|
||||
public readonly Bindable<float> BlurAmount = new Bindable<float>();
|
||||
public bool ContentDisplayed { get; private set; }
|
||||
|
||||
private Bindable<double> userDimLevel { get; set; }
|
||||
protected Bindable<double> UserDimLevel { get; private set; }
|
||||
|
||||
private Bindable<double> userBlurLevel { get; set; }
|
||||
protected Bindable<bool> ShowStoryboard { get; private set; }
|
||||
|
||||
private Bindable<bool> showStoryboard { get; set; }
|
||||
protected override Container<Drawable> Content => dimContent;
|
||||
|
||||
protected Container DimContainer { get; }
|
||||
|
||||
protected override Container<Drawable> Content => DimContainer;
|
||||
|
||||
private readonly bool isStoryboard;
|
||||
|
||||
/// <summary>
|
||||
/// As an optimisation, we add the two blur portions to be applied rather than actually applying two separate blurs.
|
||||
/// </summary>
|
||||
private Vector2 blurTarget => EnableUserDim.Value
|
||||
? new Vector2(BlurAmount.Value + (float)userBlurLevel.Value * 25)
|
||||
: new Vector2(BlurAmount.Value);
|
||||
private Container dimContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="UserDimContainer"/>.
|
||||
/// </summary>
|
||||
/// <param name="isStoryboard"> Whether or not this instance contains a storyboard.
|
||||
/// <remarks>
|
||||
/// While both backgrounds and storyboards allow user dim levels to be applied, storyboards can be toggled via <see cref="showStoryboard"/>
|
||||
/// and can cause backgrounds to become hidden via <see cref="StoryboardReplacesBackground"/>. Storyboards are also currently unable to be blurred.
|
||||
/// </remarks>
|
||||
/// </param>
|
||||
public UserDimContainer(bool isStoryboard = false)
|
||||
protected UserDimContainer()
|
||||
{
|
||||
this.isStoryboard = isStoryboard;
|
||||
AddInternal(DimContainer = new Container { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
|
||||
private Background background;
|
||||
|
||||
public Background Background
|
||||
{
|
||||
get => background;
|
||||
set
|
||||
{
|
||||
base.Add(background = value);
|
||||
background.BlurTo(blurTarget, 0, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(Drawable drawable)
|
||||
{
|
||||
if (drawable is Background)
|
||||
throw new InvalidOperationException($"Use {nameof(Background)} to set a background.");
|
||||
|
||||
base.Add(drawable);
|
||||
AddInternal(dimContent = new Container { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
userDimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||
userBlurLevel = config.GetBindable<double>(OsuSetting.BlurLevel);
|
||||
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
UserDimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||
ShowStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
|
||||
EnableUserDim.ValueChanged += _ => updateVisuals();
|
||||
userDimLevel.ValueChanged += _ => updateVisuals();
|
||||
userBlurLevel.ValueChanged += _ => updateVisuals();
|
||||
showStoryboard.ValueChanged += _ => updateVisuals();
|
||||
StoryboardReplacesBackground.ValueChanged += _ => updateVisuals();
|
||||
BlurAmount.ValueChanged += _ => updateVisuals();
|
||||
EnableUserDim.ValueChanged += _ => UpdateVisuals();
|
||||
UserDimLevel.ValueChanged += _ => UpdateVisuals();
|
||||
ShowStoryboard.ValueChanged += _ => UpdateVisuals();
|
||||
StoryboardReplacesBackground.ValueChanged += _ => UpdateVisuals();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
updateVisuals();
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
private void updateVisuals()
|
||||
/// <summary>
|
||||
/// Whether the content of this container should currently be visible.
|
||||
/// </summary>
|
||||
protected virtual bool ShowDimContent => true;
|
||||
|
||||
/// <summary>
|
||||
/// Should be invoked when any dependent dim level or user setting is changed and bring the visual state up-to-date.
|
||||
/// </summary>
|
||||
protected virtual void UpdateVisuals()
|
||||
{
|
||||
if (isStoryboard)
|
||||
{
|
||||
DimContainer.FadeTo(!showStoryboard.Value || userDimLevel.Value == 1 ? 0 : 1, background_fade_duration, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The background needs to be hidden in the case of it being replaced by the storyboard
|
||||
DimContainer.FadeTo(showStoryboard.Value && StoryboardReplacesBackground.Value ? 0 : 1, background_fade_duration, Easing.OutQuint);
|
||||
ContentDisplayed = ShowDimContent;
|
||||
|
||||
Background?.BlurTo(blurTarget, background_fade_duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
DimContainer.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)userDimLevel.Value) : Color4.White, background_fade_duration, Easing.OutQuint);
|
||||
dimContent.FadeTo((ContentDisplayed) ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||
dimContent.FadeColour(EnableUserDim.Value ? OsuColour.Gray(1 - (float)UserDimLevel.Value) : Color4.White, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs
Normal file
26
osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Graphics.ES30;
|
||||
|
||||
namespace osu.Game.Graphics.OpenGL.Vertices
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PositionAndColourVertex : IEquatable<PositionAndColourVertex>, IVertex
|
||||
{
|
||||
[VertexMember(2, VertexAttribPointerType.Float)]
|
||||
public Vector2 Position;
|
||||
|
||||
[VertexMember(4, VertexAttribPointerType.Float)]
|
||||
public Color4 Colour;
|
||||
|
||||
public bool Equals(PositionAndColourVertex other)
|
||||
=> Position.Equals(other.Position)
|
||||
&& Colour.Equals(other.Colour);
|
||||
}
|
||||
}
|
80
osu.Game/Graphics/Sprites/GlowingSpriteText.cs
Normal file
80
osu.Game/Graphics/Sprites/GlowingSpriteText.cs
Normal file
@ -0,0 +1,80 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Graphics.Sprites
|
||||
{
|
||||
public class GlowingSpriteText : Container, IHasText
|
||||
{
|
||||
private readonly OsuSpriteText spriteText, blurredText;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => spriteText.Text;
|
||||
set => blurredText.Text = spriteText.Text = value;
|
||||
}
|
||||
|
||||
public FontUsage Font
|
||||
{
|
||||
get => spriteText.Font;
|
||||
set => blurredText.Font = spriteText.Font = value.With(fixedWidth: true);
|
||||
}
|
||||
|
||||
public Vector2 TextSize
|
||||
{
|
||||
get => spriteText.Size;
|
||||
set => blurredText.Size = spriteText.Size = value;
|
||||
}
|
||||
|
||||
public ColourInfo TextColour
|
||||
{
|
||||
get => spriteText.Colour;
|
||||
set => spriteText.Colour = value;
|
||||
}
|
||||
|
||||
public ColourInfo GlowColour
|
||||
{
|
||||
get => blurredText.Colour;
|
||||
set => blurredText.Colour = value;
|
||||
}
|
||||
|
||||
public GlowingSpriteText()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new BufferedContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
BlurSigma = new Vector2(4),
|
||||
CacheDrawnFrameBuffer = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Blending = BlendingMode.Additive,
|
||||
Size = new Vector2(3f),
|
||||
Children = new[]
|
||||
{
|
||||
blurredText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Shadow = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
spriteText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Shadow = false,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -76,7 +76,12 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = path = new SmoothPath { RelativeSizeAxes = Axes.Both, PathRadius = 1 }
|
||||
Child = path = new SmoothPath
|
||||
{
|
||||
AutoSizeAxes = Axes.None,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
PathRadius = 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold) },
|
||||
text = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) },
|
||||
icon = new SpriteIcon
|
||||
{
|
||||
Size = new Vector2(14),
|
||||
@ -84,7 +84,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
};
|
||||
|
||||
Current.ValueChanged += selected => { icon.Icon = selected.NewValue ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.Circle; };
|
||||
Current.ValueChanged += selected =>
|
||||
{
|
||||
icon.Icon = selected.NewValue ? FontAwesome.Regular.CheckCircle : FontAwesome.Regular.Circle;
|
||||
text.Font = text.Font.With(weight: selected.NewValue ? FontWeight.Bold : FontWeight.Medium);
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -33,6 +34,17 @@ namespace osu.Game.Graphics.UserInterface
|
||||
PlaceholderText = "type to search";
|
||||
}
|
||||
|
||||
public override bool OnPressed(PlatformAction action)
|
||||
{
|
||||
// Shift+delete is handled via PlatformAction on macOS. this is not so useful in the context of a SearchTextBox
|
||||
// as we do not allow arrow key navigation in the first place (ie. the care should always be at the end of text)
|
||||
// Avoid handling it here to allow other components to potentially consume the shortcut.
|
||||
if (action.ActionType == PlatformActionType.CharNext && action.ActionMethod == PlatformActionMethod.Delete)
|
||||
return false;
|
||||
|
||||
return base.OnPressed(action);
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(KeyDownEvent e)
|
||||
{
|
||||
if (!e.ControlPressed && !e.ShiftPressed)
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
||||
|
||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||
new KeyBinding(InputKey.MouseButton1, GlobalAction.Back),
|
||||
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
||||
|
||||
new KeyBinding(InputKey.Space, GlobalAction.Select),
|
||||
new KeyBinding(InputKey.Enter, GlobalAction.Select),
|
||||
|
504
osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs
generated
Normal file
504
osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs
generated
Normal file
@ -0,0 +1,504 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
[DbContext(typeof(OsuDbContext))]
|
||||
[Migration("20190708070844_AddBPMAndLengthColumns")]
|
||||
partial class AddBPMAndLengthColumns
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<float>("ApproachRate");
|
||||
|
||||
b.Property<float>("CircleSize");
|
||||
|
||||
b.Property<float>("DrainRate");
|
||||
|
||||
b.Property<float>("OverallDifficulty");
|
||||
|
||||
b.Property<double>("SliderMultiplier");
|
||||
|
||||
b.Property<double>("SliderTickRate");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("BeatmapDifficulty");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AudioLeadIn");
|
||||
|
||||
b.Property<double>("BPM");
|
||||
|
||||
b.Property<int>("BaseDifficultyID");
|
||||
|
||||
b.Property<int>("BeatDivisor");
|
||||
|
||||
b.Property<int>("BeatmapSetInfoID");
|
||||
|
||||
b.Property<bool>("Countdown");
|
||||
|
||||
b.Property<double>("DistanceSpacing");
|
||||
|
||||
b.Property<int>("GridSize");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<bool>("Hidden");
|
||||
|
||||
b.Property<double>("Length");
|
||||
|
||||
b.Property<bool>("LetterboxInBreaks");
|
||||
|
||||
b.Property<string>("MD5Hash");
|
||||
|
||||
b.Property<int?>("MetadataID");
|
||||
|
||||
b.Property<int?>("OnlineBeatmapID");
|
||||
|
||||
b.Property<string>("Path");
|
||||
|
||||
b.Property<int>("RulesetID");
|
||||
|
||||
b.Property<bool>("SpecialStyle");
|
||||
|
||||
b.Property<float>("StackLeniency");
|
||||
|
||||
b.Property<double>("StarDifficulty");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.Property<string>("StoredBookmarks");
|
||||
|
||||
b.Property<double>("TimelineZoom");
|
||||
|
||||
b.Property<string>("Version");
|
||||
|
||||
b.Property<bool>("WidescreenStoryboard");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BaseDifficultyID");
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("Hash");
|
||||
|
||||
b.HasIndex("MD5Hash");
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("OnlineBeatmapID")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("RulesetID");
|
||||
|
||||
b.ToTable("BeatmapInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Artist");
|
||||
|
||||
b.Property<string>("ArtistUnicode");
|
||||
|
||||
b.Property<string>("AudioFile");
|
||||
|
||||
b.Property<string>("AuthorString")
|
||||
.HasColumnName("Author");
|
||||
|
||||
b.Property<string>("BackgroundFile");
|
||||
|
||||
b.Property<int>("PreviewTime");
|
||||
|
||||
b.Property<string>("Source");
|
||||
|
||||
b.Property<string>("Tags");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TitleUnicode");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("BeatmapMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("BeatmapSetInfoID");
|
||||
|
||||
b.Property<int>("FileInfoID");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("FileInfoID");
|
||||
|
||||
b.ToTable("BeatmapSetFileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTimeOffset>("DateAdded");
|
||||
|
||||
b.Property<bool>("DeletePending");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int?>("MetadataID");
|
||||
|
||||
b.Property<int?>("OnlineBeatmapSetID");
|
||||
|
||||
b.Property<bool>("Protected");
|
||||
|
||||
b.Property<int>("Status");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("DeletePending");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("OnlineBeatmapSetID")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("BeatmapSetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Key")
|
||||
.HasColumnName("Key");
|
||||
|
||||
b.Property<int?>("RulesetID");
|
||||
|
||||
b.Property<int?>("SkinInfoID");
|
||||
|
||||
b.Property<string>("StringValue")
|
||||
.HasColumnName("Value");
|
||||
|
||||
b.Property<int?>("Variant");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("SkinInfoID");
|
||||
|
||||
b.HasIndex("RulesetID", "Variant");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int>("ReferenceCount");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ReferenceCount");
|
||||
|
||||
b.ToTable("FileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("IntAction")
|
||||
.HasColumnName("Action");
|
||||
|
||||
b.Property<string>("KeysString")
|
||||
.HasColumnName("Keys");
|
||||
|
||||
b.Property<int?>("RulesetID");
|
||||
|
||||
b.Property<int?>("Variant");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("IntAction");
|
||||
|
||||
b.HasIndex("RulesetID", "Variant");
|
||||
|
||||
b.ToTable("KeyBinding");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||
{
|
||||
b.Property<int?>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("InstantiationInfo");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("ShortName");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Available");
|
||||
|
||||
b.HasIndex("ShortName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("RulesetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("FileInfoID");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<int?>("ScoreInfoID");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("FileInfoID");
|
||||
|
||||
b.HasIndex("ScoreInfoID");
|
||||
|
||||
b.ToTable("ScoreFileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<double>("Accuracy")
|
||||
.HasColumnType("DECIMAL(1,4)");
|
||||
|
||||
b.Property<int>("BeatmapInfoID");
|
||||
|
||||
b.Property<int>("Combo");
|
||||
|
||||
b.Property<DateTimeOffset>("Date");
|
||||
|
||||
b.Property<bool>("DeletePending");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int>("MaxCombo");
|
||||
|
||||
b.Property<string>("ModsJson")
|
||||
.HasColumnName("Mods");
|
||||
|
||||
b.Property<long?>("OnlineScoreID");
|
||||
|
||||
b.Property<double?>("PP");
|
||||
|
||||
b.Property<int>("Rank");
|
||||
|
||||
b.Property<int>("RulesetID");
|
||||
|
||||
b.Property<string>("StatisticsJson")
|
||||
.HasColumnName("Statistics");
|
||||
|
||||
b.Property<long>("TotalScore");
|
||||
|
||||
b.Property<long?>("UserID")
|
||||
.HasColumnName("UserID");
|
||||
|
||||
b.Property<string>("UserString")
|
||||
.HasColumnName("User");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BeatmapInfoID");
|
||||
|
||||
b.HasIndex("OnlineScoreID")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("RulesetID");
|
||||
|
||||
b.ToTable("ScoreInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("FileInfoID");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<int>("SkinInfoID");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("FileInfoID");
|
||||
|
||||
b.HasIndex("SkinInfoID");
|
||||
|
||||
b.ToTable("SkinFileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Creator");
|
||||
|
||||
b.Property<bool>("DeletePending");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("DeletePending");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SkinInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
|
||||
.WithMany()
|
||||
.HasForeignKey("BaseDifficultyID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
|
||||
.WithMany("Beatmaps")
|
||||
.HasForeignKey("BeatmapSetInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||
.WithMany("Beatmaps")
|
||||
.HasForeignKey("MetadataID");
|
||||
|
||||
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||
.WithMany()
|
||||
.HasForeignKey("RulesetID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
|
||||
.WithMany("Files")
|
||||
.HasForeignKey("BeatmapSetInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||
.WithMany()
|
||||
.HasForeignKey("FileInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||
.WithMany("BeatmapSets")
|
||||
.HasForeignKey("MetadataID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Skinning.SkinInfo")
|
||||
.WithMany("Settings")
|
||||
.HasForeignKey("SkinInfoID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||
.WithMany()
|
||||
.HasForeignKey("FileInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Scoring.ScoreInfo")
|
||||
.WithMany("Files")
|
||||
.HasForeignKey("ScoreInfoID");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
|
||||
.WithMany("Scores")
|
||||
.HasForeignKey("BeatmapInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||
.WithMany()
|
||||
.HasForeignKey("RulesetID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||
.WithMany()
|
||||
.HasForeignKey("FileInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Skinning.SkinInfo")
|
||||
.WithMany("Files")
|
||||
.HasForeignKey("SkinInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
33
osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs
Normal file
33
osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
public partial class AddBPMAndLengthColumns : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "BPM",
|
||||
table: "BeatmapInfo",
|
||||
nullable: false,
|
||||
defaultValue: 0.0);
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "Length",
|
||||
table: "BeatmapInfo",
|
||||
nullable: false,
|
||||
defaultValue: 0.0);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BPM",
|
||||
table: "BeatmapInfo");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Length",
|
||||
table: "BeatmapInfo");
|
||||
}
|
||||
}
|
||||
}
|
@ -45,6 +45,8 @@ namespace osu.Game.Migrations
|
||||
|
||||
b.Property<int>("AudioLeadIn");
|
||||
|
||||
b.Property<double>("BPM");
|
||||
|
||||
b.Property<int>("BaseDifficultyID");
|
||||
|
||||
b.Property<int>("BeatDivisor");
|
||||
@ -61,6 +63,8 @@ namespace osu.Game.Migrations
|
||||
|
||||
b.Property<bool>("Hidden");
|
||||
|
||||
b.Property<double>("Length");
|
||||
|
||||
b.Property<bool>("LetterboxInBreaks");
|
||||
|
||||
b.Property<string>("MD5Hash");
|
||||
|
@ -5,8 +5,10 @@ using System;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
@ -15,8 +17,9 @@ namespace osu.Game.Online.API.Requests
|
||||
private readonly BeatmapInfo beatmap;
|
||||
private readonly BeatmapLeaderboardScope scope;
|
||||
private readonly RulesetInfo ruleset;
|
||||
private readonly IEnumerable<Mod> mods;
|
||||
|
||||
public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global)
|
||||
public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable<Mod> mods = null)
|
||||
{
|
||||
if (!beatmap.OnlineBeatmapID.HasValue)
|
||||
throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}.");
|
||||
@ -27,6 +30,7 @@ namespace osu.Game.Online.API.Requests
|
||||
this.beatmap = beatmap;
|
||||
this.scope = scope;
|
||||
this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset));
|
||||
this.mods = mods ?? Array.Empty<Mod>();
|
||||
|
||||
Success += onSuccess;
|
||||
}
|
||||
@ -38,19 +42,29 @@ namespace osu.Game.Online.API.Requests
|
||||
score.Beatmap = beatmap;
|
||||
score.Ruleset = ruleset;
|
||||
}
|
||||
|
||||
var userScore = r.UserScore;
|
||||
|
||||
if (userScore != null)
|
||||
{
|
||||
userScore.Score.Beatmap = beatmap;
|
||||
userScore.Score.Ruleset = ruleset;
|
||||
}
|
||||
}
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores{createQueryParameters()}";
|
||||
|
||||
private string createQueryParameters()
|
||||
{
|
||||
var req = base.CreateWebRequest();
|
||||
StringBuilder query = new StringBuilder(@"?");
|
||||
|
||||
req.Timeout = 30000;
|
||||
req.AddParameter(@"type", scope.ToString().ToLowerInvariant());
|
||||
req.AddParameter(@"mode", ruleset.ShortName);
|
||||
query.Append($@"type={scope.ToString().ToLowerInvariant()}");
|
||||
query.Append($@"&mode={ruleset.ShortName}");
|
||||
|
||||
return req;
|
||||
foreach (var mod in mods)
|
||||
query.Append($@"&mods[]={mod.Acronym}");
|
||||
|
||||
return query.ToString();
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}/scores";
|
||||
}
|
||||
}
|
||||
|
@ -7,21 +7,20 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserBeatmapsRequest : APIRequest<List<APIBeatmapSet>>
|
||||
public class GetUserBeatmapsRequest : PaginatedAPIRequest<List<APIBeatmapSet>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly int offset;
|
||||
|
||||
private readonly BeatmapSetType type;
|
||||
|
||||
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int offset = 0)
|
||||
public GetUserBeatmapsRequest(long userId, BeatmapSetType type, int page = 0, int itemsPerPage = 6)
|
||||
: base(page, itemsPerPage)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.offset = offset;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}?offset={offset}";
|
||||
protected override string Target => $@"users/{userId}/beatmapsets/{type.ToString().Underscore()}";
|
||||
}
|
||||
|
||||
public enum BeatmapSetType
|
||||
|
@ -6,17 +6,16 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserMostPlayedBeatmapsRequest : APIRequest<List<APIUserMostPlayedBeatmap>>
|
||||
public class GetUserMostPlayedBeatmapsRequest : PaginatedAPIRequest<List<APIUserMostPlayedBeatmap>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly int offset;
|
||||
|
||||
public GetUserMostPlayedBeatmapsRequest(long userId, int offset = 0)
|
||||
public GetUserMostPlayedBeatmapsRequest(long userId, int page = 0, int itemsPerPage = 5)
|
||||
: base(page, itemsPerPage)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
protected override string Target => $@"users/{userId}/beatmapsets/most_played?offset={offset}";
|
||||
protected override string Target => $@"users/{userId}/beatmapsets/most_played";
|
||||
}
|
||||
}
|
||||
|
@ -6,18 +6,17 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserRecentActivitiesRequest : APIRequest<List<APIRecentActivity>>
|
||||
public class GetUserRecentActivitiesRequest : PaginatedAPIRequest<List<APIRecentActivity>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly int offset;
|
||||
|
||||
public GetUserRecentActivitiesRequest(long userId, int offset = 0)
|
||||
public GetUserRecentActivitiesRequest(long userId, int page = 0, int itemsPerPage = 5)
|
||||
: base(page, itemsPerPage)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
protected override string Target => $"users/{userId}/recent_activity?offset={offset}";
|
||||
protected override string Target => $"users/{userId}/recent_activity";
|
||||
}
|
||||
|
||||
public enum RecentActivityType
|
||||
|
@ -6,21 +6,19 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetUserScoresRequest : APIRequest<List<APILegacyScoreInfo>>
|
||||
public class GetUserScoresRequest : PaginatedAPIRequest<List<APILegacyScoreInfo>>
|
||||
{
|
||||
private readonly long userId;
|
||||
private readonly ScoreType type;
|
||||
private readonly int offset;
|
||||
|
||||
public GetUserScoresRequest(long userId, ScoreType type, int offset = 0)
|
||||
public GetUserScoresRequest(long userId, ScoreType type, int page = 0, int itemsPerPage = 5)
|
||||
: base(page, itemsPerPage)
|
||||
{
|
||||
this.userId = userId;
|
||||
this.type = type;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
|
||||
protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}?offset={offset}";
|
||||
protected override string Target => $@"users/{userId}/scores/{type.ToString().ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
public enum ScoreType
|
||||
|
30
osu.Game/Online/API/Requests/PaginatedAPIRequest.cs
Normal file
30
osu.Game/Online/API/Requests/PaginatedAPIRequest.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// 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.Globalization;
|
||||
using osu.Framework.IO.Network;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public abstract class PaginatedAPIRequest<T> : APIRequest<T>
|
||||
{
|
||||
private readonly int page;
|
||||
private readonly int itemsPerPage;
|
||||
|
||||
protected PaginatedAPIRequest(int page, int itemsPerPage)
|
||||
{
|
||||
this.page = page;
|
||||
this.itemsPerPage = itemsPerPage;
|
||||
}
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
{
|
||||
var req = base.CreateWebRequest();
|
||||
|
||||
req.AddParameter("offset", (page * itemsPerPage).ToString(CultureInfo.InvariantCulture));
|
||||
req.AddParameter("limit", itemsPerPage.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
return req;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
@ -71,6 +72,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
StarDifficulty = starDifficulty,
|
||||
OnlineBeatmapID = OnlineBeatmapID,
|
||||
Version = version,
|
||||
Length = TimeSpan.FromSeconds(length).TotalMilliseconds,
|
||||
Status = Status,
|
||||
BeatmapSet = set,
|
||||
Metrics = metrics,
|
||||
@ -85,7 +87,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
{
|
||||
PlayCount = playCount,
|
||||
PassCount = passCount,
|
||||
Length = length,
|
||||
CircleCount = circleCount,
|
||||
SliderCount = sliderCount,
|
||||
},
|
||||
|
@ -30,6 +30,9 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
[JsonProperty(@"preview_url")]
|
||||
private string preview { get; set; }
|
||||
|
||||
[JsonProperty(@"has_favourited")]
|
||||
private bool hasFavourited { get; set; }
|
||||
|
||||
[JsonProperty(@"play_count")]
|
||||
private int playCount { get; set; }
|
||||
|
||||
@ -91,6 +94,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
Ranked = ranked,
|
||||
LastUpdated = lastUpdated,
|
||||
Availability = availability,
|
||||
HasFavourited = hasFavourited,
|
||||
},
|
||||
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user