Merge remote-tracking branch 'refs/remotes/origin/master' into legacy-beatmap-saving

This commit is contained in:
smoogipoo
2019-12-13 19:01:25 +09:00
92 changed files with 2044 additions and 1122 deletions

View File

@ -4,8 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills;
@ -41,10 +41,10 @@ namespace osu.Game.Rulesets.Difficulty
IBeatmap playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
var clock = new StopwatchClock();
mods.OfType<IApplicableToClock>().ForEach(m => m.ApplyToClock(clock));
var track = new TrackVirtual(10000);
mods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
return calculate(playableBeatmap, mods, clock.Rate);
return calculate(playableBeatmap, mods, track.Rate);
}
/// <summary>

View File

@ -3,8 +3,8 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
@ -35,9 +35,9 @@ namespace osu.Game.Rulesets.Difficulty
protected virtual void ApplyMods(Mod[] mods)
{
var clock = new StopwatchClock();
mods.OfType<IApplicableToClock>().ForEach(m => m.ApplyToClock(clock));
TimeRate = clock.Rate;
var track = new TrackVirtual(10000);
mods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
TimeRate = track.Rate;
}
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);

View File

@ -48,7 +48,6 @@ namespace osu.Game.Rulesets.Edit
[Resolved]
private BindableBeatDivisor beatDivisor { get; set; }
private IWorkingBeatmap workingBeatmap;
private Beatmap<TObject> playableBeatmap;
private IBeatmapProcessor beatmapProcessor;
@ -71,7 +70,7 @@ namespace osu.Game.Rulesets.Edit
{
try
{
drawableRulesetWrapper = new DrawableEditRulesetWrapper<TObject>(CreateDrawableRuleset(Ruleset, workingBeatmap, Array.Empty<Mod>()))
drawableRulesetWrapper = new DrawableEditRulesetWrapper<TObject>(CreateDrawableRuleset(Ruleset, playableBeatmap))
{
Clock = framedClock,
ProcessCustomClock = false
@ -145,8 +144,7 @@ namespace osu.Game.Rulesets.Edit
{
var parentWorkingBeatmap = parent.Get<IBindable<WorkingBeatmap>>().Value;
playableBeatmap = (Beatmap<TObject>)parentWorkingBeatmap.GetPlayableBeatmap(Ruleset.RulesetInfo, Array.Empty<Mod>());
workingBeatmap = new EditorWorkingBeatmap<TObject>(playableBeatmap, parentWorkingBeatmap);
playableBeatmap = (Beatmap<TObject>)parentWorkingBeatmap.GetPlayableBeatmap(Ruleset.RulesetInfo);
beatmapProcessor = Ruleset.CreateBeatmapProcessor(playableBeatmap);
@ -250,7 +248,7 @@ namespace osu.Game.Rulesets.Edit
protected abstract IReadOnlyList<HitObjectCompositionTool> CompositionTools { get; }
protected abstract DrawableRuleset<TObject> CreateDrawableRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods);
protected abstract DrawableRuleset<TObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null);
public void BeginPlacement(HitObject hitObject)
{

View File

@ -1,15 +1,15 @@
// 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.Timing;
using osu.Framework.Audio.Track;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// An interface for mods that make adjustments to the track.
/// </summary>
public interface IApplicableToClock : IApplicableMod
public interface IApplicableToTrack : IApplicableMod
{
void ApplyToClock(IAdjustableClock clock);
void ApplyToTrack(Track track);
}
}

View File

@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mods
/// <summary>
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
/// </summary>
public virtual Mod CreateCopy() => (Mod)Activator.CreateInstance(GetType());
public virtual Mod CreateCopy() => (Mod)MemberwiseClone();
public bool Equals(IMod other) => GetType() == other?.GetType();
}

View File

@ -1,9 +1,8 @@
// 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.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Timing;
namespace osu.Game.Rulesets.Mods
{
@ -14,12 +13,9 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage Icon => FontAwesome.Solid.Question;
public override string Description => "Whoaaaaa...";
public override void ApplyToClock(IAdjustableClock clock)
public override void ApplyToTrack(Track track)
{
if (clock is IHasPitchAdjust pitchAdjust)
pitchAdjust.PitchAdjust *= RateAdjust;
else
base.ApplyToClock(clock);
track.Frequency.Value *= RateAdjust;
}
}
}

