mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 07:06:35 +09:00
Merge remote-tracking branch 'origin/Liswiera-FL-changes' into Liswiera-FL-changes
This commit is contained in:
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
protected const int ATTRIB_ID_OVERALL_DIFFICULTY = 5;
|
||||
protected const int ATTRIB_ID_APPROACH_RATE = 7;
|
||||
protected const int ATTRIB_ID_MAX_COMBO = 9;
|
||||
protected const int ATTRIB_ID_STRAIN = 11;
|
||||
protected const int ATTRIB_ID_DIFFICULTY = 11;
|
||||
protected const int ATTRIB_ID_GREAT_HIT_WINDOW = 13;
|
||||
protected const int ATTRIB_ID_SCORE_MULTIPLIER = 15;
|
||||
protected const int ATTRIB_ID_FLASHLIGHT = 17;
|
||||
|
@ -120,14 +120,14 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
/// Calculates the difficulty of the beatmap using all mod combinations applicable to the beatmap.
|
||||
/// </summary>
|
||||
/// <returns>A collection of structures describing the difficulty of the beatmap for each mod combination.</returns>
|
||||
public IEnumerable<DifficultyAttributes> CalculateAll()
|
||||
public IEnumerable<DifficultyAttributes> CalculateAll(CancellationToken cancellationToken = default)
|
||||
{
|
||||
foreach (var combination in CreateDifficultyAdjustmentModCombinations())
|
||||
{
|
||||
if (combination is MultiMod multi)
|
||||
yield return Calculate(multi.Mods);
|
||||
yield return Calculate(multi.Mods, cancellationToken);
|
||||
else
|
||||
yield return Calculate(combination.Yield());
|
||||
yield return Calculate(combination.Yield(), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +145,11 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
playableMods = mods.Select(m => m.DeepClone()).ToArray();
|
||||
|
||||
Beatmap = beatmap.GetPlayableBeatmap(ruleset, playableMods, cancellationToken);
|
||||
// Only pass through the cancellation token if it's non-default.
|
||||
// This allows for the default timeout to be applied for playable beatmap construction.
|
||||
Beatmap = cancellationToken == default
|
||||
? beatmap.GetPlayableBeatmap(ruleset, playableMods)
|
||||
: beatmap.GetPlayableBeatmap(ruleset, playableMods, cancellationToken);
|
||||
|
||||
var track = new TrackVirtual(10000);
|
||||
playableMods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
|
||||
|
16
osu.Game/Rulesets/Difficulty/PerformanceAttributes.cs
Normal file
16
osu.Game/Rulesets/Difficulty/PerformanceAttributes.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
public class PerformanceAttributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculated score performance points.
|
||||
/// </summary>
|
||||
[JsonProperty("pp")]
|
||||
public double Total { get; set; }
|
||||
}
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
@ -37,6 +36,6 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
TimeRate = track.Rate;
|
||||
}
|
||||
|
||||
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);
|
||||
public abstract PerformanceAttributes Calculate();
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Play.PlayerSettings;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Game.Rulesets.Edit
|
||||
{
|
||||
public class ToolboxGroup : PlayerSettingsGroup
|
||||
public class EditorToolboxGroup : SettingsToolboxGroup
|
||||
{
|
||||
public ToolboxGroup(string title)
|
||||
public EditorToolboxGroup(string title)
|
||||
: base(title)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
@ -13,6 +13,7 @@ using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
@ -80,7 +81,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Config = Dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
|
||||
Config = Dependencies.Get<IRulesetConfigCache>().GetConfigFor(Ruleset);
|
||||
|
||||
try
|
||||
{
|
||||
@ -98,14 +99,11 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
dependencies.CacheAs(Playfield);
|
||||
|
||||
const float toolbar_width = 200;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Name = "Content",
|
||||
Padding = new MarginPadding { Left = toolbar_width },
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -117,20 +115,15 @@ namespace osu.Game.Rulesets.Edit
|
||||
.WithChild(BlueprintContainer = CreateBlueprintContainer())
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
new LeftToolboxFlow
|
||||
{
|
||||
Name = "Sidebar",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = toolbar_width,
|
||||
Padding = new MarginPadding { Right = 10 },
|
||||
Spacing = new Vector2(10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ToolboxGroup("toolbox (1-9)")
|
||||
new EditorToolboxGroup("toolbox (1-9)")
|
||||
{
|
||||
Child = toolboxCollection = new EditorRadioButtonCollection { RelativeSizeAxes = Axes.X }
|
||||
},
|
||||
new ToolboxGroup("toggles (Q~P)")
|
||||
new EditorToolboxGroup("toggles (Q~P)")
|
||||
{
|
||||
Child = togglesCollection = new FillFlowContainer
|
||||
{
|
||||
@ -427,6 +420,18 @@ namespace osu.Game.Rulesets.Edit
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class LeftToolboxFlow : ExpandingButtonContainer
|
||||
{
|
||||
public LeftToolboxFlow()
|
||||
: base(80, 200)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Padding = new MarginPadding { Right = 10 };
|
||||
|
||||
FillFlow.Spacing = new Vector2(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -7,7 +7,7 @@ using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Rulesets.Edit
|
||||
{
|
||||
public class ScrollingToolboxGroup : ToolboxGroup
|
||||
public class ScrollingToolboxGroup : EditorToolboxGroup
|
||||
{
|
||||
protected readonly OsuScrollContainer Scroll;
|
||||
|
||||
|
23
osu.Game/Rulesets/IRulesetConfigCache.cs
Normal file
23
osu.Game/Rulesets/IRulesetConfigCache.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
#nullable enable
|
||||
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache that provides a single <see cref="IRulesetConfigManager"/> per-ruleset.
|
||||
/// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings.
|
||||
/// </summary>
|
||||
public interface IRulesetConfigCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="IRulesetConfigManager"/> for a <see cref="Ruleset"/>.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The <see cref="Ruleset"/> to retrieve the <see cref="IRulesetConfigManager"/> for.</param>
|
||||
/// <returns>The <see cref="IRulesetConfigManager"/> defined by <paramref name="ruleset"/>, null if <paramref name="ruleset"/> doesn't define one.</returns>
|
||||
public IRulesetConfigManager? GetConfigFor(Ruleset ruleset);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// 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.Game.Database;
|
||||
|
||||
#nullable enable
|
||||
@ -10,7 +11,7 @@ namespace osu.Game.Rulesets
|
||||
/// <summary>
|
||||
/// A representation of a ruleset's metadata.
|
||||
/// </summary>
|
||||
public interface IRulesetInfo : IHasOnlineID<int>
|
||||
public interface IRulesetInfo : IHasOnlineID<int>, IEquatable<IRulesetInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// The user-exposed name of this ruleset.
|
||||
|
31
osu.Game/Rulesets/IRulesetStore.cs
Normal file
31
osu.Game/Rulesets/IRulesetStore.cs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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.Generic;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
public interface IRulesetStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieve a ruleset using a known ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ruleset's internal ID.</param>
|
||||
/// <returns>A ruleset, if available, else null.</returns>
|
||||
IRulesetInfo? GetRuleset(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a ruleset using a known short name.
|
||||
/// </summary>
|
||||
/// <param name="shortName">The ruleset's short name.</param>
|
||||
/// <returns>A ruleset, if available, else null.</returns>
|
||||
IRulesetInfo? GetRuleset(string shortName);
|
||||
|
||||
/// <summary>
|
||||
/// All available rulesets.
|
||||
/// </summary>
|
||||
IEnumerable<IRulesetInfo> AvailableRulesets { get; }
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
public void ApplyToHUD(HUDOverlay overlay)
|
||||
{
|
||||
overlay.ShowHealthbar.BindTo(showHealthBar);
|
||||
overlay.ShowHealthBar.BindTo(showHealthBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Mods
|
||||
drawableRuleset.SetReplayScore(CreateReplayScore(drawableRuleset.Beatmap, drawableRuleset.Mods));
|
||||
|
||||
// AlwaysPresent required for hitsounds
|
||||
drawableRuleset.Playfield.AlwaysPresent = true;
|
||||
drawableRuleset.Playfield.Hide();
|
||||
drawableRuleset.AlwaysPresent = true;
|
||||
drawableRuleset.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public override string Name => "Double Time";
|
||||
public override string Acronym => "DT";
|
||||
public override IconUsage? Icon => OsuIcon.ModDoubletime;
|
||||
public override IconUsage? Icon => OsuIcon.ModDoubleTime;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Zoooooooooom...";
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public override string Name => "Hard Rock";
|
||||
public override string Acronym => "HR";
|
||||
public override IconUsage? Icon => OsuIcon.ModHardrock;
|
||||
public override IconUsage? Icon => OsuIcon.ModHardRock;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Everything just got a bit harder...";
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust) };
|
||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public override string Name => "No Fail";
|
||||
public override string Acronym => "NF";
|
||||
public override IconUsage? Icon => OsuIcon.ModNofail;
|
||||
public override IconUsage? Icon => OsuIcon.ModNoFail;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => "You can't fail, no matter what.";
|
||||
public override double ScoreMultiplier => 0.5;
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
{
|
||||
public override string Name => "Sudden Death";
|
||||
public override string Acronym => "SD";
|
||||
public override IconUsage? Icon => OsuIcon.ModSuddendeath;
|
||||
public override IconUsage? Icon => OsuIcon.ModSuddenDeath;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Miss and fail.";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
@ -123,9 +123,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
public 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>();
|
||||
|
||||
private readonly Bindable<float> positionalHitsoundsLevel = new Bindable<float>();
|
||||
private readonly Bindable<int> comboIndexWithOffsetsBindable = new Bindable<int>();
|
||||
|
||||
protected override bool RequiresChildrenUpdate => true;
|
||||
@ -168,7 +168,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config, ISkinSource skinSource)
|
||||
{
|
||||
config.BindWith(OsuSetting.PositionalHitSounds, userPositionalHitSounds);
|
||||
config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel);
|
||||
|
||||
// Explicit non-virtual function call.
|
||||
base.AddInternal(Samples = new PausableSkinnableSound());
|
||||
@ -532,9 +532,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// <param name="position">The lookup X position. Generally should be <see cref="SamplePlaybackPosition"/>.</param>
|
||||
protected double CalculateSamplePlaybackBalance(double position)
|
||||
{
|
||||
const float balance_adjust_amount = 0.4f;
|
||||
float balanceAdjustAmount = positionalHitsoundsLevel.Value * 2;
|
||||
double returnedValue = balanceAdjustAmount * (position - 0.5f);
|
||||
|
||||
return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
|
||||
return returnedValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -87,23 +87,6 @@ namespace osu.Game.Rulesets.Objects
|
||||
[JsonIgnore]
|
||||
public SlimReadOnlyListWrapper<HitObject> NestedHitObjects => nestedHitObjects.AsSlimReadOnly();
|
||||
|
||||
public HitObject()
|
||||
{
|
||||
StartTimeBindable.ValueChanged += time =>
|
||||
{
|
||||
double offset = time.NewValue - time.OldValue;
|
||||
|
||||
foreach (var nested in nestedHitObjects)
|
||||
nested.StartTime += offset;
|
||||
|
||||
if (DifficultyControlPoint != DifficultyControlPoint.DEFAULT)
|
||||
DifficultyControlPoint.Time = time.NewValue;
|
||||
|
||||
if (SampleControlPoint != SampleControlPoint.DEFAULT)
|
||||
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies default values to this HitObject.
|
||||
/// </summary>
|
||||
@ -115,24 +98,22 @@ namespace osu.Game.Rulesets.Objects
|
||||
var legacyInfo = controlPointInfo as LegacyControlPointInfo;
|
||||
|
||||
if (legacyInfo != null)
|
||||
{
|
||||
DifficultyControlPoint = (DifficultyControlPoint)legacyInfo.DifficultyPointAt(StartTime).DeepClone();
|
||||
DifficultyControlPoint.Time = StartTime;
|
||||
}
|
||||
else if (DifficultyControlPoint == DifficultyControlPoint.DEFAULT)
|
||||
DifficultyControlPoint = new DifficultyControlPoint();
|
||||
|
||||
DifficultyControlPoint.Time = StartTime;
|
||||
|
||||
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||
|
||||
// This is done here after ApplyDefaultsToSelf as we may require custom defaults to be applied to have an accurate end time.
|
||||
if (legacyInfo != null)
|
||||
{
|
||||
SampleControlPoint = (SampleControlPoint)legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency).DeepClone();
|
||||
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
||||
}
|
||||
else if (SampleControlPoint == SampleControlPoint.DEFAULT)
|
||||
SampleControlPoint = new SampleControlPoint();
|
||||
|
||||
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
||||
|
||||
nestedHitObjects.Clear();
|
||||
|
||||
CreateNestedHitObjects(cancellationToken);
|
||||
@ -155,7 +136,28 @@ namespace osu.Game.Rulesets.Objects
|
||||
foreach (var h in nestedHitObjects)
|
||||
h.ApplyDefaults(controlPointInfo, difficulty, cancellationToken);
|
||||
|
||||
// `ApplyDefaults()` may be called multiple times on a single hitobject.
|
||||
// to prevent subscribing to `StartTimeBindable.ValueChanged` multiple times with the same callback,
|
||||
// remove the previous subscription (if present) before (re-)registering.
|
||||
StartTimeBindable.ValueChanged -= onStartTimeChanged;
|
||||
|
||||
// this callback must be (re-)registered after default application
|
||||
// to ensure that the read of `this.GetEndTime()` within `onStartTimeChanged` doesn't return an invalid value
|
||||
// if `StartTimeBindable` is changed prior to default application.
|
||||
StartTimeBindable.ValueChanged += onStartTimeChanged;
|
||||
|
||||
DefaultsApplied?.Invoke(this);
|
||||
|
||||
void onStartTimeChanged(ValueChangedEvent<double> time)
|
||||
{
|
||||
double offset = time.NewValue - time.OldValue;
|
||||
|
||||
foreach (var nested in nestedHitObjects)
|
||||
nested.StartTime += offset;
|
||||
|
||||
DifficultyControlPoint.Time = time.NewValue;
|
||||
SampleControlPoint.Time = this.GetEndTime() + control_point_leniency;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty)
|
||||
|
@ -188,12 +188,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
string[] split = str.Split(':');
|
||||
|
||||
var bank = (LegacySampleBank)Parsing.ParseInt(split[0]);
|
||||
var addbank = (LegacySampleBank)Parsing.ParseInt(split[1]);
|
||||
var addBank = (LegacySampleBank)Parsing.ParseInt(split[1]);
|
||||
|
||||
string stringBank = bank.ToString().ToLowerInvariant();
|
||||
if (stringBank == @"none")
|
||||
stringBank = null;
|
||||
string stringAddBank = addbank.ToString().ToLowerInvariant();
|
||||
string stringAddBank = addBank.ToString().ToLowerInvariant();
|
||||
if (stringAddBank == @"none")
|
||||
stringAddBank = null;
|
||||
|
||||
|
@ -250,13 +250,13 @@ namespace osu.Game.Rulesets.Objects
|
||||
if (subControlPoints.Length != 3)
|
||||
break;
|
||||
|
||||
List<Vector2> subpath = PathApproximator.ApproximateCircularArc(subControlPoints);
|
||||
List<Vector2> subPath = PathApproximator.ApproximateCircularArc(subControlPoints);
|
||||
|
||||
// If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation.
|
||||
if (subpath.Count == 0)
|
||||
if (subPath.Count == 0)
|
||||
break;
|
||||
|
||||
return subpath;
|
||||
return subPath;
|
||||
|
||||
case PathType.Catmull:
|
||||
return PathApproximator.ApproximateCatmull(subControlPoints);
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osuTK;
|
||||
|
||||
@ -11,6 +12,15 @@ namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public static class SliderPathExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Snaps the provided <paramref name="hitObject"/>'s duration using the <paramref name="snapProvider"/>.
|
||||
/// </summary>
|
||||
public static void SnapTo<THitObject>(this THitObject hitObject, IPositionSnapProvider? snapProvider)
|
||||
where THitObject : HitObject, IHasPath
|
||||
{
|
||||
hitObject.Path.ExpectedDistance.Value = snapProvider?.GetSnappedDistanceFromDistance(hitObject, (float)hitObject.Path.CalculatedDistance) ?? hitObject.Path.CalculatedDistance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverse the direction of this path.
|
||||
/// </summary>
|
||||
|
@ -6,15 +6,12 @@ using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Rulesets.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache that provides a single <see cref="IRulesetConfigManager"/> per-ruleset.
|
||||
/// This is done to support referring to and updating ruleset configs from multiple locations in the absence of inter-config bindings.
|
||||
/// </summary>
|
||||
public class RulesetConfigCache : Component
|
||||
public class RulesetConfigCache : Component, IRulesetConfigCache
|
||||
{
|
||||
private readonly RealmContextFactory realmFactory;
|
||||
private readonly RulesetStore rulesets;
|
||||
@ -43,18 +40,13 @@ namespace osu.Game.Rulesets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the <see cref="IRulesetConfigManager"/> for a <see cref="Ruleset"/>.
|
||||
/// </summary>
|
||||
/// <param name="ruleset">The <see cref="Ruleset"/> to retrieve the <see cref="IRulesetConfigManager"/> for.</param>
|
||||
/// <returns>The <see cref="IRulesetConfigManager"/> defined by <paramref name="ruleset"/>, null if <paramref name="ruleset"/> doesn't define one.</returns>
|
||||
/// <exception cref="InvalidOperationException">If <paramref name="ruleset"/> doesn't have a valid <see cref="RulesetInfo.ID"/>.</exception>
|
||||
public IRulesetConfigManager GetConfigFor(Ruleset ruleset)
|
||||
{
|
||||
if (!IsLoaded)
|
||||
throw new InvalidOperationException($@"Cannot retrieve {nameof(IRulesetConfigManager)} before {nameof(RulesetConfigCache)} has loaded");
|
||||
|
||||
if (!configCache.TryGetValue(ruleset.RulesetInfo.ShortName, out var config))
|
||||
// any ruleset request which wasn't initialised on startup should not be stored to realm.
|
||||
// this should only be used by tests.
|
||||
return ruleset.CreateConfig(null);
|
||||
throw new InvalidOperationException($@"Attempted to retrieve {nameof(IRulesetConfigManager)} for an unavailable ruleset {ruleset.GetDisplayString()}");
|
||||
|
||||
return config;
|
||||
}
|
||||
|
@ -49,6 +49,8 @@ namespace osu.Game.Rulesets
|
||||
|
||||
public override bool Equals(object obj) => obj is RulesetInfo rulesetInfo && Equals(rulesetInfo);
|
||||
|
||||
public bool Equals(IRulesetInfo other) => other is RulesetInfo b && Equals(b);
|
||||
|
||||
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
|
||||
public override int GetHashCode()
|
||||
{
|
||||
|
@ -13,7 +13,7 @@ using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
public class RulesetStore : DatabaseBackedStore, IDisposable
|
||||
public class RulesetStore : DatabaseBackedStore, IRulesetStore, IDisposable
|
||||
{
|
||||
private const string ruleset_library_prefix = "osu.Game.Rulesets";
|
||||
|
||||
@ -236,5 +236,13 @@ namespace osu.Game.Rulesets
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetDependencyAssembly;
|
||||
}
|
||||
|
||||
#region Implementation of IRulesetStore
|
||||
|
||||
IRulesetInfo IRulesetStore.GetRuleset(int id) => GetRuleset(id);
|
||||
IRulesetInfo IRulesetStore.GetRuleset(string shortName) => GetRuleset(shortName);
|
||||
IEnumerable<IRulesetInfo> IRulesetStore.AvailableRulesets => AvailableRulesets;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
if (result == null)
|
||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||
|
||||
result.Type = judgement.MaxResult;
|
||||
result.Type = GetSimulatedHitResult(judgement);
|
||||
ApplyResult(result);
|
||||
}
|
||||
}
|
||||
@ -145,5 +145,12 @@ namespace osu.Game.Rulesets.Scoring
|
||||
base.Update();
|
||||
hasCompleted.Value = JudgedHits == MaxHits && (JudgedHits == 0 || lastAppliedResult.TimeAbsolute < Clock.CurrentTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a simulated <see cref="HitResult"/> for a judgement. Used during <see cref="SimulateAutoplay"/> to simulate a "perfect" play.
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement to simulate a <see cref="HitResult"/> for.</param>
|
||||
/// <returns>The simulated <see cref="HitResult"/> for the judgement.</returns>
|
||||
protected virtual HitResult GetSimulatedHitResult(Judgement judgement) => judgement.MaxResult;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.UI
|
||||
CacheAs(ShaderManager = new FallbackShaderManager(ShaderManager, parent.Get<ShaderManager>()));
|
||||
}
|
||||
|
||||
RulesetConfigManager = parent.Get<RulesetConfigCache>().GetConfigFor(ruleset);
|
||||
RulesetConfigManager = parent.Get<IRulesetConfigCache>().GetConfigFor(ruleset);
|
||||
if (RulesetConfigManager != null)
|
||||
Cache(RulesetConfigManager);
|
||||
}
|
||||
@ -115,7 +116,7 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
public Sample Get(string name) => primary.Get(name) ?? fallback.Get(name);
|
||||
|
||||
public Task<Sample> GetAsync(string name) => primary.GetAsync(name) ?? fallback.GetAsync(name);
|
||||
public Task<Sample> GetAsync(string name, CancellationToken cancellationToken = default) => primary.GetAsync(name, cancellationToken) ?? fallback.GetAsync(name, cancellationToken);
|
||||
|
||||
public Stream GetStream(string name) => primary.GetStream(name) ?? fallback.GetStream(name);
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.UI
|
||||
private int direction = 1;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(GameplayClock clock, ISamplePlaybackDisabler sampleDisabler)
|
||||
private void load(GameplayClock clock)
|
||||
{
|
||||
if (clock != null)
|
||||
{
|
||||
|
@ -19,7 +19,6 @@ using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Skinning;
|
||||
using osuTK;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Audio.Sample;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
@ -88,9 +87,6 @@ namespace osu.Game.Rulesets.UI
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IReadOnlyList<Mod> mods { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private ISampleStore sampleStore { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Playfield"/>.
|
||||
/// </summary>
|
||||
|
@ -127,6 +127,17 @@ namespace osu.Game.Rulesets.UI
|
||||
return base.Handle(e);
|
||||
}
|
||||
|
||||
protected override bool HandleMouseTouchStateChange(TouchStateChangeEvent e)
|
||||
{
|
||||
if (mouseDisabled.Value)
|
||||
{
|
||||
// Only propagate positional data when mouse buttons are disabled.
|
||||
e = new TouchStateChangeEvent(e.State, e.Input, e.Touch, false, e.LastPosition);
|
||||
}
|
||||
|
||||
return base.HandleMouseTouchStateChange(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Key Counter Attachment
|
||||
|
@ -116,25 +116,11 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
||||
|
||||
if (RelativeScaleBeatLengths)
|
||||
{
|
||||
IReadOnlyList<TimingControlPoint> timingPoints = Beatmap.ControlPointInfo.TimingPoints;
|
||||
double maxDuration = 0;
|
||||
baseBeatLength = Beatmap.GetMostCommonBeatLength();
|
||||
|
||||
for (int i = 0; i < timingPoints.Count; i++)
|
||||
{
|
||||
if (timingPoints[i].Time > lastObjectTime)
|
||||
break;
|
||||
|
||||
double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastObjectTime;
|
||||
double duration = endTime - timingPoints[i].Time;
|
||||
|
||||
if (duration > maxDuration)
|
||||
{
|
||||
maxDuration = duration;
|
||||
// The slider multiplier is post-multiplied to determine the final velocity, but for relative scale beat lengths
|
||||
// the multiplier should not affect the effective timing point (the longest in the beatmap), so it is factored out here
|
||||
baseBeatLength = timingPoints[i].BeatLength / Beatmap.Difficulty.SliderMultiplier;
|
||||
}
|
||||
}
|
||||
// The slider multiplier is post-multiplied to determine the final velocity, but for relative scale beat lengths
|
||||
// the multiplier should not affect the effective timing point (the longest in the beatmap), so it is factored out here
|
||||
baseBeatLength /= Beatmap.Difficulty.SliderMultiplier;
|
||||
}
|
||||
|
||||
// Merge sequences of timing and difficulty control points to create the aggregate "multiplier" control point
|
||||
|
Reference in New Issue
Block a user