mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 07:33:20 +08:00
Merge pull request #10717 from smoogipoo/dho-apply
This commit is contained in:
commit
8706b51b77
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1109.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1110.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
44
osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs
Normal file
44
osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneHitCircleApplication : OsuTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestApplyNewCircle()
|
||||
{
|
||||
DrawableHitCircle dho = null;
|
||||
|
||||
AddStep("create circle", () => Child = dho = new DrawableHitCircle(prepareObject(new HitCircle
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
IndexInCurrentCombo = 0
|
||||
}))
|
||||
{
|
||||
Clock = new FramedClock(new StopwatchClock())
|
||||
});
|
||||
|
||||
AddStep("apply new circle", () => dho.Apply(prepareObject(new HitCircle
|
||||
{
|
||||
Position = new Vector2(128, 128),
|
||||
ComboIndex = 1,
|
||||
})));
|
||||
}
|
||||
|
||||
private HitCircle prepareObject(HitCircle circle)
|
||||
{
|
||||
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
return circle;
|
||||
}
|
||||
}
|
||||
}
|
59
osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs
Normal file
59
osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs
Normal file
@ -0,0 +1,59 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneSliderApplication : OsuTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestApplyNewSlider()
|
||||
{
|
||||
DrawableSlider dho = null;
|
||||
|
||||
AddStep("create slider", () => Child = dho = new DrawableSlider(prepareObject(new Slider
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
IndexInCurrentCombo = 0,
|
||||
StartTime = Time.Current,
|
||||
Path = new SliderPath(PathType.Linear, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(150, 100),
|
||||
new Vector2(300, 0),
|
||||
})
|
||||
})));
|
||||
|
||||
AddWaitStep("wait for progression", 1);
|
||||
|
||||
AddStep("apply new slider", () => dho.Apply(prepareObject(new Slider
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
ComboIndex = 1,
|
||||
StartTime = dho.HitObject.StartTime,
|
||||
Path = new SliderPath(PathType.Bezier, new[]
|
||||
{
|
||||
Vector2.Zero,
|
||||
new Vector2(150, 100),
|
||||
new Vector2(300, 0),
|
||||
}),
|
||||
RepeatCount = 1
|
||||
})));
|
||||
}
|
||||
|
||||
private Slider prepareObject(Slider slider)
|
||||
{
|
||||
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
return slider;
|
||||
}
|
||||
}
|
||||
}
|
46
osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs
Normal file
46
osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
public class TestSceneSpinnerApplication : OsuTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestApplyNewCircle()
|
||||
{
|
||||
DrawableSpinner dho = null;
|
||||
|
||||
AddStep("create spinner", () => Child = dho = new DrawableSpinner(prepareObject(new Spinner
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
IndexInCurrentCombo = 0,
|
||||
Duration = 0,
|
||||
}))
|
||||
{
|
||||
Clock = new FramedClock(new StopwatchClock())
|
||||
});
|
||||
|
||||
AddStep("apply new spinner", () => dho.Apply(prepareObject(new Spinner
|
||||
{
|
||||
Position = new Vector2(256, 192),
|
||||
ComboIndex = 1,
|
||||
Duration = 1000,
|
||||
})));
|
||||
}
|
||||
|
||||
private Spinner prepareObject(Spinner circle)
|
||||
{
|
||||
circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||
return circle;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -30,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
private Container scaleContainer;
|
||||
private InputManager inputManager;
|
||||
|
||||
public DrawableHitCircle(HitCircle h)
|
||||
public DrawableHitCircle([CanBeNull] HitCircle h = null)
|
||||
: base(h)
|
||||
{
|
||||
}
|
||||
@ -72,10 +73,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
Size = HitArea.DrawSize;
|
||||
|
||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
||||
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue), true);
|
||||
AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue, true);
|
||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
||||
AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osuTK;
|
||||
|
||||
@ -49,6 +50,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ShakeDuration = 30,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnApply(HitObject hitObject)
|
||||
{
|
||||
base.OnApply(hitObject);
|
||||
|
||||
IndexInCurrentComboBindable.BindTo(HitObject.IndexInCurrentComboBindable);
|
||||
PositionBindable.BindTo(HitObject.PositionBindable);
|
||||
@ -56,6 +62,16 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ScaleBindable.BindTo(HitObject.ScaleBindable);
|
||||
}
|
||||
|
||||
protected override void OnFree(HitObject hitObject)
|
||||
{
|
||||
base.OnFree(hitObject);
|
||||
|
||||
IndexInCurrentComboBindable.UnbindFrom(HitObject.IndexInCurrentComboBindable);
|
||||
PositionBindable.UnbindFrom(HitObject.PositionBindable);
|
||||
StackHeightBindable.UnbindFrom(HitObject.StackHeightBindable);
|
||||
ScaleBindable.UnbindFrom(HitObject.ScaleBindable);
|
||||
}
|
||||
|
||||
// Forward all internal management to shakeContainer.
|
||||
// This is a bit ugly but we don't have the concept of InternalContent so it'll have to do for now. (https://github.com/ppy/osu-framework/issues/1690)
|
||||
protected override void AddInternal(Drawable drawable) => shakeContainer.Add(drawable);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
@ -32,14 +33,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
|
||||
|
||||
public readonly IBindable<int> PathVersion = new Bindable<int>();
|
||||
public IBindable<int> PathVersion => pathVersion;
|
||||
private readonly Bindable<int> pathVersion = new Bindable<int>();
|
||||
|
||||
private Container<DrawableSliderHead> headContainer;
|
||||
private Container<DrawableSliderTail> tailContainer;
|
||||
private Container<DrawableSliderTick> tickContainer;
|
||||
private Container<DrawableSliderRepeat> repeatContainer;
|
||||
|
||||
public DrawableSlider(Slider s)
|
||||
public DrawableSlider([CanBeNull] Slider s = null)
|
||||
: base(s)
|
||||
{
|
||||
}
|
||||
@ -63,11 +65,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
headContainer = new Container<DrawableSliderHead> { RelativeSizeAxes = Axes.Both },
|
||||
};
|
||||
|
||||
PathVersion.BindTo(HitObject.Path.Version);
|
||||
|
||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition, true);
|
||||
ScaleBindable.BindValueChanged(scale => Ball.Scale = new Vector2(scale.NewValue), true);
|
||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||
ScaleBindable.BindValueChanged(scale => Ball.Scale = new Vector2(scale.NewValue));
|
||||
|
||||
AccentColour.BindValueChanged(colour =>
|
||||
{
|
||||
@ -78,6 +78,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
Tracking.BindValueChanged(updateSlidingSample);
|
||||
}
|
||||
|
||||
protected override void OnApply(HitObject hitObject)
|
||||
{
|
||||
base.OnApply(hitObject);
|
||||
|
||||
// Ensure that the version will change after the upcoming BindTo().
|
||||
pathVersion.Value = int.MaxValue;
|
||||
PathVersion.BindTo(HitObject.Path.Version);
|
||||
}
|
||||
|
||||
protected override void OnFree(HitObject hitObject)
|
||||
{
|
||||
base.OnFree(hitObject);
|
||||
|
||||
PathVersion.UnbindFrom(HitObject.Path.Version);
|
||||
}
|
||||
|
||||
private PausableSkinnableSound slidingSample;
|
||||
|
||||
protected override void LoadSamples()
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Bindables;
|
||||
@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
private Bindable<bool> isSpinning;
|
||||
private bool spinnerFrequencyModulate;
|
||||
|
||||
public DrawableSpinner(Spinner s)
|
||||
public DrawableSpinner([CanBeNull] Spinner s = null)
|
||||
: base(s)
|
||||
{
|
||||
}
|
||||
@ -72,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
};
|
||||
|
||||
PositionBindable.BindValueChanged(pos => Position = pos.NewValue, true);
|
||||
PositionBindable.BindValueChanged(pos => Position = pos.NewValue);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
|
@ -1,7 +1,6 @@
|
||||
// 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.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -28,9 +27,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
// suppress locally to allow hiding the visuals wherever necessary.
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Result.Type = Type;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
@ -27,7 +28,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
{
|
||||
public event Action<DrawableHitObject> DefaultsApplied;
|
||||
|
||||
public readonly HitObject HitObject;
|
||||
/// <summary>
|
||||
/// The <see cref="HitObject"/> currently represented by this <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
public HitObject HitObject { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The colour used for various elements of this DrawableHitObject.
|
||||
@ -96,10 +100,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// </remarks>
|
||||
protected virtual float SamplePlaybackPosition => 0.5f;
|
||||
|
||||
private BindableList<HitSampleInfo> samplesBindable;
|
||||
private Bindable<double> startTimeBindable;
|
||||
private Bindable<bool> userPositionalHitSounds;
|
||||
private Bindable<int> comboIndexBindable;
|
||||
private readonly Bindable<double> startTimeBindable = new Bindable<double>();
|
||||
private readonly BindableList<HitSampleInfo> samplesBindable = new BindableList<HitSampleInfo>();
|
||||
private readonly Bindable<bool> userPositionalHitSounds = new Bindable<bool>();
|
||||
private readonly Bindable<int> comboIndexBindable = new Bindable<int>();
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
@ -111,52 +115,157 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
public IBindable<ArmedState> State => state;
|
||||
|
||||
protected DrawableHitObject([NotNull] HitObject hitObject)
|
||||
/// <summary>
|
||||
/// Whether <see cref="HitObject"/> is currently applied.
|
||||
/// </summary>
|
||||
private bool hasHitObjectApplied;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="initialHitObject">
|
||||
/// The <see cref="HitObject"/> to be initially applied to this <see cref="DrawableHitObject"/>.
|
||||
/// If <c>null</c>, a hitobject is expected to be later applied via <see cref="Apply"/> (or automatically via pooling).
|
||||
/// </param>
|
||||
protected DrawableHitObject([CanBeNull] HitObject initialHitObject = null)
|
||||
{
|
||||
HitObject = hitObject ?? throw new ArgumentNullException(nameof(hitObject));
|
||||
HitObject = initialHitObject;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
userPositionalHitSounds = config.GetBindable<bool>(OsuSetting.PositionalHitSounds);
|
||||
var judgement = HitObject.CreateJudgement();
|
||||
|
||||
Result = CreateResult(judgement);
|
||||
if (Result == null)
|
||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||
config.BindWith(OsuSetting.PositionalHitSounds, userPositionalHitSounds);
|
||||
}
|
||||
|
||||
protected override void LoadAsyncComplete()
|
||||
{
|
||||
base.LoadAsyncComplete();
|
||||
|
||||
LoadSamples();
|
||||
|
||||
HitObject.DefaultsApplied += onDefaultsApplied;
|
||||
|
||||
startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy();
|
||||
startTimeBindable.BindValueChanged(_ => updateState(State.Value, true));
|
||||
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
{
|
||||
comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy();
|
||||
comboIndexBindable.BindValueChanged(_ => updateComboColour(), true);
|
||||
}
|
||||
|
||||
samplesBindable = HitObject.SamplesBindable.GetBoundCopy();
|
||||
samplesBindable.CollectionChanged += (_, __) => LoadSamples();
|
||||
|
||||
apply(HitObject);
|
||||
if (HitObject != null)
|
||||
Apply(HitObject);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
startTimeBindable.BindValueChanged(_ => updateState(State.Value, true));
|
||||
comboIndexBindable.BindValueChanged(_ => updateComboColour(), true);
|
||||
|
||||
updateState(ArmedState.Idle, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a new <see cref="HitObject"/> to be represented by this <see cref="DrawableHitObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The <see cref="HitObject"/> to apply.</param>
|
||||
public void Apply(HitObject hitObject)
|
||||
{
|
||||
free();
|
||||
|
||||
HitObject = hitObject ?? throw new InvalidOperationException($"Cannot apply a null {nameof(HitObject)}.");
|
||||
|
||||
// Ensure this DHO has a result.
|
||||
Result ??= CreateResult(HitObject.CreateJudgement())
|
||||
?? throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||
|
||||
foreach (var h in HitObject.NestedHitObjects)
|
||||
{
|
||||
var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}.");
|
||||
|
||||
drawableNested.OnNewResult += onNewResult;
|
||||
drawableNested.OnRevertResult += onRevertResult;
|
||||
drawableNested.ApplyCustomUpdateState += onApplyCustomUpdateState;
|
||||
|
||||
nestedHitObjects.Value.Add(drawableNested);
|
||||
AddNestedHitObject(drawableNested);
|
||||
}
|
||||
|
||||
startTimeBindable.BindTo(HitObject.StartTimeBindable);
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
comboIndexBindable.BindTo(combo.ComboIndexBindable);
|
||||
|
||||
samplesBindable.BindTo(HitObject.SamplesBindable);
|
||||
samplesBindable.BindCollectionChanged(onSamplesChanged, true);
|
||||
|
||||
HitObject.DefaultsApplied += onDefaultsApplied;
|
||||
|
||||
OnApply(hitObject);
|
||||
|
||||
// If not loaded, the state update happens in LoadComplete(). Otherwise, the update is scheduled to allow for lifetime updates.
|
||||
if (IsLoaded)
|
||||
Schedule(() => updateState(ArmedState.Idle, true));
|
||||
|
||||
hasHitObjectApplied = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the currently applied <see cref="HitObject"/>
|
||||
/// </summary>
|
||||
private void free()
|
||||
{
|
||||
if (!hasHitObjectApplied)
|
||||
return;
|
||||
|
||||
startTimeBindable.UnbindFrom(HitObject.StartTimeBindable);
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
comboIndexBindable.UnbindFrom(combo.ComboIndexBindable);
|
||||
|
||||
samplesBindable.UnbindFrom(HitObject.SamplesBindable);
|
||||
|
||||
// When a new hitobject is applied, the samples will be cleared before re-populating.
|
||||
// In order to stop this needless update, the event is unbound and re-bound as late as possible in Apply().
|
||||
samplesBindable.CollectionChanged -= onSamplesChanged;
|
||||
|
||||
if (nestedHitObjects.IsValueCreated)
|
||||
{
|
||||
foreach (var obj in nestedHitObjects.Value)
|
||||
{
|
||||
obj.OnNewResult -= onNewResult;
|
||||
obj.OnRevertResult -= onRevertResult;
|
||||
obj.ApplyCustomUpdateState -= onApplyCustomUpdateState;
|
||||
}
|
||||
|
||||
nestedHitObjects.Value.Clear();
|
||||
ClearNestedHitObjects();
|
||||
}
|
||||
|
||||
HitObject.DefaultsApplied -= onDefaultsApplied;
|
||||
|
||||
OnFree(HitObject);
|
||||
|
||||
HitObject = null;
|
||||
hasHitObjectApplied = false;
|
||||
}
|
||||
|
||||
protected sealed override void FreeAfterUse()
|
||||
{
|
||||
base.FreeAfterUse();
|
||||
|
||||
// Freeing while not in a pool would cause the DHO to not be usable elsewhere in the hierarchy without being re-applied.
|
||||
if (!IsInPool)
|
||||
return;
|
||||
|
||||
free();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked for this <see cref="DrawableHitObject"/> to take on any values from a newly-applied <see cref="HitObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The <see cref="HitObject"/> being applied.</param>
|
||||
protected virtual void OnApply(HitObject hitObject)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked for this <see cref="DrawableHitObject"/> to revert any values previously taken on from the currently-applied <see cref="HitObject"/>.
|
||||
/// </summary>
|
||||
/// <param name="hitObject">The currently-applied <see cref="HitObject"/>.</param>
|
||||
protected virtual void OnFree(HitObject hitObject)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked by the base <see cref="DrawableHitObject"/> to populate samples, once on initial load and potentially again on any change to the samples collection.
|
||||
/// </summary>
|
||||
@ -183,34 +292,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
AddInternal(Samples);
|
||||
}
|
||||
|
||||
private void onSamplesChanged(object sender, NotifyCollectionChangedEventArgs e) => LoadSamples();
|
||||
|
||||
private void onNewResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnNewResult?.Invoke(drawableHitObject, result);
|
||||
|
||||
private void onRevertResult(DrawableHitObject drawableHitObject, JudgementResult result) => OnRevertResult?.Invoke(drawableHitObject, result);
|
||||
|
||||
private void onApplyCustomUpdateState(DrawableHitObject drawableHitObject, ArmedState state) => ApplyCustomUpdateState?.Invoke(drawableHitObject, state);
|
||||
|
||||
private void onDefaultsApplied(HitObject hitObject)
|
||||
{
|
||||
apply(hitObject);
|
||||
updateState(state.Value, true);
|
||||
Apply(hitObject);
|
||||
DefaultsApplied?.Invoke(this);
|
||||
}
|
||||
|
||||
private void apply(HitObject hitObject)
|
||||
{
|
||||
if (nestedHitObjects.IsValueCreated)
|
||||
{
|
||||
nestedHitObjects.Value.Clear();
|
||||
ClearNestedHitObjects();
|
||||
}
|
||||
|
||||
foreach (var h in hitObject.NestedHitObjects)
|
||||
{
|
||||
var drawableNested = CreateNestedHitObject(h) ?? throw new InvalidOperationException($"{nameof(CreateNestedHitObject)} returned null for {h.GetType().ReadableName()}.");
|
||||
|
||||
drawableNested.OnNewResult += (d, r) => OnNewResult?.Invoke(d, r);
|
||||
drawableNested.OnRevertResult += (d, r) => OnRevertResult?.Invoke(d, r);
|
||||
drawableNested.ApplyCustomUpdateState += (d, j) => ApplyCustomUpdateState?.Invoke(d, j);
|
||||
|
||||
nestedHitObjects.Value.Add(drawableNested);
|
||||
AddNestedHitObject(drawableNested);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked by the base <see cref="DrawableHitObject"/> to add nested <see cref="DrawableHitObject"/>s to the hierarchy.
|
||||
/// </summary>
|
||||
@ -600,19 +695,20 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
HitObject.DefaultsApplied -= onDefaultsApplied;
|
||||
|
||||
if (HitObject != null)
|
||||
HitObject.DefaultsApplied -= onDefaultsApplied;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DrawableHitObject<TObject> : DrawableHitObject
|
||||
where TObject : HitObject
|
||||
{
|
||||
public new readonly TObject HitObject;
|
||||
public new TObject HitObject => (TObject)base.HitObject;
|
||||
|
||||
protected DrawableHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,14 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
|
||||
namespace osu.Game.Skinning
|
||||
{
|
||||
/// <summary>
|
||||
/// A drawable which has a callback when the skin changes.
|
||||
/// </summary>
|
||||
public abstract class SkinReloadableDrawable : CompositeDrawable
|
||||
public abstract class SkinReloadableDrawable : PoolableDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when <see cref="CurrentSkin"/> has changed.
|
||||
|
@ -26,7 +26,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1109.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1110.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
||||
<PackageReference Include="Sentry" Version="2.1.6" />
|
||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||
|
@ -70,7 +70,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1109.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1110.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1030.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||
@ -88,7 +88,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1109.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2020.1110.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user