View File

@ -8,7 +8,7 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModDoubleTime : ModTimeAdjust, IApplicableToClock
public abstract class ModDoubleTime : ModTimeAdjust
{
public override string Name => "Double Time";
public override string Acronym => "DT";

View File

@ -8,7 +8,7 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModHalfTime : ModTimeAdjust, IApplicableToClock
public abstract class ModHalfTime : ModTimeAdjust
{
public override string Name => "Half Time";
public override string Acronym => "HT";

View File

@ -1,9 +1,8 @@
// 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.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Timing;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods
@ -15,12 +14,9 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage Icon => OsuIcon.ModNightcore;
public override string Description => "Uguuuuuuuu...";
public override void ApplyToClock(IAdjustableClock clock)
public override void ApplyToTrack(Track track)
{
if (clock is IHasPitchAdjust pitchAdjust)
pitchAdjust.PitchAdjust *= RateAdjust;
else
base.ApplyToClock(clock);
track.Frequency.Value *= RateAdjust;
}
}
}

View File

@ -2,23 +2,19 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Audio;
using osu.Framework.Timing;
using osu.Framework.Audio.Track;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModTimeAdjust : Mod
public abstract class ModTimeAdjust : Mod, IApplicableToTrack
{
public override Type[] IncompatibleMods => new[] { typeof(ModTimeRamp) };
protected abstract double RateAdjust { get; }
public virtual void ApplyToClock(IAdjustableClock clock)
public virtual void ApplyToTrack(Track track)
{
if (clock is IHasTempoAdjust tempo)
tempo.TempoAdjust *= RateAdjust;
else
clock.Rate *= RateAdjust;
track.Tempo.Value *= RateAdjust;
}
}
}

View File

