mirror of
https://github.com/ppy/osu.git
synced 2025-01-29 05:52:56 +08:00
Merge remote-tracking branch 'Aergwyn/master' into netstandard
This commit is contained in:
commit
267bb75458
@ -15,7 +15,9 @@ This is still heavily under development and is not intended for end-user use. Th
|
|||||||
|
|
||||||
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
|
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
|
||||||
|
|
||||||
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu-framework/issues).
|
Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
|
||||||
|
|
||||||
|
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues).
|
||||||
|
|
||||||
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. I welcome all feedback so we can make contributing to this project as pain-free as possible.
|
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. I welcome all feedback so we can make contributing to this project as pain-free as possible.
|
||||||
|
|
||||||
|
@ -9,17 +9,17 @@ cache:
|
|||||||
- inspectcode -> appveyor.yml
|
- inspectcode -> appveyor.yml
|
||||||
- packages -> **\packages.config
|
- packages -> **\packages.config
|
||||||
install:
|
install:
|
||||||
- cmd: git submodule update --init --recursive
|
- cmd: git submodule update --init --recursive --depth=5
|
||||||
- cmd: choco install resharper-clt -y
|
- cmd: choco install resharper-clt -y
|
||||||
- cmd: choco install nvika -y
|
- cmd: choco install nvika -y
|
||||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe
|
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe
|
||||||
before_build:
|
before_build:
|
||||||
- cmd: CodeFileSanity.exe
|
- cmd: CodeFileSanity.exe
|
||||||
- cmd: nuget restore
|
- cmd: nuget restore -verbosity quiet
|
||||||
build:
|
build:
|
||||||
project: osu.sln
|
project: osu.sln
|
||||||
parallel: true
|
parallel: true
|
||||||
verbosity: minimal
|
verbosity: minimal
|
||||||
after_build:
|
after_build:
|
||||||
- cmd: inspectcode /o="inspectcodereport.xml" /caches-home="inspectcode" osu.sln
|
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
@ -13,7 +13,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
|
|||||||
<add key="ProjectName" value="osu.Desktop" />
|
<add key="ProjectName" value="osu.Desktop" />
|
||||||
<add key="NuSpecName" value="osu.Desktop\osu.nuspec" />
|
<add key="NuSpecName" value="osu.Desktop\osu.nuspec" />
|
||||||
<add key="SolutionName" value="osu" />
|
<add key="SolutionName" value="osu" />
|
||||||
<add key="TargetName" value="Client\osu.Desktop" />
|
<add key="TargetName" value="osu.Desktop" />
|
||||||
<add key="PackageName" value="osulazer" />
|
<add key="PackageName" value="osulazer" />
|
||||||
<add key="IconName" value="lazer.ico" />
|
<add key="IconName" value="lazer.ico" />
|
||||||
<add key="CodeSigningCertificate" value="" />
|
<add key="CodeSigningCertificate" value="" />
|
||||||
|
@ -145,6 +145,8 @@ namespace osu.Desktop.Deploy
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static void checkReleaseFiles()
|
private static void checkReleaseFiles()
|
||||||
{
|
{
|
||||||
|
if (!canGitHub) return;
|
||||||
|
|
||||||
var releaseLines = getReleaseLines();
|
var releaseLines = getReleaseLines();
|
||||||
|
|
||||||
//ensure we have all files necessary
|
//ensure we have all files necessary
|
||||||
@ -157,6 +159,8 @@ namespace osu.Desktop.Deploy
|
|||||||
|
|
||||||
private static void pruneReleases()
|
private static void pruneReleases()
|
||||||
{
|
{
|
||||||
|
if (!canGitHub) return;
|
||||||
|
|
||||||
write("Pruning RELEASES...");
|
write("Pruning RELEASES...");
|
||||||
|
|
||||||
var releaseLines = getReleaseLines().ToList();
|
var releaseLines = getReleaseLines().ToList();
|
||||||
@ -190,7 +194,7 @@ namespace osu.Desktop.Deploy
|
|||||||
|
|
||||||
private static void uploadBuild(string version)
|
private static void uploadBuild(string version)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(GitHubAccessToken) || string.IsNullOrEmpty(codeSigningCertPath))
|
if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
write("Publishing to GitHub...");
|
write("Publishing to GitHub...");
|
||||||
@ -228,8 +232,12 @@ namespace osu.Desktop.Deploy
|
|||||||
|
|
||||||
private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
|
private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
|
||||||
|
|
||||||
|
private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
|
||||||
|
|
||||||
private static void checkGitHubReleases()
|
private static void checkGitHubReleases()
|
||||||
{
|
{
|
||||||
|
if (!canGitHub) return;
|
||||||
|
|
||||||
write("Checking GitHub releases...");
|
write("Checking GitHub releases...");
|
||||||
var req = new JsonWebRequest<List<GitHubRelease>>($"{GitHubApiEndpoint}");
|
var req = new JsonWebRequest<List<GitHubRelease>>($"{GitHubApiEndpoint}");
|
||||||
req.AuthenticatedBlockingPerform();
|
req.AuthenticatedBlockingPerform();
|
||||||
|
@ -11,14 +11,14 @@ using osu.Game.Rulesets.Objects;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||||
{
|
{
|
||||||
internal class CatchBeatmapConverter : BeatmapConverter<CatchBaseHit>
|
internal class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
|
||||||
{
|
{
|
||||||
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
|
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
|
||||||
|
|
||||||
protected override IEnumerable<CatchBaseHit> ConvertHitObject(HitObject obj, Beatmap beatmap)
|
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, Beatmap beatmap)
|
||||||
{
|
{
|
||||||
var curveData = obj as IHasCurve;
|
var curveData = obj as IHasCurve;
|
||||||
var positionData = obj as IHasPosition;
|
var positionData = obj as IHasXPosition;
|
||||||
var comboData = obj as IHasCombo;
|
var comboData = obj as IHasCombo;
|
||||||
|
|
||||||
if (positionData == null)
|
if (positionData == null)
|
||||||
|
@ -6,9 +6,9 @@ using osu.Game.Rulesets.Catch.Objects;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Beatmaps
|
namespace osu.Game.Rulesets.Catch.Beatmaps
|
||||||
{
|
{
|
||||||
internal class CatchBeatmapProcessor : BeatmapProcessor<CatchBaseHit>
|
internal class CatchBeatmapProcessor : BeatmapProcessor<CatchHitObject>
|
||||||
{
|
{
|
||||||
public override void PostProcess(Beatmap<CatchBaseHit> beatmap)
|
public override void PostProcess(Beatmap<CatchHitObject> beatmap)
|
||||||
{
|
{
|
||||||
if (beatmap.ComboColors.Count == 0)
|
if (beatmap.ComboColors.Count == 0)
|
||||||
return;
|
return;
|
||||||
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
|
|||||||
int comboIndex = 0;
|
int comboIndex = 0;
|
||||||
int colourIndex = 0;
|
int colourIndex = 0;
|
||||||
|
|
||||||
CatchBaseHit lastObj = null;
|
CatchHitObject lastObj = null;
|
||||||
|
|
||||||
foreach (var obj in beatmap.HitObjects)
|
foreach (var obj in beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
|
@ -8,14 +8,14 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch
|
namespace osu.Game.Rulesets.Catch
|
||||||
{
|
{
|
||||||
public class CatchDifficultyCalculator : DifficultyCalculator<CatchBaseHit>
|
public class CatchDifficultyCalculator : DifficultyCalculator<CatchHitObject>
|
||||||
{
|
{
|
||||||
public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
|
public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, string> categoryDifficulty = null) => 0;
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
|
||||||
|
|
||||||
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
|
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public abstract class CatchBaseHit : HitObject, IHasXPosition, IHasCombo
|
public abstract class CatchHitObject : HitObject, IHasXPosition, IHasCombo
|
||||||
{
|
{
|
||||||
|
public const double OBJECT_RADIUS = 44;
|
||||||
|
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
|
|
||||||
public Color4 ComboColour { get; set; } = Color4.Gray;
|
public Color4 ComboColour { get; set; } = Color4.Gray;
|
||||||
@ -20,5 +24,14 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
/// The next fruit starts a new combo. Used for explodey.
|
/// The next fruit starts a new combo. Used for explodey.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool LastInCombo { get; set; }
|
public virtual bool LastInCombo { get; set; }
|
||||||
|
|
||||||
|
public float Scale { get; set; } = 1;
|
||||||
|
|
||||||
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,11 +5,12 @@ using System;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||||
{
|
{
|
||||||
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
|
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
|
||||||
where TObject : CatchBaseHit
|
where TObject : CatchHitObject
|
||||||
{
|
{
|
||||||
public new TObject HitObject;
|
public new TObject HitObject;
|
||||||
|
|
||||||
@ -17,12 +18,14 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
HitObject = hitObject;
|
||||||
|
|
||||||
|
Scale = new Vector2(HitObject.Scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class DrawableCatchHitObject : DrawableScrollingHitObject<CatchBaseHit>
|
public abstract class DrawableCatchHitObject : DrawableScrollingHitObject<CatchHitObject>
|
||||||
{
|
{
|
||||||
protected DrawableCatchHitObject(CatchBaseHit hitObject)
|
protected DrawableCatchHitObject(CatchHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.Both;
|
RelativePositionAxes = Axes.Both;
|
||||||
@ -30,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
Y = (float)HitObject.StartTime;
|
Y = (float)HitObject.StartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func<CatchBaseHit, bool> CheckPosition;
|
public Func<CatchHitObject, bool> CheckPosition;
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
|
RelativeChildSize = new Vector2(1, (float)HitObject.Duration)
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (CatchBaseHit tick in s.Ticks)
|
foreach (CatchHitObject tick in s.Ticks)
|
||||||
{
|
{
|
||||||
TinyDroplet tiny = tick as TinyDroplet;
|
TinyDroplet tiny = tick as TinyDroplet;
|
||||||
if (tiny != null)
|
if (tiny != null)
|
||||||
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AddNested(DrawableHitObject<CatchBaseHit> h)
|
protected override void AddNested(DrawableHitObject<CatchHitObject> h)
|
||||||
{
|
{
|
||||||
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
|
||||||
dropletContainer.Add(h);
|
dropletContainer.Add(h);
|
||||||
|
@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
|
|||||||
{
|
{
|
||||||
public class Pulp : Circle, IHasAccentColour
|
public class Pulp : Circle, IHasAccentColour
|
||||||
{
|
{
|
||||||
public const float PULP_SIZE = 20;
|
public const float PULP_SIZE = (float)CatchHitObject.OBJECT_RADIUS / 2.2f;
|
||||||
|
|
||||||
public Pulp()
|
public Pulp()
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class Droplet : CatchBaseHit
|
public class Droplet : CatchHitObject
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class Fruit : CatchBaseHit
|
public class Fruit : CatchHitObject
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ using osu.Framework.Lists;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Objects
|
namespace osu.Game.Rulesets.Catch.Objects
|
||||||
{
|
{
|
||||||
public class JuiceStream : CatchBaseHit, IHasCurve
|
public class JuiceStream : CatchHitObject, IHasCurve
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Positional distance that results in a duration of one second, before any speed adjustments.
|
/// Positional distance that results in a duration of one second, before any speed adjustments.
|
||||||
@ -42,11 +42,11 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<CatchBaseHit> Ticks
|
public IEnumerable<CatchHitObject> Ticks
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
SortedList<CatchBaseHit> ticks = new SortedList<CatchBaseHit>((a, b) => a.StartTime.CompareTo(b.StartTime));
|
SortedList<CatchHitObject> ticks = new SortedList<CatchHitObject>((a, b) => a.StartTime.CompareTo(b.StartTime));
|
||||||
|
|
||||||
if (TickDistance == 0)
|
if (TickDistance == 0)
|
||||||
return ticks;
|
return ticks;
|
||||||
|
@ -10,14 +10,14 @@ using osu.Game.Rulesets.UI;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Scoring
|
namespace osu.Game.Rulesets.Catch.Scoring
|
||||||
{
|
{
|
||||||
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit>
|
internal class CatchScoreProcessor : ScoreProcessor<CatchHitObject>
|
||||||
{
|
{
|
||||||
public CatchScoreProcessor(RulesetContainer<CatchBaseHit> rulesetContainer)
|
public CatchScoreProcessor(RulesetContainer<CatchHitObject> rulesetContainer)
|
||||||
: base(rulesetContainer)
|
: base(rulesetContainer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<CatchBaseHit> beatmap)
|
protected override void SimulateAutoplay(Beatmap<CatchHitObject> beatmap)
|
||||||
{
|
{
|
||||||
foreach (var obj in beatmap.HitObjects)
|
foreach (var obj in beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
|
@ -11,16 +11,26 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
[Ignore("getting CI working")]
|
[Ignore("getting CI working")]
|
||||||
public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
|
public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
|
||||||
{
|
{
|
||||||
public TestCaseCatchStacker() : base(typeof(CatchRuleset))
|
public TestCaseCatchStacker()
|
||||||
|
: base(typeof(CatchRuleset))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Beatmap CreateBeatmap()
|
protected override Beatmap CreateBeatmap()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap();
|
var beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo = new BeatmapInfo
|
||||||
|
{
|
||||||
|
BaseDifficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
CircleSize = 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 512; i++)
|
||||||
beatmap.HitObjects.Add(new Fruit { X = 0.5f, StartTime = i * 100, NewCombo = i % 8 == 0 });
|
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
|
||||||
|
|
||||||
return beatmap;
|
return beatmap;
|
||||||
}
|
}
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
using OpenTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Tests
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
[Ignore("getting CI working")]
|
|
||||||
internal class TestCaseCatcher : OsuTestCase
|
|
||||||
{
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
|
||||||
{
|
|
||||||
typeof(Catcher),
|
|
||||||
};
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(RulesetStore rulesets)
|
|
||||||
{
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new CatchInputManager(rulesets.GetRuleset(2))
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Child = new Catcher
|
|
||||||
{
|
|
||||||
RelativePositionAxes = Axes.Both,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Size = new Vector2(1, 0.2f),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
50
osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs
Normal file
50
osu.Game.Rulesets.Catch/Tests/TestCaseCatcherArea.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
[Ignore("getting CI working")]
|
||||||
|
internal class TestCaseCatcherArea : OsuTestCase
|
||||||
|
{
|
||||||
|
private RulesetInfo catchRuleset;
|
||||||
|
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(CatcherArea),
|
||||||
|
};
|
||||||
|
|
||||||
|
public TestCaseCatcherArea()
|
||||||
|
{
|
||||||
|
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCatcher(float size)
|
||||||
|
{
|
||||||
|
Child = new CatchInputManager(catchRuleset)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = new CatcherArea(new BeatmapDifficulty { CircleSize = size })
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.BottomLeft
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(RulesetStore rulesets)
|
||||||
|
{
|
||||||
|
catchRuleset = rulesets.GetRuleset(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs
Normal file
16
osu.Game.Rulesets.Catch/Tests/TestCasePerformancePoints.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
[Ignore("getting CI working")]
|
||||||
|
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||||
|
{
|
||||||
|
public TestCasePerformancePoints()
|
||||||
|
: base(new CatchRuleset(new RulesetInfo()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
using osu.Game.Rulesets.Catch.Objects.Drawable;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -20,10 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
private readonly Container<Drawable> content;
|
private readonly Container<Drawable> content;
|
||||||
|
|
||||||
private readonly Container catcherContainer;
|
private readonly CatcherArea catcherArea;
|
||||||
private readonly Catcher catcher;
|
|
||||||
|
|
||||||
public CatchPlayfield()
|
public CatchPlayfield(BeatmapDifficulty difficulty)
|
||||||
: base(Axes.Y)
|
: base(Axes.Y)
|
||||||
{
|
{
|
||||||
Container explodingFruitContainer;
|
Container explodingFruitContainer;
|
||||||
@ -43,30 +42,16 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
catcherContainer = new Container
|
catcherArea = new CatcherArea(difficulty)
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.TopLeft,
|
|
||||||
Height = 180,
|
|
||||||
Child = catcher = new Catcher
|
|
||||||
{
|
{
|
||||||
ExplodingFruitTarget = explodingFruitContainer,
|
ExplodingFruitTarget = explodingFruitContainer,
|
||||||
RelativePositionAxes = Axes.Both,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopLeft,
|
||||||
X = 0.5f,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
public bool CheckIfWeCanCatch(CatchHitObject obj) => catcherArea.CanCatch(obj);
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
catcher.Size = new Vector2(catcherContainer.DrawSize.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2;
|
|
||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
public override void Add(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
@ -88,7 +73,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
(judgedObject.Parent as Container<DrawableHitObject>)?.Remove(judgedObject);
|
(judgedObject.Parent as Container<DrawableHitObject>)?.Remove(judgedObject);
|
||||||
(judgedObject.Parent as Container)?.Remove(judgedObject);
|
(judgedObject.Parent as Container)?.Remove(judgedObject);
|
||||||
|
|
||||||
catcher.Add(judgedObject, screenPosition);
|
catcherArea.Add(judgedObject, screenPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchBaseHit>
|
public class CatchRulesetContainer : ScrollingRulesetContainer<CatchPlayfield, CatchHitObject>
|
||||||
{
|
{
|
||||||
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
public CatchRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||||
@ -22,15 +22,15 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
|
||||||
|
|
||||||
protected override BeatmapProcessor<CatchBaseHit> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
|
protected override BeatmapProcessor<CatchHitObject> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
|
||||||
|
|
||||||
protected override BeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
|
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter() => new CatchBeatmapConverter();
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new CatchPlayfield();
|
protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty);
|
||||||
|
|
||||||
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
public override PassThroughInputManager CreateInputManager() => new CatchInputManager(Ruleset.RulesetInfo);
|
||||||
|
|
||||||
protected override DrawableHitObject<CatchBaseHit> GetVisualRepresentation(CatchBaseHit h)
|
protected override DrawableHitObject<CatchHitObject> GetVisualRepresentation(CatchHitObject h)
|
||||||
{
|
{
|
||||||
var fruit = h as Fruit;
|
var fruit = h as Fruit;
|
||||||
if (fruit != null)
|
if (fruit != null)
|
||||||
|
@ -1,193 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Input.Bindings;
|
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using OpenTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
|
||||||
{
|
|
||||||
public class Catcher : Container, IKeyBindingHandler<CatchAction>
|
|
||||||
{
|
|
||||||
private Texture texture;
|
|
||||||
|
|
||||||
private Container<DrawableHitObject> caughtFruit;
|
|
||||||
|
|
||||||
public Container ExplodingFruitTarget;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(TextureStore textures)
|
|
||||||
{
|
|
||||||
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
createCatcherSprite(),
|
|
||||||
caughtFruit = new Container<DrawableHitObject>
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private int currentDirection;
|
|
||||||
|
|
||||||
private bool dashing;
|
|
||||||
|
|
||||||
protected bool Dashing
|
|
||||||
{
|
|
||||||
get { return dashing; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == dashing) return;
|
|
||||||
|
|
||||||
dashing = value;
|
|
||||||
|
|
||||||
if (dashing)
|
|
||||||
Schedule(addAdditiveSprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAdditiveSprite()
|
|
||||||
{
|
|
||||||
if (!dashing) return;
|
|
||||||
|
|
||||||
var additive = createCatcherSprite();
|
|
||||||
|
|
||||||
additive.RelativePositionAxes = Axes.Both;
|
|
||||||
additive.Blending = BlendingMode.Additive;
|
|
||||||
additive.Position = Position;
|
|
||||||
additive.Scale = Scale;
|
|
||||||
|
|
||||||
((Container)Parent).Add(additive);
|
|
||||||
|
|
||||||
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire();
|
|
||||||
|
|
||||||
Scheduler.AddDelayed(addAdditiveSprite, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Sprite createCatcherSprite() => new Sprite
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
FillMode = FillMode.Fit,
|
|
||||||
Texture = texture,
|
|
||||||
OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly.
|
|
||||||
};
|
|
||||||
|
|
||||||
public bool OnPressed(CatchAction action)
|
|
||||||
{
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case CatchAction.MoveLeft:
|
|
||||||
currentDirection--;
|
|
||||||
return true;
|
|
||||||
case CatchAction.MoveRight:
|
|
||||||
currentDirection++;
|
|
||||||
return true;
|
|
||||||
case CatchAction.Dash:
|
|
||||||
Dashing = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnReleased(CatchAction action)
|
|
||||||
{
|
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
case CatchAction.MoveLeft:
|
|
||||||
currentDirection++;
|
|
||||||
return true;
|
|
||||||
case CatchAction.MoveRight:
|
|
||||||
currentDirection--;
|
|
||||||
return true;
|
|
||||||
case CatchAction.Dash:
|
|
||||||
Dashing = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable.
|
|
||||||
/// </summary>
|
|
||||||
private const double base_speed = 1.0 / 512;
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
if (currentDirection == 0) return;
|
|
||||||
|
|
||||||
double dashModifier = Dashing ? 1 : 0.5;
|
|
||||||
|
|
||||||
Scale = new Vector2(Math.Sign(currentDirection), 1);
|
|
||||||
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(DrawableHitObject fruit, Vector2 absolutePosition)
|
|
||||||
{
|
|
||||||
fruit.RelativePositionAxes = Axes.None;
|
|
||||||
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
|
|
||||||
|
|
||||||
fruit.Anchor = Anchor.TopCentre;
|
|
||||||
fruit.Origin = Anchor.BottomCentre;
|
|
||||||
fruit.Scale *= 0.7f;
|
|
||||||
fruit.LifetimeEnd = double.MaxValue;
|
|
||||||
|
|
||||||
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
|
|
||||||
|
|
||||||
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
|
|
||||||
{
|
|
||||||
fruit.X += RNG.Next(-5, 5);
|
|
||||||
fruit.Y -= RNG.Next(0, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
caughtFruit.Add(fruit);
|
|
||||||
|
|
||||||
if (((CatchBaseHit)fruit.HitObject).LastInCombo)
|
|
||||||
explode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void explode()
|
|
||||||
{
|
|
||||||
var fruit = caughtFruit.ToArray();
|
|
||||||
|
|
||||||
foreach (var f in fruit)
|
|
||||||
{
|
|
||||||
var originalX = f.X * Scale.X;
|
|
||||||
|
|
||||||
if (ExplodingFruitTarget != null)
|
|
||||||
{
|
|
||||||
f.Anchor = Anchor.TopLeft;
|
|
||||||
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
|
|
||||||
|
|
||||||
caughtFruit.Remove(f);
|
|
||||||
|
|
||||||
ExplodingFruitTarget.Add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
|
|
||||||
.Then()
|
|
||||||
.MoveToY(f.Y + 50, 500, Easing.InSine);
|
|
||||||
|
|
||||||
f.MoveToX(f.X + originalX * 6, 1000);
|
|
||||||
f.FadeOut(750);
|
|
||||||
|
|
||||||
f.Expire();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
240
osu.Game.Rulesets.Catch/UI/CatcherArea.cs
Normal file
240
osu.Game.Rulesets.Catch/UI/CatcherArea.cs
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
|
{
|
||||||
|
public class CatcherArea : Container
|
||||||
|
{
|
||||||
|
public const float CATCHER_SIZE = 172;
|
||||||
|
|
||||||
|
private readonly Catcher catcher;
|
||||||
|
|
||||||
|
public Container ExplodingFruitTarget
|
||||||
|
{
|
||||||
|
set { catcher.ExplodingFruitTarget = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public CatcherArea(BeatmapDifficulty difficulty = null)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = CATCHER_SIZE;
|
||||||
|
Child = catcher = new Catcher(difficulty)
|
||||||
|
{
|
||||||
|
AdditiveTarget = this,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(DrawableHitObject fruit, Vector2 absolutePosition)
|
||||||
|
{
|
||||||
|
fruit.RelativePositionAxes = Axes.None;
|
||||||
|
fruit.Position = new Vector2(catcher.ToLocalSpace(absolutePosition).X - catcher.DrawSize.X / 2, 0);
|
||||||
|
|
||||||
|
fruit.Anchor = Anchor.TopCentre;
|
||||||
|
fruit.Origin = Anchor.BottomCentre;
|
||||||
|
fruit.Scale *= 0.7f;
|
||||||
|
fruit.LifetimeEnd = double.MaxValue;
|
||||||
|
|
||||||
|
catcher.Add(fruit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanCatch(CatchHitObject obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X * Math.Abs(catcher.Scale.X) / DrawSize.X / 2;
|
||||||
|
|
||||||
|
public class Catcher : Container, IKeyBindingHandler<CatchAction>
|
||||||
|
{
|
||||||
|
private Texture texture;
|
||||||
|
|
||||||
|
private Container<DrawableHitObject> caughtFruit;
|
||||||
|
|
||||||
|
public Container ExplodingFruitTarget;
|
||||||
|
|
||||||
|
public Container AdditiveTarget;
|
||||||
|
|
||||||
|
public Catcher(BeatmapDifficulty difficulty = null)
|
||||||
|
{
|
||||||
|
RelativePositionAxes = Axes.X;
|
||||||
|
X = 0.5f;
|
||||||
|
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
|
Anchor = Anchor.TopLeft;
|
||||||
|
|
||||||
|
Size = new Vector2(CATCHER_SIZE);
|
||||||
|
if (difficulty != null)
|
||||||
|
Scale = new Vector2(1.0f - 0.7f * (difficulty.CircleSize - 5) / 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(TextureStore textures)
|
||||||
|
{
|
||||||
|
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
createCatcherSprite(),
|
||||||
|
caughtFruit = new Container<DrawableHitObject>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int currentDirection;
|
||||||
|
|
||||||
|
private bool dashing;
|
||||||
|
|
||||||
|
protected bool Dashing
|
||||||
|
{
|
||||||
|
get { return dashing; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == dashing) return;
|
||||||
|
|
||||||
|
dashing = value;
|
||||||
|
|
||||||
|
if (dashing)
|
||||||
|
Schedule(addAdditiveSprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAdditiveSprite()
|
||||||
|
{
|
||||||
|
if (!dashing || AdditiveTarget == null) return;
|
||||||
|
|
||||||
|
var additive = createCatcherSprite();
|
||||||
|
|
||||||
|
additive.Anchor = Anchor;
|
||||||
|
additive.OriginPosition = additive.OriginPosition + new Vector2(DrawWidth / 2, 0); // also temporary to align sprite correctly.
|
||||||
|
additive.Position = Position;
|
||||||
|
additive.Scale = Scale;
|
||||||
|
additive.RelativePositionAxes = RelativePositionAxes;
|
||||||
|
additive.Blending = BlendingMode.Additive;
|
||||||
|
|
||||||
|
AdditiveTarget.Add(additive);
|
||||||
|
|
||||||
|
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire();
|
||||||
|
|
||||||
|
Scheduler.AddDelayed(addAdditiveSprite, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Sprite createCatcherSprite() => new Sprite
|
||||||
|
{
|
||||||
|
Size = new Vector2(CATCHER_SIZE),
|
||||||
|
FillMode = FillMode.Fill,
|
||||||
|
Texture = texture,
|
||||||
|
OriginPosition = new Vector2(-3, 10) // temporary until the sprite is aligned correctly.
|
||||||
|
};
|
||||||
|
|
||||||
|
public void Add(DrawableHitObject fruit)
|
||||||
|
{
|
||||||
|
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
|
||||||
|
|
||||||
|
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
|
||||||
|
{
|
||||||
|
fruit.X += RNG.Next(-5, 5);
|
||||||
|
fruit.Y -= RNG.Next(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
caughtFruit.Add(fruit);
|
||||||
|
|
||||||
|
if (((CatchHitObject)fruit.HitObject).LastInCombo)
|
||||||
|
explode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(CatchAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case CatchAction.MoveLeft:
|
||||||
|
currentDirection--;
|
||||||
|
return true;
|
||||||
|
case CatchAction.MoveRight:
|
||||||
|
currentDirection++;
|
||||||
|
return true;
|
||||||
|
case CatchAction.Dash:
|
||||||
|
Dashing = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(CatchAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case CatchAction.MoveLeft:
|
||||||
|
currentDirection++;
|
||||||
|
return true;
|
||||||
|
case CatchAction.MoveRight:
|
||||||
|
currentDirection--;
|
||||||
|
return true;
|
||||||
|
case CatchAction.Dash:
|
||||||
|
Dashing = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable.
|
||||||
|
/// </summary>
|
||||||
|
public const double BASE_SPEED = 1.0 / 512;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (currentDirection == 0) return;
|
||||||
|
|
||||||
|
double dashModifier = Dashing ? 1 : 0.5;
|
||||||
|
|
||||||
|
Scale = new Vector2(Math.Abs(Scale.X) * Math.Sign(currentDirection), Scale.Y);
|
||||||
|
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * BASE_SPEED * dashModifier, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void explode()
|
||||||
|
{
|
||||||
|
var fruit = caughtFruit.ToArray();
|
||||||
|
|
||||||
|
foreach (var f in fruit)
|
||||||
|
{
|
||||||
|
var originalX = f.X * Scale.X;
|
||||||
|
|
||||||
|
if (ExplodingFruitTarget != null)
|
||||||
|
{
|
||||||
|
f.Anchor = Anchor.TopLeft;
|
||||||
|
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
|
||||||
|
|
||||||
|
caughtFruit.Remove(f);
|
||||||
|
|
||||||
|
ExplodingFruitTarget.Add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
|
||||||
|
.Then()
|
||||||
|
.MoveToY(f.Y + 50, 500, Easing.InSine);
|
||||||
|
|
||||||
|
f.MoveToX(f.X + originalX * 6, 1000);
|
||||||
|
f.FadeOut(750);
|
||||||
|
|
||||||
|
f.Expire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -138,8 +138,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
Pattern newPattern = conversion.Generate();
|
Pattern newPattern = conversion.Generate();
|
||||||
lastPattern = newPattern;
|
lastPattern = newPattern;
|
||||||
|
|
||||||
var stairPatternGenerator = (HitObjectPatternGenerator)conversion;
|
var stairPatternGenerator = conversion as HitObjectPatternGenerator;
|
||||||
lastStair = stairPatternGenerator.StairType;
|
lastStair = stairPatternGenerator?.StairType ?? lastStair;
|
||||||
|
|
||||||
return newPattern.HitObjects;
|
return newPattern.HitObjects;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, string> categoryDifficulty = null) => 0;
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize)));
|
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter(Beatmap beatmap) => new ManiaBeatmapConverter(true, (int)Math.Max(1, Math.Round(beatmap.BeatmapInfo.BaseDifficulty.CircleSize)));
|
||||||
}
|
}
|
||||||
|
@ -176,22 +176,10 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
|
|
||||||
public class ManiaModAutoplay : ModAutoplay<ManiaHitObject>
|
public class ManiaModAutoplay : ModAutoplay<ManiaHitObject>
|
||||||
{
|
{
|
||||||
private int availableColumns;
|
|
||||||
|
|
||||||
public override void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
|
||||||
{
|
|
||||||
// Todo: This shouldn't be done, we should be getting a ManiaBeatmap which should store AvailableColumns
|
|
||||||
// But this is dependent on a _lot_ of refactoring
|
|
||||||
var maniaRulesetContainer = (ManiaRulesetContainer)rulesetContainer;
|
|
||||||
availableColumns = maniaRulesetContainer.AvailableColumns;
|
|
||||||
|
|
||||||
base.ApplyToRulesetContainer(rulesetContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap) => new Score
|
protected override Score CreateReplayScore(Beatmap<ManiaHitObject> beatmap) => new Score
|
||||||
{
|
{
|
||||||
User = new User { Username = "osu!topus!" },
|
User = new User { Username = "osu!topus!" },
|
||||||
Replay = new ManiaAutoGenerator(beatmap, availableColumns).Generate(),
|
Replay = new ManiaAutoGenerator(beatmap).Generate(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
@ -13,15 +13,11 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
{
|
{
|
||||||
internal class ManiaAutoGenerator : AutoGenerator<ManiaHitObject>
|
internal class ManiaAutoGenerator : AutoGenerator<ManiaHitObject>
|
||||||
{
|
{
|
||||||
private const double release_delay = 20;
|
public const double RELEASE_DELAY = 20;
|
||||||
|
|
||||||
private readonly int availableColumns;
|
public ManiaAutoGenerator(Beatmap<ManiaHitObject> beatmap)
|
||||||
|
|
||||||
public ManiaAutoGenerator(Beatmap<ManiaHitObject> beatmap, int availableColumns)
|
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
this.availableColumns = availableColumns;
|
|
||||||
|
|
||||||
Replay = new Replay { User = new User { Username = @"Autoplay" } };
|
Replay = new Replay { User = new User { Username = @"Autoplay" } };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,104 +26,52 @@ namespace osu.Game.Rulesets.Mania.Replays
|
|||||||
public override Replay Generate()
|
public override Replay Generate()
|
||||||
{
|
{
|
||||||
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
|
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
|
||||||
Replay.Frames.Add(new ReplayFrame(-100000, null, null, ReplayButtonState.None));
|
Replay.Frames.Add(new ManiaReplayFrame(-100000, 0));
|
||||||
|
|
||||||
double[] holdEndTimes = new double[availableColumns];
|
var pointGroups = generateActionPoints().GroupBy(a => a.Time).OrderBy(g => g.First().Time);
|
||||||
for (int i = 0; i < availableColumns; i++)
|
|
||||||
holdEndTimes[i] = double.NegativeInfinity;
|
|
||||||
|
|
||||||
// Notes are handled row-by-row
|
|
||||||
foreach (var objGroup in Beatmap.HitObjects.GroupBy(h => h.StartTime))
|
|
||||||
{
|
|
||||||
double groupTime = objGroup.Key;
|
|
||||||
|
|
||||||
int activeColumns = 0;
|
int activeColumns = 0;
|
||||||
|
foreach (var group in pointGroups)
|
||||||
// Get the previously held-down active columns
|
|
||||||
for (int i = 0; i < availableColumns; i++)
|
|
||||||
{
|
{
|
||||||
if (holdEndTimes[i] > groupTime)
|
foreach (var point in group)
|
||||||
activeColumns |= 1 << i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add on the group columns, keeping track of the held notes for the next rows
|
|
||||||
foreach (var obj in objGroup)
|
|
||||||
{
|
{
|
||||||
var holdNote = obj as HoldNote;
|
if (point is HitPoint)
|
||||||
if (holdNote != null)
|
activeColumns |= 1 << point.Column;
|
||||||
holdEndTimes[obj.Column] = Math.Max(holdEndTimes[obj.Column], holdNote.EndTime);
|
if (point is ReleasePoint)
|
||||||
|
activeColumns ^= 1 << point.Column;
|
||||||
activeColumns |= 1 << obj.Column;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Replay.Frames.Add(new ReplayFrame(groupTime, activeColumns, null, ReplayButtonState.None));
|
Replay.Frames.Add(new ManiaReplayFrame(group.First().Time, activeColumns));
|
||||||
|
|
||||||
// Add the release frames. We can't do this with the loop above because we need activeColumns to be fully populated
|
|
||||||
foreach (var obj in objGroup.GroupBy(h => (h as IHasEndTime)?.EndTime ?? h.StartTime + release_delay).OrderBy(h => h.Key))
|
|
||||||
{
|
|
||||||
var groupEndTime = obj.Key;
|
|
||||||
|
|
||||||
int activeColumnsAtEnd = 0;
|
|
||||||
for (int i = 0; i < availableColumns; i++)
|
|
||||||
{
|
|
||||||
if (holdEndTimes[i] > groupEndTime)
|
|
||||||
activeColumnsAtEnd |= 1 << i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Replay.Frames.Add(new ReplayFrame(groupEndTime, activeColumnsAtEnd, 0, ReplayButtonState.None));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Replay.Frames = Replay.Frames
|
|
||||||
// Pick the maximum activeColumns for all frames at the same time
|
|
||||||
.GroupBy(f => f.Time)
|
|
||||||
.Select(g => new ReplayFrame(g.First().Time, maxMouseX(g), 0, ReplayButtonState.None))
|
|
||||||
// The addition of release frames above maybe result in unordered frames, but we need them ordered
|
|
||||||
.OrderBy(f => f.Time)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return Replay;
|
return Replay;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private IEnumerable<IActionPoint> generateActionPoints()
|
||||||
/// Finds the maximum <see cref="ReplayFrame.MouseX"/> by count of bits from a grouping of <see cref="ReplayFrame"/>s.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="group">The <see cref="ReplayFrame"/> grouping to search.</param>
|
|
||||||
/// <returns>The maximum <see cref="ReplayFrame.MouseX"/> by count of bits.</returns>
|
|
||||||
private float maxMouseX(IGrouping<double, ReplayFrame> group)
|
|
||||||
{
|
{
|
||||||
int currentCount = -1;
|
foreach (var obj in Beatmap.HitObjects)
|
||||||
int currentMax = 0;
|
|
||||||
|
|
||||||
foreach (var val in group)
|
|
||||||
{
|
{
|
||||||
int newCount = countBits((int)(val.MouseX ?? 0));
|
yield return new HitPoint { Time = obj.StartTime, Column = obj.Column };
|
||||||
if (newCount > currentCount)
|
yield return new ReleasePoint { Time = ((obj as IHasEndTime)?.EndTime ?? obj.StartTime) + RELEASE_DELAY, Column = obj.Column };
|
||||||
{
|
|
||||||
currentCount = newCount;
|
|
||||||
currentMax = (int)(val.MouseX ?? 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentMax;
|
private interface IActionPoint
|
||||||
|
{
|
||||||
|
double Time { get; set; }
|
||||||
|
int Column { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private struct HitPoint : IActionPoint
|
||||||
/// Counts the number of bits set in a value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value to count.</param>
|
|
||||||
/// <returns>The number of set bits.</returns>
|
|
||||||
private int countBits(int value)
|
|
||||||
{
|
{
|
||||||
int count = 0;
|
public double Time { get; set; }
|
||||||
while (value > 0)
|
public int Column { get; set; }
|
||||||
{
|
|
||||||
if ((value & 1) > 0)
|
|
||||||
count++;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
private struct ReleasePoint : IActionPoint
|
||||||
|
{
|
||||||
|
public double Time { get; set; }
|
||||||
|
public int Column { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,37 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Replays
|
namespace osu.Game.Rulesets.Mania.Replays
|
||||||
{
|
{
|
||||||
internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler
|
internal class ManiaFramedReplayInputHandler : FramedReplayInputHandler
|
||||||
{
|
{
|
||||||
public ManiaFramedReplayInputHandler(Replay replay)
|
private readonly ManiaRulesetContainer container;
|
||||||
|
|
||||||
|
public ManiaFramedReplayInputHandler(Replay replay, ManiaRulesetContainer container)
|
||||||
: base(replay)
|
: base(replay)
|
||||||
{
|
{
|
||||||
|
this.container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ManiaPlayfield playfield;
|
||||||
public override List<InputState> GetPendingStates()
|
public override List<InputState> GetPendingStates()
|
||||||
{
|
{
|
||||||
var actions = new List<ManiaAction>();
|
var actions = new List<ManiaAction>();
|
||||||
|
|
||||||
int activeColumns = (int)(CurrentFrame.MouseX ?? 0);
|
if (playfield == null)
|
||||||
|
playfield = (ManiaPlayfield)container.Playfield;
|
||||||
|
|
||||||
|
int activeColumns = (int)(CurrentFrame.MouseX ?? 0);
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
while (activeColumns > 0)
|
while (activeColumns > 0)
|
||||||
{
|
{
|
||||||
if ((activeColumns & 1) > 0)
|
if ((activeColumns & 1) > 0)
|
||||||
actions.Add(ManiaAction.Key1 + counter);
|
actions.Add(playfield.Columns.ElementAt(counter).Action);
|
||||||
counter++;
|
counter++;
|
||||||
activeColumns >>= 1;
|
activeColumns >>= 1;
|
||||||
}
|
}
|
||||||
|
17
osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
Normal file
17
osu.Game.Rulesets.Mania/Replays/ManiaReplayFrame.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Replays
|
||||||
|
{
|
||||||
|
public class ManiaReplayFrame : ReplayFrame
|
||||||
|
{
|
||||||
|
public override bool IsImportant => MouseX > 0;
|
||||||
|
|
||||||
|
public ManiaReplayFrame(double time, int activeColumns)
|
||||||
|
: base(time, activeColumns, null, ReplayButtonState.None)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs
Normal file
173
osu.Game.Rulesets.Mania/Tests/TestCaseAutoGeneration.cs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
|
{
|
||||||
|
[Ignore("getting CI working")]
|
||||||
|
public class TestCaseAutoGeneration : OsuTestCase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestSingleNote()
|
||||||
|
{
|
||||||
|
// | |
|
||||||
|
// | - |
|
||||||
|
// | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 1000 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||||
|
Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||||
|
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 0 has not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 0 has not been released");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleHoldNote()
|
||||||
|
{
|
||||||
|
// | |
|
||||||
|
// | * |
|
||||||
|
// | * |
|
||||||
|
// | * |
|
||||||
|
// | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||||
|
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||||
|
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 0 has not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 0 has not been released");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleNoteChord()
|
||||||
|
{
|
||||||
|
// | | |
|
||||||
|
// | - | - |
|
||||||
|
// | | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 1000 });
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||||
|
Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||||
|
Assert.AreEqual(3, generated.Frames[1].MouseX, "Keys 1 and 2 have not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[2].MouseX, "Keys 1 and 2 have not been released");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHoldNoteChord()
|
||||||
|
{
|
||||||
|
// | | |
|
||||||
|
// | * | * |
|
||||||
|
// | * | * |
|
||||||
|
// | * | * |
|
||||||
|
// | | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 3, "Replay must have 3 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect hit time");
|
||||||
|
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect release time");
|
||||||
|
Assert.AreEqual(3, generated.Frames[1].MouseX, "Keys 1 and 2 have not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[2].MouseX, "Keys 1 and 2 have not been released");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleNoteStair()
|
||||||
|
{
|
||||||
|
// | | |
|
||||||
|
// | | - |
|
||||||
|
// | - | |
|
||||||
|
// | | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 1000 });
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time");
|
||||||
|
Assert.AreEqual(1000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[2].Time, "Incorrect first note release time");
|
||||||
|
Assert.AreEqual(2000, generated.Frames[3].Time, "Incorrect second note hit time");
|
||||||
|
Assert.AreEqual(2000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time");
|
||||||
|
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[2].MouseX, "Key 1 has not been released");
|
||||||
|
Assert.AreEqual(2, generated.Frames[3].MouseX, "Key 2 has not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[4].MouseX, "Key 2 has not been released");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHoldNoteStair()
|
||||||
|
{
|
||||||
|
// | | |
|
||||||
|
// | | * |
|
||||||
|
// | * | * |
|
||||||
|
// | * | * |
|
||||||
|
// | * | |
|
||||||
|
// | | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 5, "Replay must have 5 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time");
|
||||||
|
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect first note release time");
|
||||||
|
Assert.AreEqual(2000, generated.Frames[2].Time, "Incorrect second note hit time");
|
||||||
|
Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[4].Time, "Incorrect second note release time");
|
||||||
|
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed");
|
||||||
|
Assert.AreEqual(3, generated.Frames[2].MouseX, "Keys 1 and 2 have not been pressed");
|
||||||
|
Assert.AreEqual(2, generated.Frames[3].MouseX, "Key 1 has not been released");
|
||||||
|
Assert.AreEqual(0, generated.Frames[4].MouseX, "Key 2 has not been released");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHoldNoteWithReleasePress()
|
||||||
|
{
|
||||||
|
// | | |
|
||||||
|
// | * | - |
|
||||||
|
// | * | |
|
||||||
|
// | * | |
|
||||||
|
// | | |
|
||||||
|
|
||||||
|
var beatmap = new Beatmap<ManiaHitObject>();
|
||||||
|
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 - ManiaAutoGenerator.RELEASE_DELAY });
|
||||||
|
beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 });
|
||||||
|
|
||||||
|
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||||
|
|
||||||
|
Assert.IsTrue(generated.Frames.Count == 4, "Replay must have 4 frames");
|
||||||
|
Assert.AreEqual(1000, generated.Frames[1].Time, "Incorrect first note hit time");
|
||||||
|
Assert.AreEqual(3000, generated.Frames[2].Time, "Incorrect second note press time + first note release time");
|
||||||
|
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[3].Time, "Incorrect second note release time");
|
||||||
|
Assert.AreEqual(1, generated.Frames[1].MouseX, "Key 1 has not been pressed");
|
||||||
|
Assert.AreEqual(2, generated.Frames[2].MouseX, "Key 1 has not been released or key 2 has not been pressed");
|
||||||
|
Assert.AreEqual(0, generated.Frames[3].MouseX, "Keys 1 and 2 have not been released");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
private const double start_time = 500;
|
private const double start_time = 500;
|
||||||
private const double duration = 500;
|
private const double duration = 500;
|
||||||
|
|
||||||
public override string Description => @"Mania playfield";
|
|
||||||
|
|
||||||
protected override double TimePerAction => 200;
|
protected override double TimePerAction => 200;
|
||||||
|
|
||||||
private RulesetInfo maniaRuleset;
|
private RulesetInfo maniaRuleset;
|
||||||
|
16
osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs
Normal file
16
osu.Game.Rulesets.Mania/Tests/TestCasePerformancePoints.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
|
{
|
||||||
|
[Ignore("getting CI working")]
|
||||||
|
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||||
|
{
|
||||||
|
public TestCasePerformancePoints()
|
||||||
|
: base(new ManiaRuleset(new RulesetInfo()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -124,6 +124,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic);
|
protected override SpeedAdjustmentContainer CreateSpeedAdjustmentContainer(MultiplierControlPoint controlPoint) => new ManiaSpeedAdjustmentContainer(controlPoint, ScrollingAlgorithm.Basic);
|
||||||
|
|
||||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay);
|
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,18 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
set { Curve.Distance = value; }
|
set { Curve.Distance = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The position of the cursor at the point of completion of this <see cref="Slider"/> if it was hit
|
||||||
|
/// with as few movements as possible. This is set and used by difficulty calculation.
|
||||||
|
/// </summary>
|
||||||
|
internal Vector2? LazyEndPosition;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The distance travelled by the cursor upon completion of this <see cref="Slider"/> if it was hit
|
||||||
|
/// with as few movements as possible. This is set and used by difficulty calculation.
|
||||||
|
/// </summary>
|
||||||
|
internal float LazyTravelDistance;
|
||||||
|
|
||||||
public List<SampleInfoList> RepeatSamples { get; set; } = new List<SampleInfoList>();
|
public List<SampleInfoList> RepeatSamples { get; set; } = new List<SampleInfoList>();
|
||||||
public int RepeatCount { get; set; } = 1;
|
public int RepeatCount { get; set; } = 1;
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
|||||||
(h as Slider)?.Curve?.Calculate();
|
(h as Slider)?.Curve?.Calculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, string> categoryDifficulty = null)
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
{
|
{
|
||||||
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects);
|
OsuDifficultyBeatmap beatmap = new OsuDifficultyBeatmap(Beatmap.HitObjects, TimeRate);
|
||||||
Skill[] skills =
|
Skill[] skills =
|
||||||
{
|
{
|
||||||
new Aim(),
|
new Aim(),
|
||||||
@ -67,8 +67,8 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty
|
|||||||
|
|
||||||
if (categoryDifficulty != null)
|
if (categoryDifficulty != null)
|
||||||
{
|
{
|
||||||
categoryDifficulty.Add("Aim", aimRating.ToString("0.00"));
|
categoryDifficulty.Add("Aim", aimRating);
|
||||||
categoryDifficulty.Add("Speed", speedRating.ToString("0.00"));
|
categoryDifficulty.Add("Speed", speedRating);
|
||||||
}
|
}
|
||||||
|
|
||||||
return starRating;
|
return starRating;
|
||||||
|
@ -20,12 +20,12 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
/// Creates an enumerator, which preprocesses a list of <see cref="OsuHitObject"/>s recieved as input, wrapping them as
|
/// Creates an enumerator, which preprocesses a list of <see cref="OsuHitObject"/>s recieved as input, wrapping them as
|
||||||
/// <see cref="OsuDifficultyHitObject"/> which contains extra data required for difficulty calculation.
|
/// <see cref="OsuDifficultyHitObject"/> which contains extra data required for difficulty calculation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public OsuDifficultyBeatmap(List<OsuHitObject> objects)
|
public OsuDifficultyBeatmap(List<OsuHitObject> objects, double timeRate)
|
||||||
{
|
{
|
||||||
// Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
|
// Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases.
|
||||||
// This should probably happen before the objects reach the difficulty calculator.
|
// This should probably happen before the objects reach the difficulty calculator.
|
||||||
objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
|
objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime));
|
||||||
difficultyObjects = createDifficultyObjectEnumerator(objects);
|
difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
private IEnumerator<OsuDifficultyHitObject> createDifficultyObjectEnumerator(List<OsuHitObject> objects)
|
private IEnumerator<OsuDifficultyHitObject> createDifficultyObjectEnumerator(List<OsuHitObject> objects, double timeRate)
|
||||||
{
|
{
|
||||||
// We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object.
|
// We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object.
|
||||||
OsuHitObject[] triangle = new OsuHitObject[3];
|
OsuHitObject[] triangle = new OsuHitObject[3];
|
||||||
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
triangle[1] = triangle[0];
|
triangle[1] = triangle[0];
|
||||||
triangle[0] = objects[i];
|
triangle[0] = objects[i];
|
||||||
|
|
||||||
yield return new OsuDifficultyHitObject(triangle);
|
yield return new OsuDifficultyHitObject(triangle, timeRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
||||||
@ -33,13 +35,17 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
|
|
||||||
private const int normalized_radius = 52;
|
private const int normalized_radius = 52;
|
||||||
|
|
||||||
|
private readonly double timeRate;
|
||||||
|
|
||||||
private readonly OsuHitObject[] t;
|
private readonly OsuHitObject[] t;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the object calculating extra data required for difficulty calculation.
|
/// Initializes the object calculating extra data required for difficulty calculation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public OsuDifficultyHitObject(OsuHitObject[] triangle)
|
public OsuDifficultyHitObject(OsuHitObject[] triangle, double timeRate)
|
||||||
{
|
{
|
||||||
|
this.timeRate = timeRate;
|
||||||
|
|
||||||
t = triangle;
|
t = triangle;
|
||||||
BaseObject = t[0];
|
BaseObject = t[0];
|
||||||
setDistances();
|
setDistances();
|
||||||
@ -57,14 +63,53 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing
|
|||||||
scalingFactor *= 1 + smallCircleBonus;
|
scalingFactor *= 1 + smallCircleBonus;
|
||||||
}
|
}
|
||||||
|
|
||||||
Distance = (t[0].StackedPosition - t[1].StackedPosition).Length * scalingFactor;
|
Vector2 lastCursorPosition = t[1].StackedPosition;
|
||||||
|
float lastTravelDistance = 0;
|
||||||
|
|
||||||
|
var lastSlider = t[1] as Slider;
|
||||||
|
if (lastSlider != null)
|
||||||
|
{
|
||||||
|
computeSliderCursorPosition(lastSlider);
|
||||||
|
lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition;
|
||||||
|
lastTravelDistance = lastSlider.LazyTravelDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Distance = (lastTravelDistance + (BaseObject.StackedPosition - lastCursorPosition).Length) * scalingFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTimingValues()
|
private void setTimingValues()
|
||||||
{
|
{
|
||||||
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
// Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure.
|
||||||
DeltaTime = Math.Max(40, t[0].StartTime - t[1].StartTime);
|
DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate);
|
||||||
TimeUntilHit = 450; // BaseObject.PreEmpt;
|
TimeUntilHit = 450; // BaseObject.PreEmpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void computeSliderCursorPosition(Slider slider)
|
||||||
|
{
|
||||||
|
if (slider.LazyEndPosition != null)
|
||||||
|
return;
|
||||||
|
slider.LazyEndPosition = slider.StackedPosition;
|
||||||
|
|
||||||
|
float approxFollowCircleRadius = (float)(slider.Radius * 3);
|
||||||
|
var computeVertex = new Action<double>(t =>
|
||||||
|
{
|
||||||
|
var diff = slider.PositionAt(t) - slider.LazyEndPosition.Value;
|
||||||
|
float dist = diff.Length;
|
||||||
|
|
||||||
|
if (dist > approxFollowCircleRadius)
|
||||||
|
{
|
||||||
|
// The cursor would be outside the follow circle, we need to move it
|
||||||
|
diff.Normalize(); // Obtain direction of diff
|
||||||
|
dist -= approxFollowCircleRadius;
|
||||||
|
slider.LazyEndPosition += diff * dist;
|
||||||
|
slider.LazyTravelDistance += dist;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var scoringTimes = slider.Ticks.Select(t => t.StartTime).Concat(slider.RepeatPoints.Select(r => r.StartTime)).OrderBy(t => t);
|
||||||
|
foreach (var time in scoringTimes)
|
||||||
|
computeVertex(time);
|
||||||
|
computeVertex(slider.EndTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ using System.Linq;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
{
|
{
|
||||||
@ -114,6 +116,8 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods);
|
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new OsuDifficultyCalculator(beatmap, mods);
|
||||||
|
|
||||||
|
public override PerformanceCalculator CreatePerformanceCalculator(Beatmap beatmap, Score score) => new OsuPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
public override string Description => "osu!";
|
public override string Description => "osu!";
|
||||||
|
|
||||||
public override SettingsSubsection CreateSettings() => new OsuSettings();
|
public override SettingsSubsection CreateSettings() => new OsuSettings();
|
||||||
|
199
osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs
Normal file
199
osu.Game.Rulesets.Osu/Scoring/OsuPerformanceCalculator.cs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
|
{
|
||||||
|
public class OsuPerformanceCalculator : PerformanceCalculator<OsuHitObject>
|
||||||
|
{
|
||||||
|
private readonly int countHitCircles;
|
||||||
|
private readonly int beatmapMaxCombo;
|
||||||
|
|
||||||
|
private Mod[] mods;
|
||||||
|
private double realApproachRate;
|
||||||
|
private double accuracy;
|
||||||
|
private int scoreMaxCombo;
|
||||||
|
private int count300;
|
||||||
|
private int count100;
|
||||||
|
private int count50;
|
||||||
|
private int countMiss;
|
||||||
|
|
||||||
|
public OsuPerformanceCalculator(Ruleset ruleset, Beatmap beatmap, Score score)
|
||||||
|
: base(ruleset, beatmap, score)
|
||||||
|
{
|
||||||
|
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
|
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
||||||
|
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.RepeatCount + s.Ticks.Count());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
||||||
|
{
|
||||||
|
mods = Score.Mods;
|
||||||
|
accuracy = Score.Accuracy;
|
||||||
|
scoreMaxCombo = Score.MaxCombo;
|
||||||
|
count300 = Convert.ToInt32(Score.Statistics["300"]);
|
||||||
|
count100 = Convert.ToInt32(Score.Statistics["100"]);
|
||||||
|
count50 = Convert.ToInt32(Score.Statistics["50"]);
|
||||||
|
countMiss = Convert.ToInt32(Score.Statistics["x"]);
|
||||||
|
|
||||||
|
// Don't count scores made with supposedly unranked mods
|
||||||
|
if (mods.Any(m => !m.Ranked))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Todo: In the future we should apply changes to PreEmpt/AR at an OsuHitObject/BaseDifficulty level, but this is done
|
||||||
|
// locally for now as doing so would modify animations and other things unexpectedly
|
||||||
|
// DO NOT MODIFY THIS
|
||||||
|
double ar = Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate;
|
||||||
|
if (mods.Any(m => m is OsuModHardRock))
|
||||||
|
ar = Math.Min(10, ar * 1.4);
|
||||||
|
if (mods.Any(m => m is OsuModEasy))
|
||||||
|
ar = Math.Max(0, ar / 2);
|
||||||
|
double preEmpt = BeatmapDifficulty.DifficultyRange(ar, 1800, 1200, 450);
|
||||||
|
realApproachRate = preEmpt > 1200 ? (1800 - preEmpt) / 120 : (1200 - preEmpt) / 150 + 5;
|
||||||
|
|
||||||
|
// Custom multipliers for NoFail and SpunOut.
|
||||||
|
double multiplier = 1.12f; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
|
||||||
|
|
||||||
|
if (mods.Any(m => m is OsuModNoFail))
|
||||||
|
multiplier *= 0.90f;
|
||||||
|
|
||||||
|
if (mods.Any(m => m is OsuModSpunOut))
|
||||||
|
multiplier *= 0.95f;
|
||||||
|
|
||||||
|
double aimValue = computeAimValue();
|
||||||
|
double speedValue = computeSpeedValue();
|
||||||
|
double accuracyValue = computeAccuracyValue();
|
||||||
|
double totalValue =
|
||||||
|
Math.Pow(
|
||||||
|
Math.Pow(aimValue, 1.1f) +
|
||||||
|
Math.Pow(speedValue, 1.1f) +
|
||||||
|
Math.Pow(accuracyValue, 1.1f), 1.0f / 1.1f
|
||||||
|
) * multiplier;
|
||||||
|
|
||||||
|
if (categoryRatings != null)
|
||||||
|
{
|
||||||
|
categoryRatings.Add("Aim", aimValue);
|
||||||
|
categoryRatings.Add("Speed", speedValue);
|
||||||
|
categoryRatings.Add("Accuracy", accuracyValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeAimValue()
|
||||||
|
{
|
||||||
|
double aimValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Aim"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
|
||||||
|
|
||||||
|
// Longer maps are worth more
|
||||||
|
double lengthBonus = 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
|
||||||
|
(totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f);
|
||||||
|
|
||||||
|
aimValue *= lengthBonus;
|
||||||
|
|
||||||
|
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||||
|
aimValue *= Math.Pow(0.97f, countMiss);
|
||||||
|
|
||||||
|
// Combo scaling
|
||||||
|
if (beatmapMaxCombo > 0)
|
||||||
|
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
||||||
|
|
||||||
|
double approachRateFactor = 1.0f;
|
||||||
|
if (realApproachRate > 10.33f)
|
||||||
|
approachRateFactor += 0.45f * (realApproachRate - 10.33f);
|
||||||
|
else if (realApproachRate < 8.0f)
|
||||||
|
{
|
||||||
|
// HD is worth more with lower ar!
|
||||||
|
if (mods.Any(h => h is OsuModHidden))
|
||||||
|
approachRateFactor += 0.02f * (8.0f - realApproachRate);
|
||||||
|
else
|
||||||
|
approachRateFactor += 0.01f * (8.0f - realApproachRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
aimValue *= approachRateFactor;
|
||||||
|
|
||||||
|
if (mods.Any(h => h is OsuModHidden))
|
||||||
|
aimValue *= 1.18f;
|
||||||
|
|
||||||
|
if (mods.Any(h => h is OsuModFlashlight))
|
||||||
|
{
|
||||||
|
// Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
|
||||||
|
aimValue *= 1.45f * lengthBonus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale the aim value with accuracy _slightly_
|
||||||
|
aimValue *= 0.5f + accuracy / 2.0f;
|
||||||
|
// It is important to also consider accuracy difficulty when doing that
|
||||||
|
aimValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
|
||||||
|
|
||||||
|
return aimValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeSpeedValue()
|
||||||
|
{
|
||||||
|
double speedValue = Math.Pow(5.0f * Math.Max(1.0f, Attributes["Speed"] / 0.0675f) - 4.0f, 3.0f) / 100000.0f;
|
||||||
|
|
||||||
|
// Longer maps are worth more
|
||||||
|
speedValue *= 0.95f + 0.4f * Math.Min(1.0f, totalHits / 2000.0f) +
|
||||||
|
(totalHits > 2000 ? Math.Log10(totalHits / 2000.0f) * 0.5f : 0.0f);
|
||||||
|
|
||||||
|
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||||
|
speedValue *= Math.Pow(0.97f, countMiss);
|
||||||
|
|
||||||
|
// Combo scaling
|
||||||
|
if (beatmapMaxCombo > 0)
|
||||||
|
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
||||||
|
|
||||||
|
// Scale the speed value with accuracy _slightly_
|
||||||
|
speedValue *= 0.5f + accuracy / 2.0f;
|
||||||
|
// It is important to also consider accuracy difficulty when doing that
|
||||||
|
speedValue *= 0.98f + Math.Pow(Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty, 2) / 2500;
|
||||||
|
|
||||||
|
return speedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeAccuracyValue()
|
||||||
|
{
|
||||||
|
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
||||||
|
double betterAccuracyPercentage;
|
||||||
|
int amountHitObjectsWithAccuracy = countHitCircles;
|
||||||
|
|
||||||
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
|
betterAccuracyPercentage = ((count300 - (totalHits - amountHitObjectsWithAccuracy)) * 6 + count100 * 2 + count50) / (amountHitObjectsWithAccuracy * 6);
|
||||||
|
else
|
||||||
|
betterAccuracyPercentage = 0;
|
||||||
|
|
||||||
|
// It is possible to reach a negative accuracy with this formula. Cap it at zero - zero points
|
||||||
|
if (betterAccuracyPercentage < 0)
|
||||||
|
betterAccuracyPercentage = 0;
|
||||||
|
|
||||||
|
// Lots of arbitrary values from testing.
|
||||||
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||||
|
double accuracyValue = Math.Pow(1.52163f, Beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83f;
|
||||||
|
|
||||||
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||||
|
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
||||||
|
|
||||||
|
if (mods.Any(m => m is OsuModHidden))
|
||||||
|
accuracyValue *= 1.02f;
|
||||||
|
if (mods.Any(m => m is OsuModFlashlight))
|
||||||
|
accuracyValue *= 1.02f;
|
||||||
|
|
||||||
|
return accuracyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double totalHits => count300 + count100 + count50 + countMiss;
|
||||||
|
private double totalSuccessfulHits => count300 + count100 + count50;
|
||||||
|
|
||||||
|
protected override BeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
|
||||||
|
}
|
||||||
|
}
|
16
osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs
Normal file
16
osu.Game.Rulesets.Osu/Tests/TestCasePerformancePoints.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
[Ignore("getting CI working")]
|
||||||
|
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||||
|
{
|
||||||
|
public TestCasePerformancePoints()
|
||||||
|
: base(new OsuRuleset(new RulesetInfo()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko
|
namespace osu.Game.Rulesets.Taiko
|
||||||
@ -36,7 +35,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, string> categoryDifficulty = null)
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
{
|
{
|
||||||
// Fill our custom DifficultyHitObject class, that carries additional information
|
// Fill our custom DifficultyHitObject class, that carries additional information
|
||||||
difficultyHitObjects.Clear();
|
difficultyHitObjects.Clear();
|
||||||
@ -53,8 +52,8 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
if (categoryDifficulty != null)
|
if (categoryDifficulty != null)
|
||||||
{
|
{
|
||||||
categoryDifficulty.Add("Strain", starRating.ToString("0.00", CultureInfo.InvariantCulture));
|
categoryDifficulty.Add("Strain", starRating);
|
||||||
categoryDifficulty.Add("Hit window 300", (35 /*HitObjectManager.HitWindow300*/ / TimeRate).ToString("0.00", CultureInfo.InvariantCulture));
|
categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return starRating;
|
return starRating;
|
||||||
|
16
osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs
Normal file
16
osu.Game.Rulesets.Taiko/Tests/TestCasePerformancePoints.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests
|
||||||
|
{
|
||||||
|
[Ignore("getting CI working")]
|
||||||
|
public class TestCasePerformancePoints : Game.Tests.Visual.TestCasePerformancePoints
|
||||||
|
{
|
||||||
|
public TestCasePerformancePoints()
|
||||||
|
: base(new TaikoRuleset(new RulesetInfo()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,8 +30,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
private const double default_duration = 1000;
|
private const double default_duration = 1000;
|
||||||
private const float scroll_time = 1000;
|
private const float scroll_time = 1000;
|
||||||
|
|
||||||
public override string Description => "Taiko playfield";
|
|
||||||
|
|
||||||
protected override double TimePerAction => default_duration * 2;
|
protected override double TimePerAction => default_duration * 2;
|
||||||
|
|
||||||
private readonly Random rng = new Random(1337);
|
private readonly Random rng = new Random(1337);
|
||||||
|
@ -5,6 +5,5 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public class TestCaseAllPlayers : TestCasePlayer
|
public class TestCaseAllPlayers : TestCasePlayer
|
||||||
{
|
{
|
||||||
public override string Description => @"Showing everything to play the game.";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseBeatSyncedContainer : OsuTestCase
|
internal class TestCaseBeatSyncedContainer : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests beat synced containers.";
|
|
||||||
|
|
||||||
private readonly MusicController mc;
|
private readonly MusicController mc;
|
||||||
|
|
||||||
public TestCaseBeatSyncedContainer()
|
public TestCaseBeatSyncedContainer()
|
||||||
|
@ -9,10 +9,9 @@ using OpenTK;
|
|||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
|
[System.ComponentModel.Description("PlaySongSelect leaderboard/details area")]
|
||||||
internal class TestCaseBeatmapDetailArea : OsuTestCase
|
internal class TestCaseBeatmapDetailArea : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Beatmap details in song select";
|
|
||||||
|
|
||||||
public TestCaseBeatmapDetailArea()
|
public TestCaseBeatmapDetailArea()
|
||||||
{
|
{
|
||||||
Add(new BeatmapDetailArea
|
Add(new BeatmapDetailArea
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -8,10 +9,9 @@ using osu.Game.Screens.Select;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("PlaySongSelect beatmap details")]
|
||||||
internal class TestCaseBeatmapDetails : OsuTestCase
|
internal class TestCaseBeatmapDetails : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "BeatmapDetails tab of BeatmapDetailArea";
|
|
||||||
|
|
||||||
public TestCaseBeatmapDetails()
|
public TestCaseBeatmapDetails()
|
||||||
{
|
{
|
||||||
BeatmapDetails details;
|
BeatmapDetails details;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Screens.Select.Options;
|
using osu.Game.Screens.Select.Options;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -8,10 +9,9 @@ using OpenTK.Input;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("bottom beatmap details")]
|
||||||
internal class TestCaseBeatmapOptionsOverlay : OsuTestCase
|
internal class TestCaseBeatmapOptionsOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Beatmap options in song select";
|
|
||||||
|
|
||||||
public TestCaseBeatmapOptionsOverlay()
|
public TestCaseBeatmapOptionsOverlay()
|
||||||
{
|
{
|
||||||
var overlay = new BeatmapOptionsOverlay();
|
var overlay = new BeatmapOptionsOverlay();
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -14,13 +13,13 @@ using osu.Game.Rulesets.Osu.Mods;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[System.ComponentModel.Description("in BeatmapOverlay")]
|
||||||
public class TestCaseBeatmapScoresContainer : OsuTestCase
|
public class TestCaseBeatmapScoresContainer : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "BeatmapOverlay scores container";
|
|
||||||
|
|
||||||
private readonly IEnumerable<OnlineScore> scores;
|
private readonly IEnumerable<OnlineScore> scores;
|
||||||
private readonly IEnumerable<OnlineScore> anotherScores;
|
private readonly IEnumerable<OnlineScore> anotherScores;
|
||||||
private readonly OnlineScore topScore;
|
private readonly OnlineScore topScore;
|
||||||
|
@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseBeatmapSetOverlay : OsuTestCase
|
internal class TestCaseBeatmapSetOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"view online beatmap sets";
|
|
||||||
|
|
||||||
private readonly BeatmapSetOverlay overlay;
|
private readonly BeatmapSetOverlay overlay;
|
||||||
|
|
||||||
public TestCaseBeatmapSetOverlay()
|
public TestCaseBeatmapSetOverlay()
|
||||||
|
@ -8,8 +8,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseBreadcrumbs : OsuTestCase
|
internal class TestCaseBreadcrumbs : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"breadcrumb > control";
|
|
||||||
|
|
||||||
public TestCaseBreadcrumbs()
|
public TestCaseBreadcrumbs()
|
||||||
{
|
{
|
||||||
BreadcrumbControl<BreadcrumbTab> c;
|
BreadcrumbControl<BreadcrumbTab> c;
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseBreakOverlay : OsuTestCase
|
internal class TestCaseBreakOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests breaks behavior";
|
|
||||||
|
|
||||||
private readonly BreakOverlay breakOverlay;
|
private readonly BreakOverlay breakOverlay;
|
||||||
|
|
||||||
public TestCaseBreakOverlay()
|
public TestCaseBreakOverlay()
|
||||||
|
33
osu.Game.Tests/Visual/TestCaseButtonSystem.cs
Normal file
33
osu.Game.Tests/Visual/TestCaseButtonSystem.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
internal class TestCaseButtonSystem : OsuTestCase
|
||||||
|
{
|
||||||
|
public TestCaseButtonSystem()
|
||||||
|
{
|
||||||
|
OsuLogo logo;
|
||||||
|
ButtonSystem buttons;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
buttons = new ButtonSystem(),
|
||||||
|
logo = new OsuLogo()
|
||||||
|
};
|
||||||
|
|
||||||
|
buttons.SetOsuLogo(logo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,15 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("Testing chat api and overlay")]
|
||||||
internal class TestCaseChatDisplay : OsuTestCase
|
internal class TestCaseChatDisplay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Testing chat api and overlay";
|
|
||||||
|
|
||||||
public TestCaseChatDisplay()
|
public TestCaseChatDisplay()
|
||||||
{
|
{
|
||||||
Add(new ChatOverlay
|
Add(new ChatOverlay
|
||||||
|
@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseContextMenu : OsuTestCase
|
internal class TestCaseContextMenu : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Menu visible on right click";
|
|
||||||
|
|
||||||
private const int start_time = 0;
|
private const int start_time = 0;
|
||||||
private const int duration = 1000;
|
private const int duration = 1000;
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseDialogOverlay : OsuTestCase
|
internal class TestCaseDialogOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Display dialogs";
|
|
||||||
|
|
||||||
public TestCaseDialogOverlay()
|
public TestCaseDialogOverlay()
|
||||||
{
|
{
|
||||||
DialogOverlay overlay;
|
DialogOverlay overlay;
|
||||||
|
@ -11,8 +11,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public class TestCaseDirect : OsuTestCase
|
public class TestCaseDirect : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"osu!direct overlay";
|
|
||||||
|
|
||||||
private DirectOverlay direct;
|
private DirectOverlay direct;
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
|
@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseDrawableRoom : OsuTestCase
|
internal class TestCaseDrawableRoom : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Select your favourite room";
|
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -2,15 +2,15 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Game.Screens.Tournament;
|
using osu.Game.Screens.Tournament;
|
||||||
using osu.Game.Screens.Tournament.Teams;
|
using osu.Game.Screens.Tournament.Teams;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("for tournament use")]
|
||||||
internal class TestCaseDrawings : OsuTestCase
|
internal class TestCaseDrawings : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "Tournament drawings";
|
|
||||||
|
|
||||||
public TestCaseDrawings()
|
public TestCaseDrawings()
|
||||||
{
|
{
|
||||||
Add(new Drawings
|
Add(new Drawings
|
||||||
|
@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseGamefield : OsuTestCase
|
internal class TestCaseGamefield : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Showing hitobjects and what not.";
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseGraph : OsuTestCase
|
internal class TestCaseGraph : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "graph";
|
|
||||||
|
|
||||||
public TestCaseGraph()
|
public TestCaseGraph()
|
||||||
{
|
{
|
||||||
BarGraph graph;
|
BarGraph graph;
|
||||||
|
@ -14,8 +14,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public class TestCaseIconButton : OsuTestCase
|
public class TestCaseIconButton : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "Various display modes of icon buttons";
|
|
||||||
|
|
||||||
public TestCaseIconButton()
|
public TestCaseIconButton()
|
||||||
{
|
{
|
||||||
Child = new FillFlowContainer
|
Child = new FillFlowContainer
|
||||||
|
@ -9,8 +9,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
private readonly KeyBindingOverlay overlay;
|
private readonly KeyBindingOverlay overlay;
|
||||||
|
|
||||||
public override string Description => @"Key configuration";
|
|
||||||
|
|
||||||
public TestCaseKeyConfiguration()
|
public TestCaseKeyConfiguration()
|
||||||
{
|
{
|
||||||
Child = overlay = new KeyBindingOverlay();
|
Child = overlay = new KeyBindingOverlay();
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseKeyCounter : OsuTestCase
|
internal class TestCaseKeyCounter : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests key counter";
|
|
||||||
|
|
||||||
public TestCaseKeyCounter()
|
public TestCaseKeyCounter()
|
||||||
{
|
{
|
||||||
KeyCounterCollection kc = new KeyCounterCollection
|
KeyCounterCollection kc = new KeyCounterCollection
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Select.Leaderboards;
|
using osu.Game.Screens.Select.Leaderboards;
|
||||||
@ -9,10 +10,9 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("PlaySongSelect leaderboard")]
|
||||||
internal class TestCaseLeaderboard : OsuTestCase
|
internal class TestCaseLeaderboard : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"From song select";
|
|
||||||
|
|
||||||
private readonly Leaderboard leaderboard;
|
private readonly Leaderboard leaderboard;
|
||||||
|
|
||||||
private void newScores()
|
private void newScores()
|
||||||
|
@ -11,8 +11,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseMedalOverlay : OsuTestCase
|
internal class TestCaseMedalOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"medal get!";
|
|
||||||
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
typeof(MedalOverlay),
|
typeof(MedalOverlay),
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using osu.Framework.Graphics.Colour;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Screens.Menu;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
|
||||||
{
|
|
||||||
internal class TestCaseMenuButtonSystem : OsuTestCase
|
|
||||||
{
|
|
||||||
public override string Description => @"Main menu button system";
|
|
||||||
|
|
||||||
public TestCaseMenuButtonSystem()
|
|
||||||
{
|
|
||||||
Add(new Box
|
|
||||||
{
|
|
||||||
Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
|
|
||||||
RelativeSizeAxes = Framework.Graphics.Axes.Both,
|
|
||||||
});
|
|
||||||
Add(new ButtonSystem());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +1,16 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("player pause/fail screens")]
|
||||||
internal class TestCaseMenuOverlays : OsuTestCase
|
internal class TestCaseMenuOverlays : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests pause and fail overlays";
|
|
||||||
|
|
||||||
public TestCaseMenuOverlays()
|
public TestCaseMenuOverlays()
|
||||||
{
|
{
|
||||||
FailOverlay failOverlay;
|
FailOverlay failOverlay;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
@ -10,10 +11,9 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("mod select and icon display")]
|
||||||
internal class TestCaseMods : OsuTestCase
|
internal class TestCaseMods : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Mod select overlay and in-game display";
|
|
||||||
|
|
||||||
private ModSelectOverlay modSelect;
|
private ModSelectOverlay modSelect;
|
||||||
private ModDisplay modDisplay;
|
private ModDisplay modDisplay;
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseMusicController : OsuTestCase
|
internal class TestCaseMusicController : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests music controller ui.";
|
|
||||||
|
|
||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
public TestCaseMusicController()
|
public TestCaseMusicController()
|
||||||
|
@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
internal class TestCaseNotificationOverlay : OsuTestCase
|
internal class TestCaseNotificationOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"I handle notifications";
|
|
||||||
|
|
||||||
private readonly NotificationOverlay manager;
|
private readonly NotificationOverlay manager;
|
||||||
|
|
||||||
public TestCaseNotificationOverlay()
|
public TestCaseNotificationOverlay()
|
||||||
|
@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
private FrameworkConfigManager config;
|
private FrameworkConfigManager config;
|
||||||
private Bindable<FrameSync> frameSyncMode;
|
private Bindable<FrameSync> frameSyncMode;
|
||||||
|
|
||||||
public override string Description => @"Make it easier to see setting changes";
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -22,8 +22,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
private BeatmapManager manager;
|
private BeatmapManager manager;
|
||||||
|
|
||||||
public override string Description => @"with fake data";
|
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseReplay : TestCasePlayer
|
internal class TestCaseReplay : TestCasePlayer
|
||||||
{
|
{
|
||||||
public override string Description => @"Testing replay playback.";
|
|
||||||
|
|
||||||
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
||||||
{
|
{
|
||||||
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseReplaySettingsOverlay : OsuTestCase
|
internal class TestCaseReplaySettingsOverlay : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Settings visible in replay/auto";
|
|
||||||
|
|
||||||
public TestCaseReplaySettingsOverlay()
|
public TestCaseReplaySettingsOverlay()
|
||||||
{
|
{
|
||||||
ExampleContainer container;
|
ExampleContainer container;
|
||||||
@ -24,7 +22,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
Add(container = new ExampleContainer());
|
Add(container = new ExampleContainer());
|
||||||
|
|
||||||
AddStep(@"Add button", () => container.Add(new OsuButton
|
AddStep(@"Add button", () => container.Add(new TriangleButton
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Text = @"Button",
|
Text = @"Button",
|
||||||
|
@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
private BeatmapManager beatmaps;
|
private BeatmapManager beatmaps;
|
||||||
|
|
||||||
public override string Description => @"Results after playing.";
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(BeatmapManager beatmaps)
|
private void load(BeatmapManager beatmaps)
|
||||||
{
|
{
|
||||||
|
@ -13,8 +13,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseRoomInspector : OsuTestCase
|
internal class TestCaseRoomInspector : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"from the multiplayer lobby";
|
|
||||||
|
|
||||||
private RulesetStore rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseScoreCounter : OsuTestCase
|
internal class TestCaseScoreCounter : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests multiple counters";
|
|
||||||
|
|
||||||
public TestCaseScoreCounter()
|
public TestCaseScoreCounter()
|
||||||
{
|
{
|
||||||
int numerator = 0, denominator = 0;
|
int numerator = 0, denominator = 0;
|
||||||
|
@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseSettings : OsuTestCase
|
internal class TestCaseSettings : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests the settings overlay";
|
|
||||||
|
|
||||||
private readonly SettingsOverlay settings;
|
private readonly SettingsOverlay settings;
|
||||||
|
|
||||||
public TestCaseSettings()
|
public TestCaseSettings()
|
||||||
|
@ -7,8 +7,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseSkipButton : OsuTestCase
|
internal class TestCaseSkipButton : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Skip skip skippediskip";
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -8,8 +8,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
public class TestCaseSocial : OsuTestCase
|
public class TestCaseSocial : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"social browser overlay";
|
|
||||||
|
|
||||||
public TestCaseSocial()
|
public TestCaseSocial()
|
||||||
{
|
{
|
||||||
SocialOverlay s = new SocialOverlay
|
SocialOverlay s = new SocialOverlay
|
||||||
|
@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseSongProgress : OsuTestCase
|
internal class TestCaseSongProgress : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"With fake data";
|
|
||||||
|
|
||||||
private readonly SongProgress progress;
|
private readonly SongProgress progress;
|
||||||
private readonly SongProgressGraph graph;
|
private readonly SongProgressGraph graph;
|
||||||
|
|
||||||
|
@ -16,8 +16,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseStoryboard : OsuTestCase
|
internal class TestCaseStoryboard : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests storyboards.";
|
|
||||||
|
|
||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
private readonly Container<DrawableStoryboard> storyboardContainer;
|
private readonly Container<DrawableStoryboard> storyboardContainer;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -9,10 +10,9 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("SongSelect filter control")]
|
||||||
public class TestCaseTabControl : OsuTestCase
|
public class TestCaseTabControl : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Filter for song select";
|
|
||||||
|
|
||||||
public TestCaseTabControl()
|
public TestCaseTabControl()
|
||||||
{
|
{
|
||||||
OsuSpriteText text;
|
OsuSpriteText text;
|
||||||
|
@ -12,8 +12,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseTextAwesome : OsuTestCase
|
internal class TestCaseTextAwesome : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Tests display of icons";
|
|
||||||
|
|
||||||
public TestCaseTextAwesome()
|
public TestCaseTextAwesome()
|
||||||
{
|
{
|
||||||
FillFlowContainer flow;
|
FillFlowContainer flow;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("mostly back button")]
|
||||||
internal class TestCaseTwoLayerButton : OsuTestCase
|
internal class TestCaseTwoLayerButton : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Mostly back button";
|
|
||||||
|
|
||||||
public TestCaseTwoLayerButton()
|
public TestCaseTwoLayerButton()
|
||||||
{
|
{
|
||||||
Add(new BackButton());
|
Add(new BackButton());
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseUserPanel : OsuTestCase
|
internal class TestCaseUserPanel : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"Panels for displaying a user's status";
|
|
||||||
|
|
||||||
public TestCaseUserPanel()
|
public TestCaseUserPanel()
|
||||||
{
|
{
|
||||||
UserPanel flyte;
|
UserPanel flyte;
|
||||||
|
@ -10,8 +10,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseUserProfile : OsuTestCase
|
internal class TestCaseUserProfile : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "Tests user's profile page.";
|
|
||||||
|
|
||||||
public TestCaseUserProfile()
|
public TestCaseUserProfile()
|
||||||
{
|
{
|
||||||
var profile = new UserProfileOverlay();
|
var profile = new UserProfileOverlay();
|
||||||
|
@ -15,8 +15,6 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
internal class TestCaseUserRanks : OsuTestCase
|
internal class TestCaseUserRanks : OsuTestCase
|
||||||
{
|
{
|
||||||
public override string Description => "showing your latest achievements";
|
|
||||||
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableScore), typeof(RanksSection) };
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(DrawableScore), typeof(RanksSection) };
|
||||||
|
|
||||||
public TestCaseUserRanks()
|
public TestCaseUserRanks()
|
||||||
|
@ -80,6 +80,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs the conversion of a hit object.
|
/// Performs the conversion of a hit object.
|
||||||
|
/// This method is generally executed sequentially for all objects in a beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="original">The hit object to convert.</param>
|
/// <param name="original">The hit object to convert.</param>
|
||||||
/// <param name="beatmap">The un-converted Beatmap.</param>
|
/// <param name="beatmap">The un-converted Beatmap.</param>
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Beatmaps.IO;
|
using osu.Game.Beatmaps.IO;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
@ -52,6 +53,11 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<BeatmapInfo> BeatmapRestored;
|
public event Action<BeatmapInfo> BeatmapRestored;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a beatmap download begins.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadBegan;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -221,21 +227,29 @@ namespace osu.Game.Beatmaps
|
|||||||
/// Downloads a beatmap.
|
/// Downloads a beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmapSetInfo">The <see cref="BeatmapSetInfo"/> to be downloaded.</param>
|
/// <param name="beatmapSetInfo">The <see cref="BeatmapSetInfo"/> to be downloaded.</param>
|
||||||
/// <returns>A new <see cref="DownloadBeatmapSetRequest"/>, or an existing one if a download is already in progress.</returns>
|
/// <param name="noVideo">Whether the beatmap should be downloaded without video. Defaults to false.</param>
|
||||||
public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo)
|
public void Download(BeatmapSetInfo beatmapSetInfo, bool noVideo = false)
|
||||||
{
|
{
|
||||||
var existing = GetExistingDownload(beatmapSetInfo);
|
var existing = GetExistingDownload(beatmapSetInfo);
|
||||||
|
|
||||||
if (existing != null) return existing;
|
if (existing != null || api == null) return;
|
||||||
|
|
||||||
if (api == null) return null;
|
if (!api.LocalUser.Value.IsSupporter)
|
||||||
|
{
|
||||||
|
PostNotification?.Invoke(new SimpleNotification
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.fa_superpowers,
|
||||||
|
Text = "You gotta be a supporter to download for now 'yo"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ProgressNotification downloadNotification = new ProgressNotification
|
ProgressNotification downloadNotification = new ProgressNotification
|
||||||
{
|
{
|
||||||
Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
|
Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
|
||||||
};
|
};
|
||||||
|
|
||||||
var request = new DownloadBeatmapSetRequest(beatmapSetInfo);
|
var request = new DownloadBeatmapSetRequest(beatmapSetInfo, noVideo);
|
||||||
|
|
||||||
request.DownloadProgressed += progress =>
|
request.DownloadProgressed += progress =>
|
||||||
{
|
{
|
||||||
@ -280,8 +294,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
// don't run in the main api queue as this is a long-running task.
|
// don't run in the main api queue as this is a long-running task.
|
||||||
Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning);
|
Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning);
|
||||||
|
BeatmapDownloadBegan?.Invoke(request);
|
||||||
return request;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Beatmaps
|
|||||||
public class BeatmapMetrics
|
public class BeatmapMetrics
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total vote counts of user ratings on a scale of 0..length.
|
/// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<int> Ratings { get; set; }
|
public IEnumerable<int> Ratings { get; set; }
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
protected double TimeRate = 1;
|
protected double TimeRate = 1;
|
||||||
|
|
||||||
public abstract double Calculate(Dictionary<string, string> categoryDifficulty = null);
|
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class DifficultyCalculator<T> : DifficultyCalculator where T : HitObject
|
public abstract class DifficultyCalculator<T> : DifficultyCalculator where T : HitObject
|
||||||
|
@ -64,11 +64,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
||||||
}
|
}, 300),
|
||||||
)
|
|
||||||
{
|
|
||||||
TimeBeforeLoad = 300,
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
|
@ -3,12 +3,18 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
{
|
{
|
||||||
@ -22,6 +28,10 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
private readonly Container nestedContainer;
|
private readonly Container nestedContainer;
|
||||||
|
|
||||||
|
private readonly Container borderContainer;
|
||||||
|
|
||||||
|
private readonly Box hoverLayer;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => nestedContainer;
|
protected override Container<Drawable> Content => nestedContainer;
|
||||||
|
|
||||||
protected Panel()
|
protected Panel()
|
||||||
@ -29,20 +39,56 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
Height = MAX_HEIGHT;
|
Height = MAX_HEIGHT;
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
AddInternal(nestedContainer = new Container
|
AddInternal(borderContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 10,
|
CornerRadius = 10,
|
||||||
BorderColour = new Color4(221, 255, 255, 255),
|
BorderColour = new Color4(221, 255, 255, 255),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
nestedContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
hoverLayer = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
Blending = BlendingMode.Additive,
|
||||||
|
},
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SampleChannel sampleHover;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(AudioManager audio, OsuColour colours)
|
||||||
|
{
|
||||||
|
sampleHover = audio.Sample.Get($@"SongSelect/song-ping-variation-{RNG.Next(1, 5)}");
|
||||||
|
hoverLayer.Colour = colours.Blue.Opacity(0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(InputState state)
|
||||||
|
{
|
||||||
|
sampleHover?.Play();
|
||||||
|
|
||||||
|
hoverLayer.FadeIn(100, Easing.OutQuint);
|
||||||
|
return base.OnHover(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(InputState state)
|
||||||
|
{
|
||||||
|
hoverLayer.FadeOut(1000, Easing.OutQuint);
|
||||||
|
base.OnHoverLost(state);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetMultiplicativeAlpha(float alpha)
|
public void SetMultiplicativeAlpha(float alpha)
|
||||||
{
|
{
|
||||||
nestedContainer.Alpha = alpha;
|
borderContainer.Alpha = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -94,8 +140,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
protected virtual void Selected()
|
protected virtual void Selected()
|
||||||
{
|
{
|
||||||
nestedContainer.BorderThickness = 2.5f;
|
borderContainer.BorderThickness = 2.5f;
|
||||||
nestedContainer.EdgeEffect = new EdgeEffectParameters
|
borderContainer.EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = new Color4(130, 204, 255, 150),
|
Colour = new Color4(130, 204, 255, 150),
|
||||||
@ -106,8 +152,8 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
protected virtual void Deselected()
|
protected virtual void Deselected()
|
||||||
{
|
{
|
||||||
nestedContainer.BorderThickness = 0;
|
borderContainer.BorderThickness = 0;
|
||||||
nestedContainer.EdgeEffect = new EdgeEffectParameters
|
borderContainer.EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Shadow,
|
Type = EdgeEffectType.Shadow,
|
||||||
Offset = new Vector2(1),
|
Offset = new Vector2(1),
|
||||||
|
@ -16,12 +16,13 @@ namespace osu.Game.Configuration
|
|||||||
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
|
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
|
||||||
Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details);
|
Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details);
|
||||||
|
|
||||||
|
Set(OsuSetting.ShowConvertedBeatmaps, true);
|
||||||
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
||||||
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
|
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
|
||||||
|
|
||||||
Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
|
Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
|
||||||
|
|
||||||
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01);
|
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
|
||||||
|
|
||||||
// Online settings
|
// Online settings
|
||||||
Set(OsuSetting.Username, string.Empty);
|
Set(OsuSetting.Username, string.Empty);
|
||||||
@ -112,6 +113,7 @@ namespace osu.Game.Configuration
|
|||||||
SnakingOutSliders,
|
SnakingOutSliders,
|
||||||
ShowFpsDisplay,
|
ShowFpsDisplay,
|
||||||
ChatDisplayHeight,
|
ChatDisplayHeight,
|
||||||
Version
|
Version,
|
||||||
|
ShowConvertedBeatmaps
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
var id = obj.ID;
|
var id = obj.ID;
|
||||||
obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
||||||
|
context.Entry(obj).Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -2,34 +2,39 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
public class OsuClickableContainer : ClickableContainer
|
public class OsuClickableContainer : ClickableContainer
|
||||||
{
|
{
|
||||||
protected SampleChannel SampleClick, SampleHover;
|
private readonly HoverSampleSet sampleSet;
|
||||||
|
|
||||||
|
private readonly Container content = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
||||||
|
{
|
||||||
|
this.sampleSet = sampleSet;
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load()
|
||||||
{
|
{
|
||||||
SampleHover = audio.Sample.Get(@"UI/generic-hover");
|
if (AutoSizeAxes != Axes.None)
|
||||||
SampleClick = audio.Sample.Get(@"UI/generic-click");
|
{
|
||||||
|
content.RelativeSizeAxes = RelativeSizeAxes;
|
||||||
|
content.AutoSizeAxes = AutoSizeAxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
SampleHover?.Play();
|
content,
|
||||||
return base.OnHover(state);
|
new HoverClickSounds(sampleSet)
|
||||||
}
|
};
|
||||||
|
|
||||||
protected override bool OnClick(InputState state)
|
|
||||||
{
|
|
||||||
SampleClick?.Play();
|
|
||||||
return base.OnClick(state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio)
|
||||||
{
|
{
|
||||||
samplePopIn = audio.Sample.Get(@"UI/melodic-5");
|
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
|
||||||
samplePopOut = audio.Sample.Get(@"UI/melodic-4");
|
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
|
||||||
|
|
||||||
StateChanged += onStateChanged;
|
StateChanged += onStateChanged;
|
||||||
}
|
}
|
||||||
|
@ -57,19 +57,31 @@ namespace osu.Game.Graphics
|
|||||||
private void load(FontStore store)
|
private void load(FontStore store)
|
||||||
{
|
{
|
||||||
this.store = store;
|
this.store = store;
|
||||||
|
|
||||||
updateTexture();
|
updateTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
updateTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FontAwesome loadedIcon;
|
||||||
private void updateTexture()
|
private void updateTexture()
|
||||||
{
|
{
|
||||||
var texture = store?.Get(((char)icon).ToString());
|
var loadableIcon = icon;
|
||||||
|
|
||||||
|
if (loadableIcon == loadedIcon) return;
|
||||||
|
|
||||||
|
var texture = store?.Get(((char)loadableIcon).ToString());
|
||||||
|
|
||||||
spriteMain.Texture = texture;
|
spriteMain.Texture = texture;
|
||||||
spriteShadow.Texture = texture;
|
spriteShadow.Texture = texture;
|
||||||
|
|
||||||
if (Size == Vector2.Zero)
|
if (Size == Vector2.Zero)
|
||||||
Size = new Vector2(texture?.DisplayWidth ?? 0, texture?.DisplayHeight ?? 0);
|
Size = new Vector2(texture?.DisplayWidth ?? 0, texture?.DisplayHeight ?? 0);
|
||||||
|
|
||||||
|
loadedIcon = loadableIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user