mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 12:45:09 +08:00
Merge branch 'master' into ruleset-result-types
This commit is contained in:
commit
07558b5bc0
@ -29,6 +29,11 @@ namespace osu.Desktop.Updater
|
|||||||
|
|
||||||
private static readonly Logger logger = Logger.GetLogger("updater");
|
private static readonly Logger logger = Logger.GetLogger("updater");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether an update has been downloaded but not yet applied.
|
||||||
|
/// </summary>
|
||||||
|
private bool updatePending;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(NotificationOverlay notification)
|
private void load(NotificationOverlay notification)
|
||||||
{
|
{
|
||||||
@ -37,9 +42,9 @@ namespace osu.Desktop.Updater
|
|||||||
Splat.Locator.CurrentMutable.Register(() => new SquirrelLogger(), typeof(Splat.ILogger));
|
Splat.Locator.CurrentMutable.Register(() => new SquirrelLogger(), typeof(Splat.ILogger));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task PerformUpdateCheck() => await checkForUpdateAsync();
|
protected override async Task<bool> PerformUpdateCheck() => await checkForUpdateAsync();
|
||||||
|
|
||||||
private async Task checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
|
private async Task<bool> checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
|
||||||
{
|
{
|
||||||
// should we schedule a retry on completion of this check?
|
// should we schedule a retry on completion of this check?
|
||||||
bool scheduleRecheck = true;
|
bool scheduleRecheck = true;
|
||||||
@ -49,9 +54,19 @@ namespace osu.Desktop.Updater
|
|||||||
updateManager ??= await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
|
updateManager ??= await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
|
||||||
|
|
||||||
var info = await updateManager.CheckForUpdate(!useDeltaPatching);
|
var info = await updateManager.CheckForUpdate(!useDeltaPatching);
|
||||||
|
|
||||||
if (info.ReleasesToApply.Count == 0)
|
if (info.ReleasesToApply.Count == 0)
|
||||||
|
{
|
||||||
|
if (updatePending)
|
||||||
|
{
|
||||||
|
// the user may have dismissed the completion notice, so show it again.
|
||||||
|
notificationOverlay.Post(new UpdateCompleteNotification(this));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// no updates available. bail and retry later.
|
// no updates available. bail and retry later.
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (notification == null)
|
if (notification == null)
|
||||||
{
|
{
|
||||||
@ -72,6 +87,7 @@ namespace osu.Desktop.Updater
|
|||||||
await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f);
|
await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f);
|
||||||
|
|
||||||
notification.State = ProgressNotificationState.Completed;
|
notification.State = ProgressNotificationState.Completed;
|
||||||
|
updatePending = true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -103,6 +119,8 @@ namespace osu.Desktop.Updater
|
|||||||
Scheduler.AddDelayed(async () => await checkForUpdateAsync(), 60000 * 30);
|
Scheduler.AddDelayed(async () => await checkForUpdateAsync(), 60000 * 30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
@ -111,10 +129,27 @@ namespace osu.Desktop.Updater
|
|||||||
updateManager?.Dispose();
|
updateManager?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class UpdateCompleteNotification : ProgressCompletionNotification
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private OsuGame game { get; set; }
|
||||||
|
|
||||||
|
public UpdateCompleteNotification(SquirrelUpdateManager updateManager)
|
||||||
|
{
|
||||||
|
Text = @"Update ready to install. Click to restart!";
|
||||||
|
|
||||||
|
Activated = () =>
|
||||||
|
{
|
||||||
|
updateManager.PrepareUpdateAsync()
|
||||||
|
.ContinueWith(_ => updateManager.Schedule(() => game.GracefullyExit()));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class UpdateProgressNotification : ProgressNotification
|
private class UpdateProgressNotification : ProgressNotification
|
||||||
{
|
{
|
||||||
private readonly SquirrelUpdateManager updateManager;
|
private readonly SquirrelUpdateManager updateManager;
|
||||||
private OsuGame game;
|
|
||||||
|
|
||||||
public UpdateProgressNotification(SquirrelUpdateManager updateManager)
|
public UpdateProgressNotification(SquirrelUpdateManager updateManager)
|
||||||
{
|
{
|
||||||
@ -123,23 +158,12 @@ namespace osu.Desktop.Updater
|
|||||||
|
|
||||||
protected override Notification CreateCompletionNotification()
|
protected override Notification CreateCompletionNotification()
|
||||||
{
|
{
|
||||||
return new ProgressCompletionNotification
|
return new UpdateCompleteNotification(updateManager);
|
||||||
{
|
|
||||||
Text = @"Update ready to install. Click to restart!",
|
|
||||||
Activated = () =>
|
|
||||||
{
|
|
||||||
updateManager.PrepareUpdateAsync()
|
|
||||||
.ContinueWith(_ => updateManager.Schedule(() => game.GracefullyExit()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, OsuGame game)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
this.game = game;
|
|
||||||
|
|
||||||
IconContent.AddRange(new Drawable[]
|
IconContent.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
|
@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new CatchPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public int LegacyID => 2;
|
public int LegacyID => 2;
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -25,8 +24,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
private int tinyTicksMissed;
|
private int tinyTicksMissed;
|
||||||
private int misses;
|
private int misses;
|
||||||
|
|
||||||
public CatchPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public CatchPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -29,8 +28,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public ManiaPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new ManiaPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public const string SHORT_NAME = "mania";
|
public const string SHORT_NAME = "mania";
|
||||||
|
|
||||||
|
@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
public double SpeedStrain;
|
public double SpeedStrain;
|
||||||
public double ApproachRate;
|
public double ApproachRate;
|
||||||
public double OverallDifficulty;
|
public double OverallDifficulty;
|
||||||
|
public int HitCircleCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
|
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
|
||||||
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
|
|
||||||
|
int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
return new OsuDifficultyAttributes
|
return new OsuDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
@ -56,6 +58,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||||
MaxCombo = maxCombo,
|
MaxCombo = maxCombo,
|
||||||
|
HitCircleCount = hitCirclesCount,
|
||||||
Skills = skills
|
Skills = skills
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,9 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -19,9 +17,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
|
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
|
||||||
|
|
||||||
private readonly int countHitCircles;
|
|
||||||
private readonly int beatmapMaxCombo;
|
|
||||||
|
|
||||||
private Mod[] mods;
|
private Mod[] mods;
|
||||||
|
|
||||||
private double accuracy;
|
private double accuracy;
|
||||||
@ -31,14 +26,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public OsuPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
|
||||||
|
|
||||||
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
|
||||||
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
|
||||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
||||||
@ -81,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
categoryRatings.Add("Accuracy", accuracyValue);
|
categoryRatings.Add("Accuracy", accuracyValue);
|
||||||
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
||||||
categoryRatings.Add("AR", Attributes.ApproachRate);
|
categoryRatings.Add("AR", Attributes.ApproachRate);
|
||||||
categoryRatings.Add("Max Combo", beatmapMaxCombo);
|
categoryRatings.Add("Max Combo", Attributes.MaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
@ -106,8 +96,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimValue *= Math.Pow(0.97, countMiss);
|
aimValue *= Math.Pow(0.97, countMiss);
|
||||||
|
|
||||||
// Combo scaling
|
// Combo scaling
|
||||||
if (beatmapMaxCombo > 0)
|
if (Attributes.MaxCombo > 0)
|
||||||
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(beatmapMaxCombo, 0.8), 1.0);
|
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
double approachRateFactor = 1.0;
|
double approachRateFactor = 1.0;
|
||||||
|
|
||||||
@ -154,8 +144,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
speedValue *= Math.Pow(0.97, countMiss);
|
speedValue *= Math.Pow(0.97, countMiss);
|
||||||
|
|
||||||
// Combo scaling
|
// Combo scaling
|
||||||
if (beatmapMaxCombo > 0)
|
if (Attributes.MaxCombo > 0)
|
||||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(beatmapMaxCombo, 0.8), 1.0);
|
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
double approachRateFactor = 1.0;
|
double approachRateFactor = 1.0;
|
||||||
if (Attributes.ApproachRate > 10.33)
|
if (Attributes.ApproachRate > 10.33)
|
||||||
@ -178,7 +168,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
||||||
double betterAccuracyPercentage;
|
double betterAccuracyPercentage;
|
||||||
int amountHitObjectsWithAccuracy = countHitCircles;
|
int amountHitObjectsWithAccuracy = Attributes.HitCircleCount;
|
||||||
|
|
||||||
if (amountHitObjectsWithAccuracy > 0)
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
||||||
|
@ -171,7 +171,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new OsuPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new OsuPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -24,8 +23,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public TaikoPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,8 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
yield return new TernaryStateMenuItem("Strong") { State = { BindTarget = selectionStrongState } };
|
yield return new TernaryStateMenuItem("Strong") { State = { BindTarget = selectionStrongState } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool HandleMovement(MoveSelectionEvent moveEvent) => true;
|
||||||
|
|
||||||
protected override void UpdateTernaryStates()
|
protected override void UpdateTernaryStates()
|
||||||
{
|
{
|
||||||
base.UpdateTernaryStates();
|
base.UpdateTernaryStates();
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -14,13 +15,29 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
{
|
{
|
||||||
public class TaikoLegacySkinTransformer : LegacySkinTransformer
|
public class TaikoLegacySkinTransformer : LegacySkinTransformer
|
||||||
{
|
{
|
||||||
|
private Lazy<bool> hasExplosion;
|
||||||
|
|
||||||
public TaikoLegacySkinTransformer(ISkinSource source)
|
public TaikoLegacySkinTransformer(ISkinSource source)
|
||||||
: base(source)
|
: base(source)
|
||||||
{
|
{
|
||||||
|
Source.SourceChanged += sourceChanged;
|
||||||
|
sourceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sourceChanged()
|
||||||
|
{
|
||||||
|
hasExplosion = new Lazy<bool>(() => Source.GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Drawable GetDrawableComponent(ISkinComponent component)
|
public override Drawable GetDrawableComponent(ISkinComponent component)
|
||||||
{
|
{
|
||||||
|
if (component is GameplaySkinComponent<HitResult>)
|
||||||
|
{
|
||||||
|
// if a taiko skin is providing explosion sprites, hide the judgements completely
|
||||||
|
if (hasExplosion.Value)
|
||||||
|
return Drawable.Empty();
|
||||||
|
}
|
||||||
|
|
||||||
if (!(component is TaikoSkinComponent taikoComponent))
|
if (!(component is TaikoSkinComponent taikoComponent))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -87,10 +104,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
var hitName = getHitName(taikoComponent.Component);
|
var hitName = getHitName(taikoComponent.Component);
|
||||||
var hitSprite = this.GetAnimation(hitName, true, false);
|
var hitSprite = this.GetAnimation(hitName, true, false);
|
||||||
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
|
||||||
|
|
||||||
if (hitSprite != null)
|
if (hitSprite != null)
|
||||||
|
{
|
||||||
|
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
||||||
|
|
||||||
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new TaikoPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new TaikoPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public int LegacyID => 1;
|
public int LegacyID => 1;
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
@ -23,33 +24,41 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivation()
|
public void TestGameplayOverlayActivation()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivationPaused()
|
public void TestGameplayOverlayActivationPaused()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
AddStep("pause gameplay", () => Player.Pause());
|
AddStep("pause gameplay", () => Player.Pause());
|
||||||
|
AddAssert("local user not playing", () => !Player.LocalUserPlaying.Value);
|
||||||
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivationReplayLoaded()
|
public void TestGameplayOverlayActivationReplayLoaded()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
||||||
|
AddAssert("local user not playing", () => !Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivationBreaks()
|
public void TestGameplayOverlayActivationBreaks()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
||||||
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
AddAssert("local user not playing", () => !Player.LocalUserPlaying.Value);
|
||||||
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
||||||
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
||||||
@ -57,6 +66,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
protected class OverlayTestPlayer : TestPlayer
|
protected class OverlayTestPlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
||||||
|
public new Bindable<bool> LocalUserPlaying => base.LocalUserPlaying;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Configuration.Tracking;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Input;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -69,6 +70,7 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
Set(OsuSetting.MouseDisableButtons, false);
|
Set(OsuSetting.MouseDisableButtons, false);
|
||||||
Set(OsuSetting.MouseDisableWheel, false);
|
Set(OsuSetting.MouseDisableWheel, false);
|
||||||
|
Set(OsuSetting.ConfineMouseMode, OsuConfineMouseMode.DuringGameplay);
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
Set(OsuSetting.ShowFpsDisplay, false);
|
Set(OsuSetting.ShowFpsDisplay, false);
|
||||||
@ -194,6 +196,7 @@ namespace osu.Game.Configuration
|
|||||||
FadePlayfieldWhenHealthLow,
|
FadePlayfieldWhenHealthLow,
|
||||||
MouseDisableButtons,
|
MouseDisableButtons,
|
||||||
MouseDisableWheel,
|
MouseDisableWheel,
|
||||||
|
ConfineMouseMode,
|
||||||
AudioOffset,
|
AudioOffset,
|
||||||
VolumeInactive,
|
VolumeInactive,
|
||||||
MenuMusic,
|
MenuMusic,
|
||||||
|
61
osu.Game/Input/ConfineMouseTracker.cs
Normal file
61
osu.Game/Input/ConfineMouseTracker.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
|
namespace osu.Game.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connects <see cref="OsuSetting.ConfineMouseMode"/> with <see cref="FrameworkSetting.ConfineMouseMode"/>.
|
||||||
|
/// If <see cref="OsuGame.LocalUserPlaying"/> is true, we should also confine the mouse cursor if it has been
|
||||||
|
/// requested with <see cref="OsuConfineMouseMode.DuringGameplay"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class ConfineMouseTracker : Component
|
||||||
|
{
|
||||||
|
private Bindable<ConfineMouseMode> frameworkConfineMode;
|
||||||
|
private Bindable<OsuConfineMouseMode> osuConfineMode;
|
||||||
|
private IBindable<bool> localUserPlaying;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGame game, FrameworkConfigManager frameworkConfigManager, OsuConfigManager osuConfigManager)
|
||||||
|
{
|
||||||
|
frameworkConfineMode = frameworkConfigManager.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode);
|
||||||
|
osuConfineMode = osuConfigManager.GetBindable<OsuConfineMouseMode>(OsuSetting.ConfineMouseMode);
|
||||||
|
localUserPlaying = game.LocalUserPlaying.GetBoundCopy();
|
||||||
|
|
||||||
|
osuConfineMode.ValueChanged += _ => updateConfineMode();
|
||||||
|
localUserPlaying.BindValueChanged(_ => updateConfineMode(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfineMode()
|
||||||
|
{
|
||||||
|
// confine mode is unavailable on some platforms
|
||||||
|
if (frameworkConfineMode.Disabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (osuConfineMode.Value)
|
||||||
|
{
|
||||||
|
case OsuConfineMouseMode.Never:
|
||||||
|
frameworkConfineMode.Value = ConfineMouseMode.Never;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuConfineMouseMode.Fullscreen:
|
||||||
|
frameworkConfineMode.Value = ConfineMouseMode.Fullscreen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuConfineMouseMode.DuringGameplay:
|
||||||
|
frameworkConfineMode.Value = localUserPlaying.Value ? ConfineMouseMode.Always : ConfineMouseMode.Never;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuConfineMouseMode.Always:
|
||||||
|
frameworkConfineMode.Value = ConfineMouseMode.Always;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
osu.Game/Input/OsuConfineMouseMode.cs
Normal file
37
osu.Game/Input/OsuConfineMouseMode.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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.ComponentModel;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the situations in which the mouse cursor should be confined to the window.
|
||||||
|
/// Expands upon <see cref="ConfineMouseMode"/> by providing the option to confine during gameplay.
|
||||||
|
/// </summary>
|
||||||
|
public enum OsuConfineMouseMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will be free to move outside the game window.
|
||||||
|
/// </summary>
|
||||||
|
Never,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will be locked to the window bounds while in fullscreen mode.
|
||||||
|
/// </summary>
|
||||||
|
Fullscreen,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will be locked to the window bounds during gameplay,
|
||||||
|
/// but may otherwise move freely.
|
||||||
|
/// </summary>
|
||||||
|
[Description("During Gameplay")]
|
||||||
|
DuringGameplay,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will always be locked to the window bounds while the game has focus.
|
||||||
|
/// </summary>
|
||||||
|
Always
|
||||||
|
}
|
||||||
|
}
|
@ -95,6 +95,15 @@ namespace osu.Game
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
|
public readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the local user is currently interacting with the game in a way that should not be interrupted.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is exclusively managed by <see cref="Player"/>. If other components are mutating this state, a more
|
||||||
|
/// resilient method should be used to ensure correct state.
|
||||||
|
/// </remarks>
|
||||||
|
public Bindable<bool> LocalUserPlaying = new BindableBool();
|
||||||
|
|
||||||
protected OsuScreenStack ScreenStack;
|
protected OsuScreenStack ScreenStack;
|
||||||
|
|
||||||
protected BackButton BackButton;
|
protected BackButton BackButton;
|
||||||
@ -577,7 +586,8 @@ namespace osu.Game
|
|||||||
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
idleTracker
|
idleTracker,
|
||||||
|
new ConfineMouseTracker()
|
||||||
});
|
});
|
||||||
|
|
||||||
ScreenStack.ScreenPushed += screenPushed;
|
ScreenStack.ScreenPushed += screenPushed;
|
||||||
@ -947,6 +957,9 @@ namespace osu.Game
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset on screen change for sanity.
|
||||||
|
LocalUserPlaying.Value = false;
|
||||||
|
|
||||||
if (current is IOsuScreen currentOsuScreen)
|
if (current is IOsuScreen currentOsuScreen)
|
||||||
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
|
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
|
||||||
|
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
||||||
using osu.Game.Updater;
|
using osu.Game.Updater;
|
||||||
|
|
||||||
@ -21,6 +23,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
|
|
||||||
private SettingsButton checkForUpdatesButton;
|
private SettingsButton checkForUpdatesButton;
|
||||||
|
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private NotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(Storage storage, OsuConfigManager config, OsuGame game)
|
private void load(Storage storage, OsuConfigManager config, OsuGame game)
|
||||||
{
|
{
|
||||||
@ -38,7 +43,19 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
checkForUpdatesButton.Enabled.Value = false;
|
checkForUpdatesButton.Enabled.Value = false;
|
||||||
Task.Run(updateManager.CheckForUpdateAsync).ContinueWith(t => Schedule(() => checkForUpdatesButton.Enabled.Value = true));
|
Task.Run(updateManager.CheckForUpdateAsync).ContinueWith(t => Schedule(() =>
|
||||||
|
{
|
||||||
|
if (!t.Result)
|
||||||
|
{
|
||||||
|
notifications?.Post(new SimpleNotification
|
||||||
|
{
|
||||||
|
Text = $"You are running the latest release ({game.Version})",
|
||||||
|
Icon = FontAwesome.Solid.CheckCircle,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdatesButton.Enabled.Value = true;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Input;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||||
{
|
{
|
||||||
@ -47,10 +47,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
LabelText = "Map absolute input to window",
|
LabelText = "Map absolute input to window",
|
||||||
Current = config.GetBindable<bool>(FrameworkSetting.MapAbsoluteInputToWindow)
|
Current = config.GetBindable<bool>(FrameworkSetting.MapAbsoluteInputToWindow)
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ConfineMouseMode>
|
new SettingsEnumDropdown<OsuConfineMouseMode>
|
||||||
{
|
{
|
||||||
LabelText = "Confine mouse cursor to window",
|
LabelText = "Confine mouse cursor to window",
|
||||||
Current = config.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode),
|
Current = osuConfig.GetBindable<OsuConfineMouseMode>(OsuSetting.ConfineMouseMode)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -16,19 +16,16 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
protected readonly DifficultyAttributes Attributes;
|
protected readonly DifficultyAttributes Attributes;
|
||||||
|
|
||||||
protected readonly Ruleset Ruleset;
|
protected readonly Ruleset Ruleset;
|
||||||
protected readonly IBeatmap Beatmap;
|
|
||||||
protected readonly ScoreInfo Score;
|
protected readonly ScoreInfo Score;
|
||||||
|
|
||||||
protected double TimeRate { get; private set; } = 1;
|
protected double TimeRate { get; private set; } = 1;
|
||||||
|
|
||||||
protected PerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
protected PerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
{
|
{
|
||||||
Ruleset = ruleset;
|
Ruleset = ruleset;
|
||||||
Score = score;
|
Score = score;
|
||||||
|
|
||||||
Beatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods);
|
Attributes = attributes ?? throw new ArgumentNullException(nameof(attributes));
|
||||||
|
|
||||||
Attributes = ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods);
|
|
||||||
|
|
||||||
ApplyMods(score.Mods);
|
ApplyMods(score.Mods);
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
// apply any custom state overrides
|
// apply any custom state overrides
|
||||||
ApplyCustomUpdateState?.Invoke(this, newState);
|
ApplyCustomUpdateState?.Invoke(this, newState);
|
||||||
|
|
||||||
if (newState == ArmedState.Hit)
|
if (!force && newState == ArmedState.Hit)
|
||||||
PlaySamples();
|
PlaySamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,28 @@ namespace osu.Game.Rulesets
|
|||||||
|
|
||||||
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
||||||
|
|
||||||
public virtual PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => null;
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="PerformanceCalculator"/> to generate performance data from the provided score.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attributes">Difficulty attributes for the beatmap related to the provided score.</param>
|
||||||
|
/// <param name="score">The score to be processed.</param>
|
||||||
|
/// <returns>A performance calculator instance for the provided score.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public virtual PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="PerformanceCalculator"/> to generate performance data from the provided score.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to use as a source for generating <see cref="DifficultyAttributes"/>.</param>
|
||||||
|
/// <param name="score">The score to be processed.</param>
|
||||||
|
/// <returns>A performance calculator instance for the provided score.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score)
|
||||||
|
{
|
||||||
|
var difficultyCalculator = CreateDifficultyCalculator(beatmap);
|
||||||
|
var difficultyAttributes = difficultyCalculator.Calculate(score.Mods);
|
||||||
|
return CreatePerformanceCalculator(difficultyAttributes, score);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual HitObjectComposer CreateHitObjectComposer() => null;
|
public virtual HitObjectComposer CreateHitObjectComposer() => null;
|
||||||
|
|
||||||
|
@ -113,7 +113,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
};
|
};
|
||||||
|
|
||||||
controlPoints = group.ControlPoints.GetBoundCopy();
|
controlPoints = group.ControlPoints.GetBoundCopy();
|
||||||
controlPoints.CollectionChanged += (_, __) => createChildren();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -125,6 +124,12 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
createChildren();
|
createChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
controlPoints.CollectionChanged += (_, __) => createChildren();
|
||||||
|
}
|
||||||
|
|
||||||
private void createChildren()
|
private void createChildren()
|
||||||
{
|
{
|
||||||
fill.ChildrenEnumerable = controlPoints.Select(createAttribute).Where(c => c != null);
|
fill.ChildrenEnumerable = controlPoints.Select(createAttribute).Where(c => c != null);
|
||||||
|
@ -111,7 +111,8 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
foreach (var cp in currentGroupItems)
|
foreach (var cp in currentGroupItems)
|
||||||
Beatmap.Value.Beatmap.ControlPointInfo.Add(time, cp);
|
Beatmap.Value.Beatmap.ControlPointInfo.Add(time, cp);
|
||||||
|
|
||||||
SelectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(time);
|
// the control point might not necessarily exist yet, if currentGroupItems was empty.
|
||||||
|
SelectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(time, true);
|
||||||
|
|
||||||
changeHandler?.EndChange();
|
changeHandler?.EndChange();
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,8 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private readonly Bindable<bool> storyboardReplacesBackground = new Bindable<bool>();
|
private readonly Bindable<bool> storyboardReplacesBackground = new Bindable<bool>();
|
||||||
|
|
||||||
|
protected readonly Bindable<bool> LocalUserPlaying = new Bindable<bool>();
|
||||||
|
|
||||||
public int RestartCount;
|
public int RestartCount;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -155,8 +157,8 @@ namespace osu.Game.Screens.Play
|
|||||||
DrawableRuleset.SetRecordTarget(recordingReplay = new Replay());
|
DrawableRuleset.SetRecordTarget(recordingReplay = new Replay());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(AudioManager audio, OsuConfigManager config)
|
private void load(AudioManager audio, OsuConfigManager config, OsuGame game)
|
||||||
{
|
{
|
||||||
Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray();
|
Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray();
|
||||||
|
|
||||||
@ -172,6 +174,9 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||||
|
|
||||||
|
if (game != null)
|
||||||
|
LocalUserPlaying.BindTo(game.LocalUserPlaying);
|
||||||
|
|
||||||
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);
|
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);
|
||||||
|
|
||||||
ScoreProcessor = ruleset.CreateScoreProcessor();
|
ScoreProcessor = ruleset.CreateScoreProcessor();
|
||||||
@ -219,9 +224,9 @@ namespace osu.Game.Screens.Play
|
|||||||
skipOverlay.Hide();
|
skipOverlay.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawableRuleset.IsPaused.BindValueChanged(_ => updateOverlayActivationMode());
|
DrawableRuleset.IsPaused.BindValueChanged(_ => updateGameplayState());
|
||||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateOverlayActivationMode());
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateGameplayState());
|
||||||
breakTracker.IsBreakTime.BindValueChanged(_ => updateOverlayActivationMode());
|
breakTracker.IsBreakTime.BindValueChanged(_ => updateGameplayState());
|
||||||
|
|
||||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
||||||
|
|
||||||
@ -353,14 +358,11 @@ namespace osu.Game.Screens.Play
|
|||||||
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
|
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverlayActivationMode()
|
private void updateGameplayState()
|
||||||
{
|
{
|
||||||
bool canTriggerOverlays = DrawableRuleset.IsPaused.Value || breakTracker.IsBreakTime.Value;
|
bool inGameplay = !DrawableRuleset.HasReplayLoaded.Value && !DrawableRuleset.IsPaused.Value && !breakTracker.IsBreakTime.Value;
|
||||||
|
OverlayActivationMode.Value = inGameplay ? OverlayActivation.Disabled : OverlayActivation.UserTriggered;
|
||||||
if (DrawableRuleset.HasReplayLoaded.Value || canTriggerOverlays)
|
LocalUserPlaying.Value = inGameplay;
|
||||||
OverlayActivationMode.Value = OverlayActivation.UserTriggered;
|
|
||||||
else
|
|
||||||
OverlayActivationMode.Value = OverlayActivation.Disabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePauseOnFocusLostState() =>
|
private void updatePauseOnFocusLostState() =>
|
||||||
@ -441,6 +443,10 @@ namespace osu.Game.Screens.Play
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Restart()
|
public void Restart()
|
||||||
{
|
{
|
||||||
|
// at the point of restarting the track should either already be paused or the volume should be zero.
|
||||||
|
// stopping here is to ensure music doesn't become audible after exiting back to PlayerLoader.
|
||||||
|
musicController.Stop();
|
||||||
|
|
||||||
sampleRestart?.Play();
|
sampleRestart?.Play();
|
||||||
RestartRequested?.Invoke();
|
RestartRequested?.Invoke();
|
||||||
|
|
||||||
@ -657,7 +663,7 @@ namespace osu.Game.Screens.Play
|
|||||||
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
||||||
mod.ApplyToTrack(musicController.CurrentTrack);
|
mod.ApplyToTrack(musicController.CurrentTrack);
|
||||||
|
|
||||||
updateOverlayActivationMode();
|
updateGameplayState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSuspending(IScreen next)
|
public override void OnSuspending(IScreen next)
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Updater
|
|||||||
version = game.Version;
|
version = game.Version;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task PerformUpdateCheck()
|
protected override async Task<bool> PerformUpdateCheck()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -53,12 +53,17 @@ namespace osu.Game.Updater
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// we shouldn't crash on a web failure. or any failure for the matter.
|
// we shouldn't crash on a web failure. or any failure for the matter.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string getBestUrl(GitHubRelease release)
|
private string getBestUrl(GitHubRelease release)
|
||||||
|
@ -57,25 +57,31 @@ namespace osu.Game.Updater
|
|||||||
|
|
||||||
private readonly object updateTaskLock = new object();
|
private readonly object updateTaskLock = new object();
|
||||||
|
|
||||||
private Task updateCheckTask;
|
private Task<bool> updateCheckTask;
|
||||||
|
|
||||||
public async Task CheckForUpdateAsync()
|
public async Task<bool> CheckForUpdateAsync()
|
||||||
{
|
{
|
||||||
if (!CanCheckForUpdate)
|
if (!CanCheckForUpdate)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
Task waitTask;
|
Task<bool> waitTask;
|
||||||
|
|
||||||
lock (updateTaskLock)
|
lock (updateTaskLock)
|
||||||
waitTask = (updateCheckTask ??= PerformUpdateCheck());
|
waitTask = (updateCheckTask ??= PerformUpdateCheck());
|
||||||
|
|
||||||
await waitTask;
|
bool hasUpdates = await waitTask;
|
||||||
|
|
||||||
lock (updateTaskLock)
|
lock (updateTaskLock)
|
||||||
updateCheckTask = null;
|
updateCheckTask = null;
|
||||||
|
|
||||||
|
return hasUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task PerformUpdateCheck() => Task.CompletedTask;
|
/// <summary>
|
||||||
|
/// Performs an asynchronous check for application updates.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Whether any update is waiting. May return true if an error occured (there is potentially an update available).</returns>
|
||||||
|
protected virtual Task<bool> PerformUpdateCheck() => Task.FromResult(false);
|
||||||
|
|
||||||
private class UpdateCompleteNotification : SimpleNotification
|
private class UpdateCompleteNotification : SimpleNotification
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user