mirror of
https://github.com/ppy/osu
synced 2025-01-02 04:12:13 +00:00
Optimise by removing state machine
This commit is contained in:
parent
3daacbc2d2
commit
62f77a05be
@ -1,7 +1,9 @@
|
||||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
@ -36,11 +38,14 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
DrawableHitObject blockingObject = null;
|
||||
|
||||
// Find the last hitobject which blocks future hits.
|
||||
foreach (var obj in enumerateHitObjectsUpTo(hitObject))
|
||||
var enumerator = new HitObjectEnumerator(hitObjectContainer, hitObject.HitObject.StartTime);
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
if (hitObjectCanBlockFutureHits(obj))
|
||||
blockingObject = obj;
|
||||
Debug.Assert(enumerator.Current != null);
|
||||
|
||||
if (hitObjectCanBlockFutureHits(enumerator.Current))
|
||||
blockingObject = enumerator.Current;
|
||||
}
|
||||
|
||||
// If there is no previous hitobject, allow the hit.
|
||||
@ -67,13 +72,17 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
if (!hitObjectCanBlockFutureHits(hitObject))
|
||||
return;
|
||||
|
||||
foreach (var obj in enumerateHitObjectsUpTo(hitObject))
|
||||
var enumerator = new HitObjectEnumerator(hitObjectContainer, hitObject.HitObject.StartTime);
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
if (obj.Judged)
|
||||
Debug.Assert(enumerator.Current != null);
|
||||
|
||||
if (enumerator.Current.Judged)
|
||||
continue;
|
||||
|
||||
if (hitObjectCanBlockFutureHits(obj))
|
||||
((DrawableOsuHitObject)obj).MissForcefully();
|
||||
if (hitObjectCanBlockFutureHits(enumerator.Current))
|
||||
((DrawableOsuHitObject)enumerator.Current).MissForcefully();
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,23 +93,89 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
private static bool hitObjectCanBlockFutureHits(DrawableHitObject hitObject)
|
||||
=> hitObject is DrawableHitCircle;
|
||||
|
||||
// Todo: Inefficient
|
||||
private IEnumerable<DrawableHitObject> enumerateHitObjectsUpTo(DrawableHitObject hitObject)
|
||||
private struct HitObjectEnumerator : IEnumerator<DrawableHitObject>
|
||||
{
|
||||
return enumerate(hitObjectContainer.AliveObjects);
|
||||
private readonly IEnumerator<DrawableHitObject> hitObjectEnumerator;
|
||||
private readonly double targetTime;
|
||||
|
||||
IEnumerable<DrawableHitObject> enumerate(IEnumerable<DrawableHitObject> list)
|
||||
private DrawableHitObject currentTopLevel;
|
||||
private int currentNestedIndex;
|
||||
|
||||
public HitObjectEnumerator(HitObjectContainer hitObjectContainer, double targetTime)
|
||||
{
|
||||
foreach (var obj in list)
|
||||
{
|
||||
if (obj.HitObject.StartTime >= hitObject.HitObject.StartTime)
|
||||
yield break;
|
||||
hitObjectEnumerator = hitObjectContainer.AliveObjects.GetEnumerator();
|
||||
this.targetTime = targetTime;
|
||||
|
||||
yield return obj;
|
||||
currentTopLevel = null;
|
||||
currentNestedIndex = -1;
|
||||
Current = null;
|
||||
}
|
||||
|
||||
foreach (var nested in enumerate(obj.NestedHitObjects))
|
||||
yield return nested;
|
||||
}
|
||||
/// <summary>
|
||||
/// Attempts to move to the next top-level or nested hitobject.
|
||||
/// Stops when no such hitobject is found or until the hitobject start time reaches <see cref="targetTime"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether a new hitobject was moved to.</returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
// If we don't already have a top-level hitobject, try to get one.
|
||||
if (currentTopLevel == null)
|
||||
return moveNextTopLevel();
|
||||
|
||||
// If we have a top-level hitobject, try to move to the next nested hitobject or otherwise move to the next top-level hitobject.
|
||||
if (!moveNextNested())
|
||||
return moveNextTopLevel();
|
||||
|
||||
// Guaranteed by moveNextNested() to have a hitobject.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move to the next top-level hitobject.
|
||||
/// </summary>
|
||||
/// <returns>Whether a new top-level hitobject was found.</returns>
|
||||
private bool moveNextTopLevel()
|
||||
{
|
||||
currentNestedIndex = -1;
|
||||
|
||||
hitObjectEnumerator.MoveNext();
|
||||
currentTopLevel = hitObjectEnumerator.Current;
|
||||
|
||||
Current = currentTopLevel;
|
||||
|
||||
return Current?.HitObject.StartTime < targetTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to move to the next nested hitobject in the current top-level hitobject.
|
||||
/// </summary>
|
||||
/// <returns>Whether a new nested hitobject was moved to.</returns>
|
||||
private bool moveNextNested()
|
||||
{
|
||||
currentNestedIndex++;
|
||||
if (currentNestedIndex >= currentTopLevel.NestedHitObjects.Count)
|
||||
return false;
|
||||
|
||||
Current = currentTopLevel.NestedHitObjects[currentNestedIndex];
|
||||
Debug.Assert(Current != null);
|
||||
|
||||
return Current?.HitObject.StartTime < targetTime;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
hitObjectEnumerator.Reset();
|
||||
currentTopLevel = null;
|
||||
currentNestedIndex = -1;
|
||||
Current = null;
|
||||
}
|
||||
|
||||
public DrawableHitObject Current { get; set; }
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user