mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 00:23:59 +09:00
Merge branch 'improve-hud-hiding' into cinema-mod
This commit is contained in:
@ -54,6 +54,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1210.1" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1212.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -2,23 +2,21 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Scoring
|
namespace osu.Game.Rulesets.Catch.Scoring
|
||||||
{
|
{
|
||||||
public class CatchScoreProcessor : ScoreProcessor<CatchHitObject>
|
public class CatchScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
public CatchScoreProcessor(DrawableRuleset<CatchHitObject> drawableRuleset)
|
public CatchScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private float hpDrainRate;
|
private float hpDrainRate;
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<CatchHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
TimeRange.Value = BeatmapDifficulty.DifficultyRange(beatmap.Beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(Beatmap);
|
||||||
|
|
||||||
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay);
|
||||||
|
|
||||||
|
@ -3,13 +3,11 @@
|
|||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Scoring
|
namespace osu.Game.Rulesets.Mania.Scoring
|
||||||
{
|
{
|
||||||
internal class ManiaScoreProcessor : ScoreProcessor<ManiaHitObject>
|
internal class ManiaScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hit HP multiplier at OD = 0.
|
/// The hit HP multiplier at OD = 0.
|
||||||
@ -51,12 +49,12 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double hpMultiplier = 1;
|
private double hpMultiplier = 1;
|
||||||
|
|
||||||
public ManiaScoreProcessor(DrawableRuleset<ManiaHitObject> drawableRuleset)
|
public ManiaScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<ManiaHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
@ -65,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SimulateAutoplay(Beatmap<ManiaHitObject> beatmap)
|
protected override void SimulateAutoplay(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
protected override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages);
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(Beatmap);
|
||||||
|
|
||||||
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
public override int Variant => (int)(Beatmap.Stages.Count == 1 ? PlayfieldType.Single : PlayfieldType.Dual) + Beatmap.TotalColumns;
|
||||||
|
|
||||||
|
@ -5,22 +5,20 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
{
|
{
|
||||||
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject>
|
internal class OsuScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
public OsuScoreProcessor(DrawableRuleset<OsuHitObject> drawableRuleset)
|
public OsuScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private float hpDrainRate;
|
private float hpDrainRate;
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<OsuHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // always show the gameplay cursor
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(Beatmap);
|
||||||
|
|
||||||
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
protected override Playfield CreatePlayfield() => new OsuPlayfield();
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Scoring
|
namespace osu.Game.Rulesets.Taiko.Scoring
|
||||||
{
|
{
|
||||||
internal class TaikoScoreProcessor : ScoreProcessor<TaikoHitObject>
|
internal class TaikoScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A value used for calculating <see cref="hpMultiplier"/>.
|
/// A value used for calculating <see cref="hpMultiplier"/>.
|
||||||
@ -31,16 +31,16 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double hpMissMultiplier;
|
private double hpMissMultiplier;
|
||||||
|
|
||||||
public TaikoScoreProcessor(DrawableRuleset<TaikoHitObject> drawableRuleset)
|
public TaikoScoreProcessor(IBeatmap beatmap)
|
||||||
: base(drawableRuleset)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap(Beatmap<TaikoHitObject> beatmap)
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
base.ApplyBeatmap(beatmap);
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.FindAll(o => o is Hit).Count * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
||||||
|
|
||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
new BarLineGenerator<BarLine>(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar.Major ? new DrawableBarLineMajor(bar) : new DrawableBarLine(bar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(Beatmap);
|
||||||
|
|
||||||
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer();
|
||||||
|
|
||||||
|
81
osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
Normal file
81
osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
|
{
|
||||||
|
public class TestSceneHUDOverlay : ManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
private HUDOverlay hudOverlay;
|
||||||
|
|
||||||
|
private Drawable hideTarget => hudOverlay.KeyCounter; // best way of checking hideTargets without exposing.
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestShownByDefault()
|
||||||
|
{
|
||||||
|
createNew();
|
||||||
|
|
||||||
|
AddAssert("showhud is set", () => hudOverlay.ShowHud.Value);
|
||||||
|
|
||||||
|
AddAssert("hidetarget is visible", () => hideTarget.IsPresent);
|
||||||
|
AddAssert("pause button is visible", () => hudOverlay.HoldToQuit.IsPresent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFadesInOnLoadComplete()
|
||||||
|
{
|
||||||
|
float? initialAlpha = null;
|
||||||
|
|
||||||
|
createNew(h => h.OnLoadComplete += _ => initialAlpha = hideTarget.Alpha);
|
||||||
|
AddUntilStep("wait for load", () => hudOverlay.IsAlive);
|
||||||
|
AddAssert("initial alpha was less than 1", () => initialAlpha != null && initialAlpha < 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHideExternally()
|
||||||
|
{
|
||||||
|
createNew();
|
||||||
|
|
||||||
|
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||||
|
|
||||||
|
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
|
||||||
|
AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestExternalHideDoesntAffectConfig()
|
||||||
|
{
|
||||||
|
bool originalConfigValue = false;
|
||||||
|
|
||||||
|
createNew();
|
||||||
|
|
||||||
|
AddStep("get original config value", () => originalConfigValue = config.Get<bool>(OsuSetting.ShowInterface));
|
||||||
|
|
||||||
|
AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
|
||||||
|
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
|
||||||
|
|
||||||
|
AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
|
||||||
|
AddAssert("config unchanged", () => originalConfigValue == config.Get<bool>(OsuSetting.ShowInterface));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createNew(Action<HUDOverlay> action = null)
|
||||||
|
{
|
||||||
|
AddStep("create overlay", () =>
|
||||||
|
{
|
||||||
|
Child = hudOverlay = new HUDOverlay(null, null, Array.Empty<Mod>());
|
||||||
|
|
||||||
|
action?.Invoke(hudOverlay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.IO.File;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
@ -112,7 +112,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
switch (pair.Key)
|
switch (pair.Key)
|
||||||
{
|
{
|
||||||
case @"AudioFilename":
|
case @"AudioFilename":
|
||||||
metadata.AudioFile = FileSafety.PathStandardise(pair.Value);
|
metadata.AudioFile = pair.Value.ToStandardisedPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"AudioLeadIn":
|
case @"AudioLeadIn":
|
||||||
@ -300,12 +300,12 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
case EventType.Background:
|
case EventType.Background:
|
||||||
string bgFilename = split[2].Trim('"');
|
string bgFilename = split[2].Trim('"');
|
||||||
beatmap.BeatmapInfo.Metadata.BackgroundFile = FileSafety.PathStandardise(bgFilename);
|
beatmap.BeatmapInfo.Metadata.BackgroundFile = bgFilename.ToStandardisedPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventType.Video:
|
case EventType.Video:
|
||||||
string videoFilename = split[2].Trim('"');
|
string videoFilename = split[2].Trim('"');
|
||||||
beatmap.BeatmapInfo.Metadata.VideoFile = FileSafety.PathStandardise(videoFilename);
|
beatmap.BeatmapInfo.Metadata.VideoFile = videoFilename.ToStandardisedPath();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EventType.Break:
|
case EventType.Break:
|
||||||
|
@ -8,8 +8,8 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.IO.File;
|
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.Storyboards;
|
using osu.Game.Storyboards;
|
||||||
|
|
||||||
@ -335,6 +335,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string cleanFilename(string path) => FileSafety.PathStandardise(path.Trim('"'));
|
private string cleanFilename(string path) => path.Trim('"').ToStandardisedPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using osu.Game.Rulesets.Mods;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Storyboards;
|
using osu.Game.Storyboards;
|
||||||
using osu.Framework.IO.File;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -83,7 +82,10 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <returns>The absolute path of the output file.</returns>
|
/// <returns>The absolute path of the output file.</returns>
|
||||||
public string Save()
|
public string Save()
|
||||||
{
|
{
|
||||||
var path = FileSafety.GetTempPath(Guid.NewGuid().ToString().Replace("-", string.Empty) + ".json");
|
string directory = Path.Combine(Path.GetTempPath(), @"osu!");
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
|
||||||
|
var path = Path.Combine(directory, Guid.NewGuid().ToString().Replace("-", string.Empty) + ".json");
|
||||||
using (var sw = new StreamWriter(path))
|
using (var sw = new StreamWriter(path))
|
||||||
sw.WriteLine(Beatmap.Serialize());
|
sw.WriteLine(Beatmap.Serialize());
|
||||||
return path;
|
return path;
|
||||||
|
@ -13,7 +13,6 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.IO.File;
|
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
@ -493,7 +492,7 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
fileInfos.Add(new TFileModel
|
fileInfos.Add(new TFileModel
|
||||||
{
|
{
|
||||||
Filename = FileSafety.PathStandardise(file.Substring(prefix.Length)),
|
Filename = file.Substring(prefix.Length).ToStandardisedPath(),
|
||||||
FileInfo = files.Add(s)
|
FileInfo = files.Add(s)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,15 @@ namespace osu.Game.Database
|
|||||||
lock (writeLock)
|
lock (writeLock)
|
||||||
{
|
{
|
||||||
recycleThreadContexts();
|
recycleThreadContexts();
|
||||||
storage.DeleteDatabase(database_name);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
storage.DeleteDatabase(database_name);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// for now we are not sure why file handles are kept open by EF, but this is generally only used in testing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,16 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
{
|
{
|
||||||
public abstract class ScoreProcessor
|
public class ScoreProcessor
|
||||||
{
|
{
|
||||||
|
private const double base_portion = 0.3;
|
||||||
|
private const double combo_portion = 0.7;
|
||||||
|
private const double max_score = 1000000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
|
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
|
||||||
/// This may occur regardless of whether an <see cref="AllJudged"/> event is invoked.
|
/// This may occur regardless of whether an <see cref="AllJudged"/> event is invoked.
|
||||||
@ -67,11 +70,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
public readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a <see cref="HitWindows"/> for this processor.
|
|
||||||
/// </summary>
|
|
||||||
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current rank.
|
/// The current rank.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -90,132 +88,23 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether all <see cref="Judgement"/>s have been processed.
|
/// Whether all <see cref="Judgement"/>s have been processed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasCompleted => false;
|
public bool HasCompleted => JudgedHits == MaxHits;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
|
||||||
/// </summary>
|
|
||||||
public int JudgedHits { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this ScoreProcessor has already triggered the failed state.
|
/// Whether this ScoreProcessor has already triggered the failed state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasFailed { get; private set; }
|
public bool HasFailed { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default conditions for failing.
|
/// The maximum number of hits that can be judged.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
|
|
||||||
|
|
||||||
protected ScoreProcessor()
|
|
||||||
{
|
|
||||||
Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
|
|
||||||
Accuracy.ValueChanged += delegate
|
|
||||||
{
|
|
||||||
Rank.Value = rankFrom(Accuracy.Value);
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
|
||||||
Rank.Value = mod.AdjustRank(Rank.Value, Accuracy.Value);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScoreRank rankFrom(double acc)
|
|
||||||
{
|
|
||||||
if (acc == 1)
|
|
||||||
return ScoreRank.X;
|
|
||||||
if (acc > 0.95)
|
|
||||||
return ScoreRank.S;
|
|
||||||
if (acc > 0.9)
|
|
||||||
return ScoreRank.A;
|
|
||||||
if (acc > 0.8)
|
|
||||||
return ScoreRank.B;
|
|
||||||
if (acc > 0.7)
|
|
||||||
return ScoreRank.C;
|
|
||||||
|
|
||||||
return ScoreRank.D;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets this ScoreProcessor to a default state.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
|
||||||
protected virtual void Reset(bool storeResults)
|
|
||||||
{
|
|
||||||
TotalScore.Value = 0;
|
|
||||||
Accuracy.Value = 1;
|
|
||||||
Health.Value = 1;
|
|
||||||
Combo.Value = 0;
|
|
||||||
Rank.Value = ScoreRank.X;
|
|
||||||
HighestCombo.Value = 0;
|
|
||||||
|
|
||||||
JudgedHits = 0;
|
|
||||||
|
|
||||||
HasFailed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the score is in a failed state and notifies subscribers.
|
|
||||||
/// <para>
|
|
||||||
/// This can only ever notify subscribers once.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
protected void UpdateFailed(JudgementResult result)
|
|
||||||
{
|
|
||||||
if (HasFailed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Failed?.Invoke() != false)
|
|
||||||
HasFailed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The judgement scoring result to notify subscribers of.</param>
|
|
||||||
protected void NotifyNewJudgement(JudgementResult result)
|
|
||||||
{
|
|
||||||
NewJudgement?.Invoke(result);
|
|
||||||
|
|
||||||
if (HasCompleted)
|
|
||||||
AllJudged?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve a score populated with data for the current play this processor is responsible for.
|
|
||||||
/// </summary>
|
|
||||||
public virtual void PopulateScore(ScoreInfo score)
|
|
||||||
{
|
|
||||||
score.TotalScore = (long)Math.Round(TotalScore.Value);
|
|
||||||
score.Combo = Combo.Value;
|
|
||||||
score.MaxCombo = HighestCombo.Value;
|
|
||||||
score.Accuracy = Math.Round(Accuracy.Value, 4);
|
|
||||||
score.Rank = Rank.Value;
|
|
||||||
score.Date = DateTimeOffset.Now;
|
|
||||||
|
|
||||||
var hitWindows = CreateHitWindows();
|
|
||||||
|
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
|
||||||
score.Statistics[result] = GetStatistic(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract int GetStatistic(HitResult result);
|
|
||||||
|
|
||||||
public abstract double GetStandardisedScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ScoreProcessor<TObject> : ScoreProcessor
|
|
||||||
where TObject : HitObject
|
|
||||||
{
|
|
||||||
private const double base_portion = 0.3;
|
|
||||||
private const double combo_portion = 0.7;
|
|
||||||
private const double max_score = 1000000;
|
|
||||||
|
|
||||||
public sealed override bool HasCompleted => JudgedHits == MaxHits;
|
|
||||||
|
|
||||||
protected int MaxHits { get; private set; }
|
protected int MaxHits { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
||||||
|
/// </summary>
|
||||||
|
public int JudgedHits { get; private set; }
|
||||||
|
|
||||||
private double maxHighestCombo;
|
private double maxHighestCombo;
|
||||||
|
|
||||||
private double maxBaseScore;
|
private double maxBaseScore;
|
||||||
@ -225,17 +114,22 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
private double scoreMultiplier = 1;
|
private double scoreMultiplier = 1;
|
||||||
|
|
||||||
public ScoreProcessor(DrawableRuleset<TObject> drawableRuleset)
|
public ScoreProcessor(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
Debug.Assert(base_portion + combo_portion == 1.0);
|
Debug.Assert(base_portion + combo_portion == 1.0);
|
||||||
|
|
||||||
drawableRuleset.OnNewResult += applyResult;
|
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
|
||||||
drawableRuleset.OnRevertResult += revertResult;
|
Accuracy.ValueChanged += accuracy =>
|
||||||
|
{
|
||||||
|
Rank.Value = rankFrom(accuracy.NewValue);
|
||||||
|
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||||
|
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
|
||||||
|
};
|
||||||
|
|
||||||
ApplyBeatmap(drawableRuleset.Beatmap);
|
ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
Reset(false);
|
Reset(false);
|
||||||
SimulateAutoplay(drawableRuleset.Beatmap);
|
SimulateAutoplay(beatmap);
|
||||||
Reset(true);
|
Reset(true);
|
||||||
|
|
||||||
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
||||||
@ -257,19 +151,19 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies any properties of the <see cref="Beatmap{TObject}"/> which affect scoring to this <see cref="ScoreProcessor{TObject}"/>.
|
/// Applies any properties of the <see cref="IBeatmap"/> which affect scoring to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to read properties from.</param>
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
|
||||||
protected virtual void ApplyBeatmap(Beatmap<TObject> beatmap)
|
protected virtual void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simulates an autoplay of the <see cref="Beatmap{TObject}"/> to determine scoring values.
|
/// Simulates an autoplay of the <see cref="IBeatmap"/> to determine scoring values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
||||||
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to simulate.</param>
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
|
||||||
protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap)
|
protected virtual void SimulateAutoplay(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
foreach (var obj in beatmap.HitObjects)
|
foreach (var obj in beatmap.HitObjects)
|
||||||
simulate(obj);
|
simulate(obj);
|
||||||
@ -289,7 +183,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
result.Type = judgement.MaxResult;
|
result.Type = judgement.MaxResult;
|
||||||
|
|
||||||
applyResult(result);
|
ApplyResult(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,22 +191,26 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
private void applyResult(JudgementResult result)
|
public void ApplyResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
ApplyResult(result);
|
ApplyResultInternal(result);
|
||||||
updateScore();
|
|
||||||
|
|
||||||
UpdateFailed(result);
|
updateScore();
|
||||||
NotifyNewJudgement(result);
|
updateFailed(result);
|
||||||
|
|
||||||
|
NewJudgement?.Invoke(result);
|
||||||
|
|
||||||
|
if (HasCompleted)
|
||||||
|
AllJudged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
private void revertResult(JudgementResult result)
|
public void RevertResult(JudgementResult result)
|
||||||
{
|
{
|
||||||
RevertResult(result);
|
RevertResultInternal(result);
|
||||||
updateScore();
|
updateScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,10 +220,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Any changes applied via this method can be reverted via <see cref="RevertResult"/>.
|
/// Any changes applied via this method can be reverted via <see cref="RevertResultInternal"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
protected virtual void ApplyResult(JudgementResult result)
|
protected virtual void ApplyResultInternal(JudgementResult result)
|
||||||
{
|
{
|
||||||
result.ComboAtJudgement = Combo.Value;
|
result.ComboAtJudgement = Combo.Value;
|
||||||
result.HighestComboAtJudgement = HighestCombo.Value;
|
result.HighestComboAtJudgement = HighestCombo.Value;
|
||||||
@ -372,10 +270,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResult"/>.
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResultInternal"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
protected virtual void RevertResult(JudgementResult result)
|
protected virtual void RevertResultInternal(JudgementResult result)
|
||||||
{
|
{
|
||||||
Combo.Value = result.ComboAtJudgement;
|
Combo.Value = result.ComboAtJudgement;
|
||||||
HighestCombo.Value = result.HighestComboAtJudgement;
|
HighestCombo.Value = result.HighestComboAtJudgement;
|
||||||
@ -432,11 +330,49 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetStatistic(HitResult result) => scoreResultCounts.GetOrDefault(result);
|
/// <summary>
|
||||||
|
/// Checks if the score is in a failed state and notifies subscribers.
|
||||||
|
/// <para>
|
||||||
|
/// This can only ever notify subscribers once.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
private void updateFailed(JudgementResult result)
|
||||||
|
{
|
||||||
|
if (HasFailed)
|
||||||
|
return;
|
||||||
|
|
||||||
public override double GetStandardisedScore() => getScore(ScoringMode.Standardised);
|
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
|
||||||
|
return;
|
||||||
|
|
||||||
protected override void Reset(bool storeResults)
|
if (Failed?.Invoke() != false)
|
||||||
|
HasFailed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScoreRank rankFrom(double acc)
|
||||||
|
{
|
||||||
|
if (acc == 1)
|
||||||
|
return ScoreRank.X;
|
||||||
|
if (acc > 0.95)
|
||||||
|
return ScoreRank.S;
|
||||||
|
if (acc > 0.9)
|
||||||
|
return ScoreRank.A;
|
||||||
|
if (acc > 0.8)
|
||||||
|
return ScoreRank.B;
|
||||||
|
if (acc > 0.7)
|
||||||
|
return ScoreRank.C;
|
||||||
|
|
||||||
|
return ScoreRank.D;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetStatistic(HitResult result) => scoreResultCounts.GetOrDefault(result);
|
||||||
|
|
||||||
|
public double GetStandardisedScore() => getScore(ScoringMode.Standardised);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets this ScoreProcessor to a default state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
||||||
|
protected virtual void Reset(bool storeResults)
|
||||||
{
|
{
|
||||||
scoreResultCounts.Clear();
|
scoreResultCounts.Clear();
|
||||||
|
|
||||||
@ -447,13 +383,49 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
maxBaseScore = baseScore;
|
maxBaseScore = baseScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Reset(storeResults);
|
JudgedHits = 0;
|
||||||
|
|
||||||
baseScore = 0;
|
baseScore = 0;
|
||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
|
|
||||||
|
TotalScore.Value = 0;
|
||||||
|
Accuracy.Value = 1;
|
||||||
|
Health.Value = 1;
|
||||||
|
Combo.Value = 0;
|
||||||
|
Rank.Value = ScoreRank.X;
|
||||||
|
HighestCombo.Value = 0;
|
||||||
|
|
||||||
|
HasFailed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve a score populated with data for the current play this processor is responsible for.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void PopulateScore(ScoreInfo score)
|
||||||
|
{
|
||||||
|
score.TotalScore = (long)Math.Round(TotalScore.Value);
|
||||||
|
score.Combo = Combo.Value;
|
||||||
|
score.MaxCombo = HighestCombo.Value;
|
||||||
|
score.Accuracy = Math.Round(Accuracy.Value, 4);
|
||||||
|
score.Rank = Rank.Value;
|
||||||
|
score.Date = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
var hitWindows = CreateHitWindows();
|
||||||
|
|
||||||
|
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
||||||
|
score.Statistics[result] = GetStatistic(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default conditions for failing.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a <see cref="HitWindows"/> for this processor.
|
||||||
|
/// </summary>
|
||||||
|
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -45,6 +45,10 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public abstract class DrawableRuleset<TObject> : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter
|
public abstract class DrawableRuleset<TObject> : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter
|
||||||
where TObject : HitObject
|
where TObject : HitObject
|
||||||
{
|
{
|
||||||
|
public override event Action<JudgementResult> OnNewResult;
|
||||||
|
|
||||||
|
public override event Action<JudgementResult> OnRevertResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The selected variant.
|
/// The selected variant.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -91,16 +95,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<JudgementResult> OnNewResult;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a <see cref="JudgementResult"/> is being reverted by a <see cref="DrawableHitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<JudgementResult> OnRevertResult;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The beatmap.
|
/// The beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -309,7 +303,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <returns>The Playfield.</returns>
|
/// <returns>The Playfield.</returns>
|
||||||
protected abstract Playfield CreatePlayfield();
|
protected abstract Playfield CreatePlayfield();
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor(Beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the active mods to this DrawableRuleset.
|
/// Applies the active mods to this DrawableRuleset.
|
||||||
@ -366,6 +360,16 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class DrawableRuleset : CompositeDrawable
|
public abstract class DrawableRuleset : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="JudgementResult"/> has been applied by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract event Action<JudgementResult> OnNewResult;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a <see cref="JudgementResult"/> is being reverted by a <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract event Action<JudgementResult> OnRevertResult;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a replay is currently loaded.
|
/// Whether a replay is currently loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Screens.Backgrounds;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -29,14 +28,13 @@ using osu.Game.Input.Bindings;
|
|||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osu.Game.Screens.Edit.Setup;
|
using osu.Game.Screens.Edit.Setup;
|
||||||
using osu.Game.Screens.Edit.Timing;
|
using osu.Game.Screens.Edit.Timing;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit
|
namespace osu.Game.Screens.Edit
|
||||||
{
|
{
|
||||||
public class Editor : OsuScreen, IKeyBindingHandler<GlobalAction>
|
public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
|
|
||||||
|
|
||||||
public override float BackgroundParallaxAmount => 0.1f;
|
public override float BackgroundParallaxAmount => 0.1f;
|
||||||
|
|
||||||
public override bool AllowBackButton => false;
|
public override bool AllowBackButton => false;
|
||||||
@ -250,8 +248,12 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
base.OnEntering(last);
|
base.OnEntering(last);
|
||||||
|
|
||||||
|
// todo: temporary. we want to be applying dim using the UserDimContainer eventually.
|
||||||
Background.FadeColour(Color4.DarkGray, 500);
|
Background.FadeColour(Color4.DarkGray, 500);
|
||||||
|
|
||||||
|
Background.EnableUserDim.Value = false;
|
||||||
|
Background.BlurAmount.Value = 0;
|
||||||
|
|
||||||
resetTrack(true);
|
resetTrack(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
processor.NewJudgement += onNewJudgement;
|
if (processor != null)
|
||||||
|
processor.NewJudgement += onNewJudgement;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -96,7 +97,9 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
processor.NewJudgement -= onNewJudgement;
|
|
||||||
|
if (processor != null)
|
||||||
|
processor.NewJudgement -= onNewJudgement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
@ -23,8 +24,8 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
public class HUDOverlay : Container
|
public class HUDOverlay : Container
|
||||||
{
|
{
|
||||||
private const int duration = 250;
|
private const int fade_duration = 400;
|
||||||
private const Easing easing = Easing.OutQuint;
|
private const Easing fade_easing = Easing.Out;
|
||||||
|
|
||||||
public readonly KeyCounterDisplay KeyCounter;
|
public readonly KeyCounterDisplay KeyCounter;
|
||||||
public readonly RollingCounter<int> ComboCounter;
|
public readonly RollingCounter<int> ComboCounter;
|
||||||
@ -43,8 +44,15 @@ namespace osu.Game.Screens.Play
|
|||||||
private readonly DrawableRuleset drawableRuleset;
|
private readonly DrawableRuleset drawableRuleset;
|
||||||
private readonly IReadOnlyList<Mod> mods;
|
private readonly IReadOnlyList<Mod> mods;
|
||||||
|
|
||||||
private Bindable<bool> showHud;
|
/// <summary>
|
||||||
|
/// Whether the elements that can optionally be hidden should be visible.
|
||||||
|
/// </summary>
|
||||||
|
public Bindable<bool> ShowHud { get; } = new BindableBool();
|
||||||
|
|
||||||
|
private Bindable<bool> configShowHud;
|
||||||
|
|
||||||
private readonly Container visibilityContainer;
|
private readonly Container visibilityContainer;
|
||||||
|
|
||||||
private readonly BindableBool replayLoaded = new BindableBool();
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
private static bool hasShownNotificationOnce;
|
private static bool hasShownNotificationOnce;
|
||||||
@ -53,6 +61,8 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private readonly Container topScoreContainer;
|
private readonly Container topScoreContainer;
|
||||||
|
|
||||||
|
private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter };
|
||||||
|
|
||||||
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
|
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
|
||||||
{
|
{
|
||||||
this.scoreProcessor = scoreProcessor;
|
this.scoreProcessor = scoreProcessor;
|
||||||
@ -73,8 +83,6 @@ namespace osu.Game.Screens.Play
|
|||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
AutoSizeDuration = 200,
|
|
||||||
AutoSizeEasing = Easing.Out,
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
AccuracyCounter = CreateAccuracyCounter(),
|
AccuracyCounter = CreateAccuracyCounter(),
|
||||||
@ -86,15 +94,17 @@ namespace osu.Game.Screens.Play
|
|||||||
Progress = CreateProgress(),
|
Progress = CreateProgress(),
|
||||||
ModDisplay = CreateModsContainer(),
|
ModDisplay = CreateModsContainer(),
|
||||||
HitErrorDisplay = CreateHitErrorDisplayOverlay(),
|
HitErrorDisplay = CreateHitErrorDisplayOverlay(),
|
||||||
|
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
|
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.BottomRight,
|
Origin = Anchor.BottomRight,
|
||||||
Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
|
Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
|
AutoSizeDuration = fade_duration,
|
||||||
|
AutoSizeEasing = fade_easing,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -108,34 +118,24 @@ namespace osu.Game.Screens.Play
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
BindProcessor(scoreProcessor);
|
if (scoreProcessor != null)
|
||||||
BindDrawableRuleset(drawableRuleset);
|
BindProcessor(scoreProcessor);
|
||||||
|
|
||||||
Progress.Objects = drawableRuleset.Objects;
|
if (drawableRuleset != null)
|
||||||
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value;
|
{
|
||||||
Progress.RequestSeek = time => RequestSeek(time);
|
BindDrawableRuleset(drawableRuleset);
|
||||||
Progress.ReferenceClock = drawableRuleset.FrameStableClock;
|
|
||||||
|
Progress.Objects = drawableRuleset.Objects;
|
||||||
|
Progress.AllowSeeking = drawableRuleset.HasReplayLoaded.Value;
|
||||||
|
Progress.RequestSeek = time => RequestSeek(time);
|
||||||
|
Progress.ReferenceClock = drawableRuleset.FrameStableClock;
|
||||||
|
}
|
||||||
|
|
||||||
ModDisplay.Current.Value = mods;
|
ModDisplay.Current.Value = mods;
|
||||||
|
|
||||||
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
configShowHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
||||||
showHud.BindValueChanged(visible => visibilityContainer.FadeTo(visible.NewValue ? 1 : 0, duration, easing), true);
|
|
||||||
|
|
||||||
ShowHealthbar.BindValueChanged(healthBar =>
|
if (!configShowHud.Value && !hasShownNotificationOnce)
|
||||||
{
|
|
||||||
if (healthBar.NewValue)
|
|
||||||
{
|
|
||||||
HealthDisplay.FadeIn(duration, easing);
|
|
||||||
topScoreContainer.MoveToY(30, duration, easing);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HealthDisplay.FadeOut(duration, easing);
|
|
||||||
topScoreContainer.MoveToY(0, duration, easing);
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
if (!showHud.Value && !hasShownNotificationOnce)
|
|
||||||
{
|
{
|
||||||
hasShownNotificationOnce = true;
|
hasShownNotificationOnce = true;
|
||||||
|
|
||||||
@ -144,12 +144,39 @@ namespace osu.Game.Screens.Play
|
|||||||
Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
|
Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start all elements hidden
|
||||||
|
hideTargets.ForEach(d => d.Hide());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Hide() => throw new InvalidOperationException($"{nameof(HUDOverlay)} should not be hidden as it will remove the ability of a user to quit. Use {nameof(ShowHud)} instead.");
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
|
ShowHud.BindValueChanged(visible => hideTargets.ForEach(d => d.FadeTo(visible.NewValue ? 1 : 0, fade_duration, fade_easing)));
|
||||||
|
|
||||||
|
ShowHealthbar.BindValueChanged(healthBar =>
|
||||||
|
{
|
||||||
|
if (healthBar.NewValue)
|
||||||
|
{
|
||||||
|
HealthDisplay.FadeIn(fade_duration, fade_easing);
|
||||||
|
topScoreContainer.MoveToY(30, fade_duration, fade_easing);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HealthDisplay.FadeOut(fade_duration, fade_easing);
|
||||||
|
topScoreContainer.MoveToY(0, fade_duration, fade_easing);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
configShowHud.BindValueChanged(visible =>
|
||||||
|
{
|
||||||
|
if (!ShowHud.Disabled)
|
||||||
|
ShowHud.Value = visible.NewValue;
|
||||||
|
}, true);
|
||||||
|
|
||||||
replayLoaded.BindValueChanged(replayLoadedValueChanged, true);
|
replayLoaded.BindValueChanged(replayLoadedValueChanged, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +216,7 @@ namespace osu.Game.Screens.Play
|
|||||||
switch (e.Key)
|
switch (e.Key)
|
||||||
{
|
{
|
||||||
case Key.Tab:
|
case Key.Tab:
|
||||||
showHud.Value = !showHud.Value;
|
configShowHud.Value = !configShowHud.Value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,7 +284,7 @@ namespace osu.Game.Screens.Play
|
|||||||
Margin = new MarginPadding { Top = 20, Right = 10 },
|
Margin = new MarginPadding { Top = 20, Right = 10 },
|
||||||
};
|
};
|
||||||
|
|
||||||
protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.FirstAvailableHitWindows);
|
protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset?.FirstAvailableHitWindows);
|
||||||
|
|
||||||
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
|
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
|
||||||
|
|
||||||
|
@ -140,6 +140,9 @@ namespace osu.Game.Screens.Play
|
|||||||
// bind clock into components that require it
|
// bind clock into components that require it
|
||||||
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
||||||
|
|
||||||
|
DrawableRuleset.OnNewResult += ScoreProcessor.ApplyResult;
|
||||||
|
DrawableRuleset.OnRevertResult += ScoreProcessor.RevertResult;
|
||||||
|
|
||||||
// Bind ScoreProcessor to ourselves
|
// Bind ScoreProcessor to ourselves
|
||||||
ScoreProcessor.AllJudged += onCompletion;
|
ScoreProcessor.AllJudged += onCompletion;
|
||||||
ScoreProcessor.Failed += onFail;
|
ScoreProcessor.Failed += onFail;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1210.1" />
|
<PackageReference Include="ppy.osu.Framework" Version="2019.1212.0" />
|
||||||
<PackageReference Include="Sentry" Version="1.2.0" />
|
<PackageReference Include="Sentry" Version="1.2.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.1210.1" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.1212.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1210.1" />
|
<PackageReference Include="ppy.osu.Framework" Version="2019.1212.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Reference in New Issue
Block a user