@ -3,15 +3,14 @@
using System;
using System.Linq;
using osu.Framework.Audio;
using osu.Framework.Timing;
using osu.Framework.Audio.Track;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModTimeRamp : Mod, IUpdatableByPlayfield, IApplicableToClock, IApplicableToBeatmap
public abstract class ModTimeRamp : Mod, IUpdatableByPlayfield, IApplicableToTrack, IApplicableToBeatmap
{
/// <summary>
/// The point in the beatmap at which the final ramping rate should be reached.
@ -24,11 +23,11 @@ namespace osu.Game.Rulesets.Mods
private double finalRateTime;
private double beginRampTime;
private IAdjustableClock clock;
private Track track;
public virtual void ApplyToClock(IAdjustableClock clock)
public virtual void ApplyToTrack(Track track)
{
this.clock = clock;
this.track = track;
lastAdjust = 1;
@ -46,7 +45,7 @@ namespace osu.Game.Rulesets.Mods
public virtual void Update(Playfield playfield)
{
applyAdjustment((clock.CurrentTime - beginRampTime) / finalRateTime);
applyAdjustment((track.CurrentTime - beginRampTime) / finalRateTime);
}
private double lastAdjust = 1;
@ -59,23 +58,8 @@ namespace osu.Game.Rulesets.Mods
{
double adjust = 1 + (Math.Sign(FinalRateAdjustment) * Math.Clamp(amount, 0, 1) * Math.Abs(FinalRateAdjustment));
switch (clock)
{
case IHasPitchAdjust pitch:
pitch.PitchAdjust /= lastAdjust;
pitch.PitchAdjust *= adjust;
break;
case IHasTempoAdjust tempo:
tempo.TempoAdjust /= lastAdjust;
tempo.TempoAdjust *= adjust;
break;
default:
clock.Rate /= lastAdjust;
clock.Rate *= adjust;
break;
}
track.Tempo.Value /= lastAdjust;
track.Tempo.Value *= adjust;
lastAdjust = adjust;
}

View File

@ -60,7 +60,7 @@ namespace osu.Game.Rulesets
/// <param name="mods">The <see cref="Mod"/>s to apply.</param>
/// <exception cref="BeatmapInvalidForRulesetException">Unable to successfully load the beatmap to be usable with this ruleset.</exception>
/// <returns></returns>
public abstract DrawableRuleset CreateDrawableRulesetWith(IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods);
public abstract DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList<Mod> mods = null);
/// <summary>
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.

View File

@ -13,13 +13,16 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI;
using osu.Game.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>
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
/// This may occur regardless of whether an <see cref="AllJudged"/> event is invoked.
@ -67,11 +70,6 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
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>
/// The current rank.
/// </summary>
@ -90,132 +88,23 @@ namespace osu.Game.Rulesets.Scoring
/// <summary>
/// Whether all <see cref="Judgement"/>s have been processed.
/// </summary>
public virtual bool HasCompleted => false;
/// <summary>
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
/// </summary>
public int JudgedHits { get; protected set; }
public bool HasCompleted => JudgedHits == MaxHits;
/// <summary>
/// Whether this ScoreProcessor has already triggered the failed state.
/// </summary>
public virtual bool HasFailed { get; private set; }
public bool HasFailed { get; private set; }
/// <summary>
/// The default conditions for failing.
/// The maximum number of hits that can be judged.
/// </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; }
/// <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 maxBaseScore;
@ -225,17 +114,22 @@ namespace osu.Game.Rulesets.Scoring
private double scoreMultiplier = 1;
public ScoreProcessor(DrawableRuleset<TObject> drawableRuleset)
public ScoreProcessor(IBeatmap beatmap)
{
Debug.Assert(base_portion + combo_portion == 1.0);
drawableRuleset.OnNewResult += applyResult;
drawableRuleset.OnRevertResult += revertResult;
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
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);
SimulateAutoplay(drawableRuleset.Beatmap);
SimulateAutoplay(beatmap);
Reset(true);
if (maxBaseScore == 0 || maxHighestCombo == 0)
@ -257,19 +151,19 @@ namespace osu.Game.Rulesets.Scoring
}
/// <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>
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to read properties from.</param>
protected virtual void ApplyBeatmap(Beatmap<TObject> beatmap)
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
protected virtual void ApplyBeatmap(IBeatmap beatmap)
{
}
/// <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>
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to simulate.</param>
protected virtual void SimulateAutoplay(Beatmap<TObject> beatmap)
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
protected virtual void SimulateAutoplay(IBeatmap beatmap)
{
foreach (var obj in beatmap.HitObjects)
simulate(obj);
@ -289,7 +183,7 @@ namespace osu.Game.Rulesets.Scoring
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"/>.
/// </summary>
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
private void applyResult(JudgementResult result)
public void ApplyResult(JudgementResult result)
{
ApplyResult(result);
updateScore();
ApplyResultInternal(result);
UpdateFailed(result);
NotifyNewJudgement(result);
updateScore();
updateFailed(result);
NewJudgement?.Invoke(result);
if (HasCompleted)
AllJudged?.Invoke();
}
/// <summary>
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
/// </summary>
/// <param name="result">The judgement scoring result.</param>
private void revertResult(JudgementResult result)
public void RevertResult(JudgementResult result)
{
RevertResult(result);
RevertResultInternal(result);
updateScore();
}
@ -322,10 +220,10 @@ namespace osu.Game.Rulesets.Scoring
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
/// </summary>
/// <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>
/// <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.HighestComboAtJudgement = HighestCombo.Value;
@ -372,10 +270,10 @@ namespace osu.Game.Rulesets.Scoring
}
/// <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>
/// <param name="result">The judgement scoring result.</param>
protected virtual void RevertResult(JudgementResult result)
protected virtual void RevertResultInternal(JudgementResult result)
{
Combo.Value = result.ComboAtJudgement;
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();
@ -447,13 +383,49 @@ namespace osu.Game.Rulesets.Scoring
maxBaseScore = baseScore;
}
base.Reset(storeResults);
JudgedHits = 0;
baseScore = 0;
rollingMaxBaseScore = 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>
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
/// </summary>

View File

