// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; namespace osu.Game.Rulesets.Scoring { public abstract class JudgementProcessor : Component { /// /// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by this . /// public event Action NewJudgement; /// /// The maximum number of hits that can be judged. /// protected int MaxHits { get; private set; } /// /// The total number of judged s at the current point in time. /// public int JudgedHits { get; private set; } private readonly BindableBool hasCompleted = new BindableBool(); /// /// Whether all s have been processed. /// public IBindable HasCompleted => hasCompleted; /// /// Applies a to this . /// /// The to read properties from. public virtual void ApplyBeatmap(IBeatmap beatmap) { Reset(false); SimulateAutoplay(beatmap); Reset(true); } /// /// Applies the score change of a to this . /// /// The to apply. public void ApplyResult(JudgementResult result) { JudgedHits++; ApplyResultInternal(result); NewJudgement?.Invoke(result); updateHasCompleted(); } /// /// Reverts the score change of a that was applied to this . /// /// The judgement scoring result. public void RevertResult(JudgementResult result) { JudgedHits--; updateHasCompleted(); RevertResultInternal(result); } /// /// Applies the score change of a to this . /// /// /// Any changes applied via this method can be reverted via . /// /// The to apply. protected abstract void ApplyResultInternal(JudgementResult result); /// /// Reverts the score change of a that was applied to this via . /// /// The judgement scoring result. protected abstract void RevertResultInternal(JudgementResult result); /// /// Resets this to a default state. /// /// Whether to store the current state of the for future use. protected virtual void Reset(bool storeResults) { if (storeResults) MaxHits = JudgedHits; JudgedHits = 0; } /// /// Creates the that represents the scoring result for a . /// /// The which was judged. /// The that provides the scoring information. protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement); /// /// Simulates an autoplay of the to determine scoring values. /// /// This provided temporarily. DO NOT USE. /// The to simulate. protected virtual void SimulateAutoplay(IBeatmap beatmap) { foreach (var obj in beatmap.HitObjects) simulate(obj); void simulate(HitObject obj) { foreach (var nested in obj.NestedHitObjects) simulate(nested); var judgement = obj.CreateJudgement(); var result = CreateResult(obj, judgement); if (result == null) throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); result.Type = judgement.MaxResult; ApplyResult(result); } } private void updateHasCompleted() => hasCompleted.Value = JudgedHits == MaxHits; } }