2021-07-08 15:40:32 +08:00
|
|
|
// 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;
|
|
|
|
using osu.Framework.Bindables;
|
2021-07-08 15:56:16 +08:00
|
|
|
using osu.Game.Beatmaps;
|
2021-07-08 15:40:32 +08:00
|
|
|
|
|
|
|
namespace osu.Game.Rulesets.Mods
|
|
|
|
{
|
|
|
|
public class DifficultyBindable : Bindable<float?>
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Whether the extended limits should be applied to this bindable.
|
|
|
|
/// </summary>
|
2021-07-09 12:24:26 +08:00
|
|
|
public readonly BindableBool ExtendedLimits = new BindableBool();
|
2021-07-08 15:40:32 +08:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// An internal numeric bindable to hold and propagate min/max/precision.
|
|
|
|
/// The value of this bindable should not be set.
|
|
|
|
/// </summary>
|
2021-07-12 10:26:30 +08:00
|
|
|
internal readonly BindableFloat CurrentNumber = new BindableFloat
|
2021-07-08 15:40:32 +08:00
|
|
|
{
|
|
|
|
MinValue = 0,
|
|
|
|
MaxValue = 10,
|
|
|
|
};
|
|
|
|
|
2021-07-08 15:56:16 +08:00
|
|
|
/// <summary>
|
|
|
|
/// A function that can extract the current value of this setting from a beatmap difficulty for display purposes.
|
|
|
|
/// </summary>
|
2021-07-09 12:24:26 +08:00
|
|
|
public Func<BeatmapDifficulty, float> ReadCurrentFromDifficulty;
|
2021-07-08 15:56:16 +08:00
|
|
|
|
2021-07-08 15:40:32 +08:00
|
|
|
public float Precision
|
|
|
|
{
|
|
|
|
set => CurrentNumber.Precision = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public float MinValue
|
|
|
|
{
|
|
|
|
set => CurrentNumber.MinValue = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private float maxValue;
|
|
|
|
|
|
|
|
public float MaxValue
|
|
|
|
{
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (value == maxValue)
|
|
|
|
return;
|
|
|
|
|
|
|
|
maxValue = value;
|
|
|
|
updateMaxValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private float? extendedMaxValue;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// The maximum value to be used when extended limits are applied.
|
|
|
|
/// </summary>
|
|
|
|
public float? ExtendedMaxValue
|
|
|
|
{
|
|
|
|
set
|
|
|
|
{
|
|
|
|
if (value == extendedMaxValue)
|
|
|
|
return;
|
|
|
|
|
|
|
|
extendedMaxValue = value;
|
|
|
|
updateMaxValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public DifficultyBindable()
|
2021-07-12 15:52:57 +08:00
|
|
|
: this(null)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public DifficultyBindable(float? defaultValue = null)
|
|
|
|
: base(defaultValue)
|
2021-07-08 15:40:32 +08:00
|
|
|
{
|
|
|
|
ExtendedLimits.BindValueChanged(_ => updateMaxValue());
|
2021-07-08 16:40:09 +08:00
|
|
|
}
|
2021-07-08 15:40:32 +08:00
|
|
|
|
2021-07-08 16:40:09 +08:00
|
|
|
public override float? Value
|
|
|
|
{
|
|
|
|
get => base.Value;
|
|
|
|
set
|
2021-07-08 15:40:32 +08:00
|
|
|
{
|
|
|
|
// Ensure that in the case serialisation runs in the wrong order (and limit extensions aren't applied yet) the deserialised value is still propagated.
|
2021-07-08 16:40:09 +08:00
|
|
|
if (value != null)
|
|
|
|
CurrentNumber.MaxValue = MathF.Max(CurrentNumber.MaxValue, value.Value);
|
|
|
|
|
|
|
|
base.Value = value;
|
|
|
|
}
|
2021-07-08 15:40:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void updateMaxValue()
|
|
|
|
{
|
|
|
|
CurrentNumber.MaxValue = ExtendedLimits.Value && extendedMaxValue != null ? extendedMaxValue.Value : maxValue;
|
|
|
|
}
|
2021-07-11 21:12:46 +08:00
|
|
|
|
2021-07-12 15:52:57 +08:00
|
|
|
public override void BindTo(Bindable<float?> them)
|
2021-07-11 21:12:46 +08:00
|
|
|
{
|
2021-07-12 15:52:57 +08:00
|
|
|
if (!(them is DifficultyBindable otherDifficultyBindable))
|
|
|
|
throw new InvalidOperationException($"Cannot bind to a non-{nameof(DifficultyBindable)}.");
|
|
|
|
|
|
|
|
ReadCurrentFromDifficulty = otherDifficultyBindable.ReadCurrentFromDifficulty;
|
|
|
|
|
2021-07-13 04:25:33 +08:00
|
|
|
// the following max value copies are only safe as long as these values are effectively constants.
|
2021-07-12 15:52:57 +08:00
|
|
|
MaxValue = otherDifficultyBindable.maxValue;
|
|
|
|
ExtendedMaxValue = otherDifficultyBindable.extendedMaxValue;
|
2021-07-13 04:25:33 +08:00
|
|
|
|
|
|
|
ExtendedLimits.BindTarget = otherDifficultyBindable.ExtendedLimits;
|
|
|
|
|
|
|
|
// the actual values need to be copied after the max value constraints.
|
|
|
|
CurrentNumber.BindTarget = otherDifficultyBindable.CurrentNumber;
|
|
|
|
base.BindTo(them);
|
2021-07-12 15:52:57 +08:00
|
|
|
}
|
|
|
|
|
2021-07-12 16:33:29 +08:00
|
|
|
public override void UnbindFrom(IUnbindable them)
|
|
|
|
{
|
|
|
|
if (!(them is DifficultyBindable otherDifficultyBindable))
|
|
|
|
throw new InvalidOperationException($"Cannot unbind from a non-{nameof(DifficultyBindable)}.");
|
|
|
|
|
|
|
|
base.UnbindFrom(them);
|
|
|
|
|
|
|
|
CurrentNumber.UnbindFrom(otherDifficultyBindable.CurrentNumber);
|
|
|
|
ExtendedLimits.UnbindFrom(otherDifficultyBindable.ExtendedLimits);
|
|
|
|
}
|
|
|
|
|
2021-07-12 15:52:57 +08:00
|
|
|
public new DifficultyBindable GetBoundCopy() => new DifficultyBindable { BindTarget = this };
|
2021-07-08 15:40:32 +08:00
|
|
|
}
|
|
|
|
}
|