@ -45,6 +45,10 @@ namespace osu.Game.Rulesets.UI
public abstract class DrawableRuleset<TObject> : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter
where TObject : HitObject
{
public override event Action<JudgementResult> OnNewResult;
public override event Action<JudgementResult> OnRevertResult;
/// <summary>
/// The selected variant.
/// </summary>
@ -91,20 +95,10 @@ 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>
/// The beatmap.
/// </summary>
public Beatmap<TObject> Beatmap;
public readonly Beatmap<TObject> Beatmap;
public override IEnumerable<HitObject> Objects => Beatmap.HitObjects;
@ -124,20 +118,22 @@ namespace osu.Game.Rulesets.UI
/// Creates a ruleset visualisation for the provided ruleset and beatmap.
/// </summary>
/// <param name="ruleset">The ruleset being represented.</param>
/// <param name="workingBeatmap">The beatmap to create the hit renderer for.</param>
/// <param name="beatmap">The beatmap to create the hit renderer for.</param>
/// <param name="mods">The <see cref="Mod"/>s to apply.</param>
protected DrawableRuleset(Ruleset ruleset, IWorkingBeatmap workingBeatmap, IReadOnlyList<Mod> mods)
protected DrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
: base(ruleset)
{
if (workingBeatmap == null)
throw new ArgumentException("Beatmap cannot be null.", nameof(workingBeatmap));
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap), "Beatmap cannot be null.");
this.mods = mods.ToArray();
if (!(beatmap is Beatmap<TObject> tBeatmap))
throw new ArgumentException($"{GetType()} expected the beatmap to contain hitobjects of type {typeof(TObject)}.", nameof(beatmap));
Beatmap = tBeatmap;
this.mods = mods?.ToArray() ?? Array.Empty<Mod>();
RelativeSizeAxes = Axes.Both;
Beatmap = (Beatmap<TObject>)workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
KeyBindingInputManager = CreateInputManager();
playfield = new Lazy<Playfield>(CreatePlayfield);
@ -309,7 +305,7 @@ namespace osu.Game.Rulesets.UI
/// <returns>The Playfield.</returns>
protected abstract Playfield CreatePlayfield();
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this);
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor(Beatmap);
/// <summary>
/// Applies the active mods to this DrawableRuleset.
@ -366,6 +362,16 @@ namespace osu.Game.Rulesets.UI
/// </summary>
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>
/// Whether a replay is currently loaded.
/// </summary>
@ -511,15 +517,19 @@ namespace osu.Game.Rulesets.UI
public IEnumerable<string> GetAvailableResources() => throw new NotImplementedException();
public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => throw new NotImplementedException();
public void AddAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotImplementedException();
public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable) => throw new NotImplementedException();
public void RemoveAdjustment(AdjustableProperty type, BindableNumber<double> adjustBindable) => throw new NotImplementedException();
public BindableDouble Volume => throw new NotImplementedException();
public BindableNumber<double> Volume => throw new NotImplementedException();
public BindableDouble Balance => throw new NotImplementedException();
public BindableNumber<double> Balance => throw new NotImplementedException();
public BindableDouble Frequency => throw new NotImplementedException();
public BindableNumber<double> Frequency => throw new NotImplementedException();
public BindableNumber<double> Tempo => throw new NotImplementedException();
public IBindable<double> GetAggregate(AdjustableProperty type) => throw new NotImplementedException();
public IBindable<double> AggregateVolume => throw new NotImplementedException();
@ -527,6 +537,8 @@ namespace osu.Game.Rulesets.UI
public IBindable<double> AggregateFrequency => throw new NotImplementedException();
public IBindable<double> AggregateTempo => throw new NotImplementedException();
public int PlaybackConcurrency
{
get => throw new NotImplementedException();

View File

@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
[Cached(Type = typeof(IScrollingInfo))]
private readonly LocalScrollingInfo scrollingInfo;
protected DrawableScrollingRuleset(Ruleset ruleset, IWorkingBeatmap beatmap, IReadOnlyList<Mod> mods)
protected DrawableScrollingRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
: base(ruleset, beatmap, mods)
{
scrollingInfo = new LocalScrollingInfo();