mirror of
https://github.com/osukey/osukey.git
synced 2025-07-02 16:59:53 +09:00
Merge branch 'master' into update-check-improvements
This commit is contained in:
@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
public override ISkin CreateLegacySkinProvider(ISkinSource source, IBeatmap beatmap) => new CatchLegacySkinTransformer(source);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new CatchPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public int LegacyID => 2;
|
public int LegacyID => 2;
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -25,8 +24,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
private int tinyTicksMissed;
|
private int tinyTicksMissed;
|
||||||
private int misses;
|
private int misses;
|
||||||
|
|
||||||
public CatchPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public CatchPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -29,8 +28,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public ManiaPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public ManiaPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new ManiaPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public const string SHORT_NAME = "mania";
|
public const string SHORT_NAME = "mania";
|
||||||
|
|
||||||
|
@ -29,12 +29,12 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
new SettingsEnumDropdown<ManiaScrollingDirection>
|
new SettingsEnumDropdown<ManiaScrollingDirection>
|
||||||
{
|
{
|
||||||
LabelText = "Scrolling direction",
|
LabelText = "Scrolling direction",
|
||||||
Bindable = config.GetBindable<ManiaScrollingDirection>(ManiaRulesetSetting.ScrollDirection)
|
Current = config.GetBindable<ManiaScrollingDirection>(ManiaRulesetSetting.ScrollDirection)
|
||||||
},
|
},
|
||||||
new SettingsSlider<double, TimeSlider>
|
new SettingsSlider<double, TimeSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Scroll speed",
|
LabelText = "Scroll speed",
|
||||||
Bindable = config.GetBindable<double>(ManiaRulesetSetting.ScrollTime),
|
Current = config.GetBindable<double>(ManiaRulesetSetting.ScrollTime),
|
||||||
KeyboardStep = 5
|
KeyboardStep = 5
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -11,5 +11,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
public double SpeedStrain;
|
public double SpeedStrain;
|
||||||
public double ApproachRate;
|
public double ApproachRate;
|
||||||
public double OverallDifficulty;
|
public double OverallDifficulty;
|
||||||
|
public int HitCircleCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
|
// Add the ticks + tail of the slider. 1 is subtracted because the head circle would be counted twice (once for the slider itself in the line above)
|
||||||
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
maxCombo += beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
||||||
|
|
||||||
|
int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle);
|
||||||
|
|
||||||
return new OsuDifficultyAttributes
|
return new OsuDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
@ -56,6 +58,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
|
||||||
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
OverallDifficulty = (80 - hitWindowGreat) / 6,
|
||||||
MaxCombo = maxCombo,
|
MaxCombo = maxCombo,
|
||||||
|
HitCircleCount = hitCirclesCount,
|
||||||
Skills = skills
|
Skills = skills
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,9 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -19,9 +17,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
|
public new OsuDifficultyAttributes Attributes => (OsuDifficultyAttributes)base.Attributes;
|
||||||
|
|
||||||
private readonly int countHitCircles;
|
|
||||||
private readonly int beatmapMaxCombo;
|
|
||||||
|
|
||||||
private Mod[] mods;
|
private Mod[] mods;
|
||||||
|
|
||||||
private double accuracy;
|
private double accuracy;
|
||||||
@ -31,14 +26,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public OsuPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public OsuPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
countHitCircles = Beatmap.HitObjects.Count(h => h is HitCircle);
|
|
||||||
|
|
||||||
beatmapMaxCombo = Beatmap.HitObjects.Count;
|
|
||||||
// Add the ticks + tail of the slider. 1 is subtracted because the "headcircle" would be counted twice (once for the slider itself in the line above)
|
|
||||||
beatmapMaxCombo += Beatmap.HitObjects.OfType<Slider>().Sum(s => s.NestedHitObjects.Count - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
public override double Calculate(Dictionary<string, double> categoryRatings = null)
|
||||||
@ -81,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
categoryRatings.Add("Accuracy", accuracyValue);
|
categoryRatings.Add("Accuracy", accuracyValue);
|
||||||
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
categoryRatings.Add("OD", Attributes.OverallDifficulty);
|
||||||
categoryRatings.Add("AR", Attributes.ApproachRate);
|
categoryRatings.Add("AR", Attributes.ApproachRate);
|
||||||
categoryRatings.Add("Max Combo", beatmapMaxCombo);
|
categoryRatings.Add("Max Combo", Attributes.MaxCombo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalValue;
|
return totalValue;
|
||||||
@ -106,8 +96,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
aimValue *= Math.Pow(0.97, countMiss);
|
aimValue *= Math.Pow(0.97, countMiss);
|
||||||
|
|
||||||
// Combo scaling
|
// Combo scaling
|
||||||
if (beatmapMaxCombo > 0)
|
if (Attributes.MaxCombo > 0)
|
||||||
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(beatmapMaxCombo, 0.8), 1.0);
|
aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
double approachRateFactor = 1.0;
|
double approachRateFactor = 1.0;
|
||||||
|
|
||||||
@ -154,8 +144,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
speedValue *= Math.Pow(0.97, countMiss);
|
speedValue *= Math.Pow(0.97, countMiss);
|
||||||
|
|
||||||
// Combo scaling
|
// Combo scaling
|
||||||
if (beatmapMaxCombo > 0)
|
if (Attributes.MaxCombo > 0)
|
||||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(beatmapMaxCombo, 0.8), 1.0);
|
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
|
||||||
|
|
||||||
double approachRateFactor = 1.0;
|
double approachRateFactor = 1.0;
|
||||||
if (Attributes.ApproachRate > 10.33)
|
if (Attributes.ApproachRate > 10.33)
|
||||||
@ -178,7 +168,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
// This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window
|
||||||
double betterAccuracyPercentage;
|
double betterAccuracyPercentage;
|
||||||
int amountHitObjectsWithAccuracy = countHitCircles;
|
int amountHitObjectsWithAccuracy = Attributes.HitCircleCount;
|
||||||
|
|
||||||
if (amountHitObjectsWithAccuracy > 0)
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
BorderThickness = 10;
|
BorderThickness = 9; // roughly matches slider borders and makes stacked circles distinctly visible from each other.
|
||||||
BorderColour = Color4.White;
|
BorderColour = Color4.White;
|
||||||
|
|
||||||
Child = new Box
|
Child = new Box
|
||||||
|
@ -171,7 +171,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new OsuDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new OsuPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new OsuPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
||||||
|
|
||||||
|
@ -49,6 +49,23 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject;
|
OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject;
|
||||||
|
|
||||||
|
bool allowFallback = false;
|
||||||
|
|
||||||
|
// attempt lookup using priority specification
|
||||||
|
Texture baseTexture = getTextureWithFallback(string.Empty);
|
||||||
|
|
||||||
|
// if the base texture was not found without a fallback, switch on fallback mode and re-perform the lookup.
|
||||||
|
if (baseTexture == null)
|
||||||
|
{
|
||||||
|
allowFallback = true;
|
||||||
|
baseTexture = getTextureWithFallback(string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
|
||||||
|
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
|
||||||
|
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
|
||||||
|
Texture overlayTexture = getTextureWithFallback("overlay");
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
circleSprites = new Container<Sprite>
|
circleSprites = new Container<Sprite>
|
||||||
@ -60,13 +77,13 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
{
|
{
|
||||||
hitCircleSprite = new Sprite
|
hitCircleSprite = new Sprite
|
||||||
{
|
{
|
||||||
Texture = getTextureWithFallback(string.Empty),
|
Texture = baseTexture,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
hitCircleOverlay = new Sprite
|
hitCircleOverlay = new Sprite
|
||||||
{
|
{
|
||||||
Texture = getTextureWithFallback("overlay"),
|
Texture = overlayTexture,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
}
|
}
|
||||||
@ -101,8 +118,13 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
Texture tex = null;
|
Texture tex = null;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(priorityLookup))
|
if (!string.IsNullOrEmpty(priorityLookup))
|
||||||
|
{
|
||||||
tex = skin.GetTexture($"{priorityLookup}{name}");
|
tex = skin.GetTexture($"{priorityLookup}{name}");
|
||||||
|
|
||||||
|
if (!allowFallback)
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
return tex ?? skin.GetTexture($"hitcircle{name}");
|
return tex ?? skin.GetTexture($"hitcircle{name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,17 +27,17 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Snaking in sliders",
|
LabelText = "Snaking in sliders",
|
||||||
Bindable = config.GetBindable<bool>(OsuRulesetSetting.SnakingInSliders)
|
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingInSliders)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Snaking out sliders",
|
LabelText = "Snaking out sliders",
|
||||||
Bindable = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
|
Current = config.GetBindable<bool>(OsuRulesetSetting.SnakingOutSliders)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Cursor trail",
|
LabelText = "Cursor trail",
|
||||||
Bindable = config.GetBindable<bool>(OsuRulesetSetting.ShowCursorTrail)
|
Current = config.GetBindable<bool>(OsuRulesetSetting.ShowCursorTrail)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -24,8 +23,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public TaikoPerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
public TaikoPerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
: base(ruleset, beatmap, score)
|
: base(ruleset, attributes, score)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -14,13 +15,29 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
{
|
{
|
||||||
public class TaikoLegacySkinTransformer : LegacySkinTransformer
|
public class TaikoLegacySkinTransformer : LegacySkinTransformer
|
||||||
{
|
{
|
||||||
|
private Lazy<bool> hasExplosion;
|
||||||
|
|
||||||
public TaikoLegacySkinTransformer(ISkinSource source)
|
public TaikoLegacySkinTransformer(ISkinSource source)
|
||||||
: base(source)
|
: base(source)
|
||||||
{
|
{
|
||||||
|
Source.SourceChanged += sourceChanged;
|
||||||
|
sourceChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sourceChanged()
|
||||||
|
{
|
||||||
|
hasExplosion = new Lazy<bool>(() => Source.GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Drawable GetDrawableComponent(ISkinComponent component)
|
public override Drawable GetDrawableComponent(ISkinComponent component)
|
||||||
{
|
{
|
||||||
|
if (component is GameplaySkinComponent<HitResult>)
|
||||||
|
{
|
||||||
|
// if a taiko skin is providing explosion sprites, hide the judgements completely
|
||||||
|
if (hasExplosion.Value)
|
||||||
|
return Drawable.Empty();
|
||||||
|
}
|
||||||
|
|
||||||
if (!(component is TaikoSkinComponent taikoComponent))
|
if (!(component is TaikoSkinComponent taikoComponent))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -87,10 +104,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
var hitName = getHitName(taikoComponent.Component);
|
var hitName = getHitName(taikoComponent.Component);
|
||||||
var hitSprite = this.GetAnimation(hitName, true, false);
|
var hitSprite = this.GetAnimation(hitName, true, false);
|
||||||
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
|
||||||
|
|
||||||
if (hitSprite != null)
|
if (hitSprite != null)
|
||||||
|
{
|
||||||
|
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
||||||
|
|
||||||
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new TaikoPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => new TaikoPerformanceCalculator(this, attributes, score);
|
||||||
|
|
||||||
public int LegacyID => 1;
|
public int LegacyID => 1;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 }
|
new HitCircle { StartTime = 1000, NewCombo = true }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -100,7 +100,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -109,7 +109,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
(OsuHitObject)current.HitObjects[1],
|
(OsuHitObject)current.HitObjects[1],
|
||||||
(OsuHitObject)current.HitObjects[2],
|
(OsuHitObject)current.HitObjects[2],
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -146,7 +146,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new OsuHitObject[]
|
current.AddRange(new OsuHitObject[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new Slider
|
new Slider
|
||||||
{
|
{
|
||||||
StartTime = 2000,
|
StartTime = 2000,
|
||||||
@ -188,7 +188,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000, NewCombo = true },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
new HitCircle { StartTime = 3000 },
|
new HitCircle { StartTime = 3000 },
|
||||||
});
|
});
|
||||||
@ -197,7 +197,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
(OsuHitObject)current.HitObjects[0],
|
(OsuHitObject)current.HitObjects[0],
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
(OsuHitObject)current.HitObjects[1],
|
(OsuHitObject)current.HitObjects[1],
|
||||||
@ -216,7 +216,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000 },
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
@ -226,6 +226,9 @@ namespace osu.Game.Tests.Editing
|
|||||||
new HitCircle { StartTime = 3500 },
|
new HitCircle { StartTime = 3500 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var patchedFirst = (HitCircle)current.HitObjects[1];
|
||||||
|
patchedFirst.NewCombo = true;
|
||||||
|
|
||||||
var patch = new OsuBeatmap
|
var patch = new OsuBeatmap
|
||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
@ -244,7 +247,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000 },
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
@ -277,7 +280,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500 },
|
new HitCircle { StartTime = 500, NewCombo = true },
|
||||||
new HitCircle { StartTime = 1000 },
|
new HitCircle { StartTime = 1000 },
|
||||||
new HitCircle { StartTime = 1500 },
|
new HitCircle { StartTime = 1500 },
|
||||||
new HitCircle { StartTime = 2000 },
|
new HitCircle { StartTime = 2000 },
|
||||||
@ -291,7 +294,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 750 },
|
new HitCircle { StartTime = 750, NewCombo = true },
|
||||||
(OsuHitObject)current.HitObjects[1],
|
(OsuHitObject)current.HitObjects[1],
|
||||||
(OsuHitObject)current.HitObjects[4],
|
(OsuHitObject)current.HitObjects[4],
|
||||||
(OsuHitObject)current.HitObjects[5],
|
(OsuHitObject)current.HitObjects[5],
|
||||||
@ -309,20 +312,20 @@ namespace osu.Game.Tests.Editing
|
|||||||
{
|
{
|
||||||
current.AddRange(new[]
|
current.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(50) },
|
new HitCircle { StartTime = 500, Position = new Vector2(50), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(100) },
|
new HitCircle { StartTime = 500, Position = new Vector2(100), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(150) },
|
new HitCircle { StartTime = 500, Position = new Vector2(150), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(200) },
|
new HitCircle { StartTime = 500, Position = new Vector2(200), NewCombo = true },
|
||||||
});
|
});
|
||||||
|
|
||||||
var patch = new OsuBeatmap
|
var patch = new OsuBeatmap
|
||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
{
|
{
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(150) },
|
new HitCircle { StartTime = 500, Position = new Vector2(150), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(100) },
|
new HitCircle { StartTime = 500, Position = new Vector2(100), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(50) },
|
new HitCircle { StartTime = 500, Position = new Vector2(50), NewCombo = true },
|
||||||
new HitCircle { StartTime = 500, Position = new Vector2(200) },
|
new HitCircle { StartTime = 500, Position = new Vector2(200), NewCombo = true },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
using (var zip = ZipArchive.Open(temp))
|
using (var zip = ZipArchive.Open(temp))
|
||||||
zip.WriteToDirectory(extractedFolder);
|
zip.WriteToDirectory(extractedFolder);
|
||||||
|
|
||||||
bool success = setup.ChangeAudioTrack(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3"));
|
bool success = setup.ChildrenOfType<ResourcesSection>().First().ChangeAudioTrack(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3"));
|
||||||
|
|
||||||
File.Delete(temp);
|
File.Delete(temp);
|
||||||
Directory.Delete(extractedFolder, true);
|
Directory.Delete(extractedFolder, true);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
@ -23,33 +24,41 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivation()
|
public void TestGameplayOverlayActivation()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivationPaused()
|
public void TestGameplayOverlayActivationPaused()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
AddStep("pause gameplay", () => Player.Pause());
|
AddStep("pause gameplay", () => Player.Pause());
|
||||||
|
AddAssert("local user not playing", () => !Player.LocalUserPlaying.Value);
|
||||||
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivationReplayLoaded()
|
public void TestGameplayOverlayActivationReplayLoaded()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
AddStep("load a replay", () => Player.DrawableRuleset.HasReplayLoaded.Value = true);
|
||||||
|
AddAssert("local user not playing", () => !Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
AddAssert("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestGameplayOverlayActivationBreaks()
|
public void TestGameplayOverlayActivationBreaks()
|
||||||
{
|
{
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddAssert("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
AddStep("seek to break", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().StartTime));
|
||||||
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
AddUntilStep("activation mode is user triggered", () => Player.OverlayActivationMode == OverlayActivation.UserTriggered);
|
||||||
|
AddAssert("local user not playing", () => !Player.LocalUserPlaying.Value);
|
||||||
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
AddStep("seek to break end", () => Player.GameplayClockContainer.Seek(Beatmap.Value.Beatmap.Breaks.First().EndTime));
|
||||||
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
AddUntilStep("activation mode is disabled", () => Player.OverlayActivationMode == OverlayActivation.Disabled);
|
||||||
|
AddAssert("local user playing", () => Player.LocalUserPlaying.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer();
|
||||||
@ -57,6 +66,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
protected class OverlayTestPlayer : TestPlayer
|
protected class OverlayTestPlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value;
|
||||||
|
public new Bindable<bool> LocalUserPlaying => base.LocalUserPlaying;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
|
{
|
||||||
|
public class TestSceneLabelledSliderBar : OsuTestScene
|
||||||
|
{
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestSliderBar(bool hasDescription) => createSliderBar(hasDescription);
|
||||||
|
|
||||||
|
private void createSliderBar(bool hasDescription = false)
|
||||||
|
{
|
||||||
|
AddStep("create component", () =>
|
||||||
|
{
|
||||||
|
LabelledSliderBar<double> component;
|
||||||
|
|
||||||
|
Child = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Width = 500,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Child = component = new LabelledSliderBar<double>
|
||||||
|
{
|
||||||
|
Current = new BindableDouble(5)
|
||||||
|
{
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
component.Label = "a sample component";
|
||||||
|
component.Description = hasDescription ? "this text describes the component" : string.Empty;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,34 +10,34 @@ namespace osu.Game.Tournament.Components
|
|||||||
{
|
{
|
||||||
public class DateTextBox : SettingsTextBox
|
public class DateTextBox : SettingsTextBox
|
||||||
{
|
{
|
||||||
public new Bindable<DateTimeOffset> Bindable
|
public new Bindable<DateTimeOffset> Current
|
||||||
{
|
{
|
||||||
get => bindable;
|
get => current;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
bindable = value.GetBoundCopy();
|
current = value.GetBoundCopy();
|
||||||
bindable.BindValueChanged(dto =>
|
current.BindValueChanged(dto =>
|
||||||
base.Bindable.Value = dto.NewValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"), true);
|
base.Current.Value = dto.NewValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hold a reference to the provided bindable so we don't have to in every settings section.
|
// hold a reference to the provided bindable so we don't have to in every settings section.
|
||||||
private Bindable<DateTimeOffset> bindable = new Bindable<DateTimeOffset>();
|
private Bindable<DateTimeOffset> current = new Bindable<DateTimeOffset>();
|
||||||
|
|
||||||
public DateTextBox()
|
public DateTextBox()
|
||||||
{
|
{
|
||||||
base.Bindable = new Bindable<string>();
|
base.Current = new Bindable<string>();
|
||||||
|
|
||||||
((OsuTextBox)Control).OnCommit += (sender, newText) =>
|
((OsuTextBox)Control).OnCommit += (sender, newText) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bindable.Value = DateTimeOffset.Parse(sender.Text);
|
current.Value = DateTimeOffset.Parse(sender.Text);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// reset textbox content to its last valid state on a parse failure.
|
// reset textbox content to its last valid state on a parse failure.
|
||||||
bindable.TriggerChange();
|
current.TriggerChange();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -63,25 +63,25 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
LabelText = "Name",
|
LabelText = "Name",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.Name
|
Current = Model.Name
|
||||||
},
|
},
|
||||||
new SettingsTextBox
|
new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Description",
|
LabelText = "Description",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.Description
|
Current = Model.Description
|
||||||
},
|
},
|
||||||
new DateTextBox
|
new DateTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Start Time",
|
LabelText = "Start Time",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.StartDate
|
Current = Model.StartDate
|
||||||
},
|
},
|
||||||
new SettingsSlider<int>
|
new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = "Best of",
|
LabelText = "Best of",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.BestOf
|
Current = Model.BestOf
|
||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
{
|
{
|
||||||
@ -186,14 +186,14 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
LabelText = "Beatmap ID",
|
LabelText = "Beatmap ID",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 200,
|
Width = 200,
|
||||||
Bindable = beatmapId,
|
Current = beatmapId,
|
||||||
},
|
},
|
||||||
new SettingsTextBox
|
new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Mods",
|
LabelText = "Mods",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 200,
|
Width = 200,
|
||||||
Bindable = mods,
|
Current = mods,
|
||||||
},
|
},
|
||||||
drawableContainer = new Container
|
drawableContainer = new Container
|
||||||
{
|
{
|
||||||
|
@ -74,13 +74,13 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
LabelText = "Mod",
|
LabelText = "Mod",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.Mod
|
Current = Model.Mod
|
||||||
},
|
},
|
||||||
new SettingsSlider<int>
|
new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = "Seed",
|
LabelText = "Seed",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.Seed
|
Current = Model.Seed
|
||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
{
|
{
|
||||||
@ -187,21 +187,21 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
LabelText = "Beatmap ID",
|
LabelText = "Beatmap ID",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 200,
|
Width = 200,
|
||||||
Bindable = beatmapId,
|
Current = beatmapId,
|
||||||
},
|
},
|
||||||
new SettingsSlider<int>
|
new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = "Seed",
|
LabelText = "Seed",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 200,
|
Width = 200,
|
||||||
Bindable = beatmap.Seed
|
Current = beatmap.Seed
|
||||||
},
|
},
|
||||||
new SettingsTextBox
|
new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Score",
|
LabelText = "Score",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 200,
|
Width = 200,
|
||||||
Bindable = score,
|
Current = score,
|
||||||
},
|
},
|
||||||
drawableContainer = new Container
|
drawableContainer = new Container
|
||||||
{
|
{
|
||||||
|
@ -102,31 +102,31 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
LabelText = "Name",
|
LabelText = "Name",
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
Bindable = Model.FullName
|
Current = Model.FullName
|
||||||
},
|
},
|
||||||
new SettingsTextBox
|
new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Acronym",
|
LabelText = "Acronym",
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
Bindable = Model.Acronym
|
Current = Model.Acronym
|
||||||
},
|
},
|
||||||
new SettingsTextBox
|
new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Flag",
|
LabelText = "Flag",
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
Bindable = Model.FlagName
|
Current = Model.FlagName
|
||||||
},
|
},
|
||||||
new SettingsTextBox
|
new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = "Seed",
|
LabelText = "Seed",
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
Bindable = Model.Seed
|
Current = Model.Seed
|
||||||
},
|
},
|
||||||
new SettingsSlider<int>
|
new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = "Last Year Placement",
|
LabelText = "Last Year Placement",
|
||||||
Width = 0.33f,
|
Width = 0.33f,
|
||||||
Bindable = Model.LastYearPlacing
|
Current = Model.LastYearPlacing
|
||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
{
|
{
|
||||||
@ -247,7 +247,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
LabelText = "User ID",
|
LabelText = "User ID",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 200,
|
Width = 200,
|
||||||
Bindable = userId,
|
Current = userId,
|
||||||
},
|
},
|
||||||
drawableContainer = new Container
|
drawableContainer = new Container
|
||||||
{
|
{
|
||||||
|
@ -113,13 +113,13 @@ namespace osu.Game.Tournament.Screens.Gameplay
|
|||||||
new SettingsSlider<int>
|
new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = "Chroma width",
|
LabelText = "Chroma width",
|
||||||
Bindable = LadderInfo.ChromaKeyWidth,
|
Current = LadderInfo.ChromaKeyWidth,
|
||||||
KeyboardStep = 1,
|
KeyboardStep = 1,
|
||||||
},
|
},
|
||||||
new SettingsSlider<int>
|
new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = "Players per team",
|
LabelText = "Players per team",
|
||||||
Bindable = LadderInfo.PlayersPerTeam,
|
Current = LadderInfo.PlayersPerTeam,
|
||||||
KeyboardStep = 1,
|
KeyboardStep = 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,15 +51,15 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
|
|
||||||
editorInfo.Selected.ValueChanged += selection =>
|
editorInfo.Selected.ValueChanged += selection =>
|
||||||
{
|
{
|
||||||
roundDropdown.Bindable = selection.NewValue?.Round;
|
roundDropdown.Current = selection.NewValue?.Round;
|
||||||
losersCheckbox.Current = selection.NewValue?.Losers;
|
losersCheckbox.Current = selection.NewValue?.Losers;
|
||||||
dateTimeBox.Bindable = selection.NewValue?.Date;
|
dateTimeBox.Current = selection.NewValue?.Date;
|
||||||
|
|
||||||
team1Dropdown.Bindable = selection.NewValue?.Team1;
|
team1Dropdown.Current = selection.NewValue?.Team1;
|
||||||
team2Dropdown.Bindable = selection.NewValue?.Team2;
|
team2Dropdown.Current = selection.NewValue?.Team2;
|
||||||
};
|
};
|
||||||
|
|
||||||
roundDropdown.Bindable.ValueChanged += round =>
|
roundDropdown.Current.ValueChanged += round =>
|
||||||
{
|
{
|
||||||
if (editorInfo.Selected.Value?.Date.Value < round.NewValue?.StartDate.Value)
|
if (editorInfo.Selected.Value?.Date.Value < round.NewValue?.StartDate.Value)
|
||||||
{
|
{
|
||||||
@ -88,7 +88,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
{
|
{
|
||||||
public SettingsRoundDropdown(BindableList<TournamentRound> rounds)
|
public SettingsRoundDropdown(BindableList<TournamentRound> rounds)
|
||||||
{
|
{
|
||||||
Bindable = new Bindable<TournamentRound>();
|
Current = new Bindable<TournamentRound>();
|
||||||
|
|
||||||
foreach (var r in rounds.Prepend(new TournamentRound()))
|
foreach (var r in rounds.Prepend(new TournamentRound()))
|
||||||
add(r);
|
add(r);
|
||||||
|
@ -61,7 +61,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
|
|||||||
new SettingsTeamDropdown(LadderInfo.Teams)
|
new SettingsTeamDropdown(LadderInfo.Teams)
|
||||||
{
|
{
|
||||||
LabelText = "Show specific team",
|
LabelText = "Show specific team",
|
||||||
Bindable = currentTeam,
|
Current = currentTeam,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,18 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
IHasComboInformation lastObj = null;
|
IHasComboInformation lastObj = null;
|
||||||
|
|
||||||
|
bool isFirst = true;
|
||||||
|
|
||||||
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
foreach (var obj in Beatmap.HitObjects.OfType<IHasComboInformation>())
|
||||||
{
|
{
|
||||||
|
if (isFirst)
|
||||||
|
{
|
||||||
|
obj.NewCombo = true;
|
||||||
|
|
||||||
|
// first hitobject should always be marked as a new combo for sanity.
|
||||||
|
isFirst = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (obj.NewCombo)
|
if (obj.NewCombo)
|
||||||
{
|
{
|
||||||
obj.IndexInCurrentCombo = 0;
|
obj.IndexInCurrentCombo = 0;
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Configuration.Tracking;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Input;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -69,6 +70,7 @@ namespace osu.Game.Configuration
|
|||||||
|
|
||||||
Set(OsuSetting.MouseDisableButtons, false);
|
Set(OsuSetting.MouseDisableButtons, false);
|
||||||
Set(OsuSetting.MouseDisableWheel, false);
|
Set(OsuSetting.MouseDisableWheel, false);
|
||||||
|
Set(OsuSetting.ConfineMouseMode, OsuConfineMouseMode.DuringGameplay);
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
Set(OsuSetting.ShowFpsDisplay, false);
|
Set(OsuSetting.ShowFpsDisplay, false);
|
||||||
@ -194,6 +196,7 @@ namespace osu.Game.Configuration
|
|||||||
FadePlayfieldWhenHealthLow,
|
FadePlayfieldWhenHealthLow,
|
||||||
MouseDisableButtons,
|
MouseDisableButtons,
|
||||||
MouseDisableWheel,
|
MouseDisableWheel,
|
||||||
|
ConfineMouseMode,
|
||||||
AudioOffset,
|
AudioOffset,
|
||||||
VolumeInactive,
|
VolumeInactive,
|
||||||
MenuMusic,
|
MenuMusic,
|
||||||
|
@ -57,7 +57,7 @@ namespace osu.Game.Configuration
|
|||||||
yield return new SettingsSlider<float>
|
yield return new SettingsSlider<float>
|
||||||
{
|
{
|
||||||
LabelText = attr.Label,
|
LabelText = attr.Label,
|
||||||
Bindable = bNumber,
|
Current = bNumber,
|
||||||
KeyboardStep = 0.1f,
|
KeyboardStep = 0.1f,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ namespace osu.Game.Configuration
|
|||||||
yield return new SettingsSlider<double>
|
yield return new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = attr.Label,
|
LabelText = attr.Label,
|
||||||
Bindable = bNumber,
|
Current = bNumber,
|
||||||
KeyboardStep = 0.1f,
|
KeyboardStep = 0.1f,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ namespace osu.Game.Configuration
|
|||||||
yield return new SettingsSlider<int>
|
yield return new SettingsSlider<int>
|
||||||
{
|
{
|
||||||
LabelText = attr.Label,
|
LabelText = attr.Label,
|
||||||
Bindable = bNumber
|
Current = bNumber
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -86,7 +86,7 @@ namespace osu.Game.Configuration
|
|||||||
yield return new SettingsCheckbox
|
yield return new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = attr.Label,
|
LabelText = attr.Label,
|
||||||
Bindable = bBool
|
Current = bBool
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -95,7 +95,7 @@ namespace osu.Game.Configuration
|
|||||||
yield return new SettingsTextBox
|
yield return new SettingsTextBox
|
||||||
{
|
{
|
||||||
LabelText = attr.Label,
|
LabelText = attr.Label,
|
||||||
Bindable = bString
|
Current = bString
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -105,7 +105,7 @@ namespace osu.Game.Configuration
|
|||||||
var dropdown = (Drawable)Activator.CreateInstance(dropdownType);
|
var dropdown = (Drawable)Activator.CreateInstance(dropdownType);
|
||||||
|
|
||||||
dropdownType.GetProperty(nameof(SettingsDropdown<object>.LabelText))?.SetValue(dropdown, attr.Label);
|
dropdownType.GetProperty(nameof(SettingsDropdown<object>.LabelText))?.SetValue(dropdown, attr.Label);
|
||||||
dropdownType.GetProperty(nameof(SettingsDropdown<object>.Bindable))?.SetValue(dropdown, bindable);
|
dropdownType.GetProperty(nameof(SettingsDropdown<object>.Current))?.SetValue(dropdown, bindable);
|
||||||
|
|
||||||
yield return dropdown;
|
yield return dropdown;
|
||||||
|
|
||||||
|
24
osu.Game/Graphics/UserInterfaceV2/LabelledSliderBar.cs
Normal file
24
osu.Game/Graphics/UserInterfaceV2/LabelledSliderBar.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Game.Overlays.Settings;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterfaceV2
|
||||||
|
{
|
||||||
|
public class LabelledSliderBar<TNumber> : LabelledComponent<SettingsSlider<TNumber>, TNumber>
|
||||||
|
where TNumber : struct, IEquatable<TNumber>, IComparable<TNumber>, IConvertible
|
||||||
|
{
|
||||||
|
public LabelledSliderBar()
|
||||||
|
: base(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override SettingsSlider<TNumber> CreateComponent() => new SettingsSlider<TNumber>
|
||||||
|
{
|
||||||
|
TransferValueOnCommit = true,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
61
osu.Game/Input/ConfineMouseTracker.cs
Normal file
61
osu.Game/Input/ConfineMouseTracker.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 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.Framework.Bindables;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
|
namespace osu.Game.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Connects <see cref="OsuSetting.ConfineMouseMode"/> with <see cref="FrameworkSetting.ConfineMouseMode"/>.
|
||||||
|
/// If <see cref="OsuGame.LocalUserPlaying"/> is true, we should also confine the mouse cursor if it has been
|
||||||
|
/// requested with <see cref="OsuConfineMouseMode.DuringGameplay"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class ConfineMouseTracker : Component
|
||||||
|
{
|
||||||
|
private Bindable<ConfineMouseMode> frameworkConfineMode;
|
||||||
|
private Bindable<OsuConfineMouseMode> osuConfineMode;
|
||||||
|
private IBindable<bool> localUserPlaying;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGame game, FrameworkConfigManager frameworkConfigManager, OsuConfigManager osuConfigManager)
|
||||||
|
{
|
||||||
|
frameworkConfineMode = frameworkConfigManager.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode);
|
||||||
|
osuConfineMode = osuConfigManager.GetBindable<OsuConfineMouseMode>(OsuSetting.ConfineMouseMode);
|
||||||
|
localUserPlaying = game.LocalUserPlaying.GetBoundCopy();
|
||||||
|
|
||||||
|
osuConfineMode.ValueChanged += _ => updateConfineMode();
|
||||||
|
localUserPlaying.BindValueChanged(_ => updateConfineMode(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfineMode()
|
||||||
|
{
|
||||||
|
// confine mode is unavailable on some platforms
|
||||||
|
if (frameworkConfineMode.Disabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (osuConfineMode.Value)
|
||||||
|
{
|
||||||
|
case OsuConfineMouseMode.Never:
|
||||||
|
frameworkConfineMode.Value = ConfineMouseMode.Never;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuConfineMouseMode.Fullscreen:
|
||||||
|
frameworkConfineMode.Value = ConfineMouseMode.Fullscreen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuConfineMouseMode.DuringGameplay:
|
||||||
|
frameworkConfineMode.Value = localUserPlaying.Value ? ConfineMouseMode.Always : ConfineMouseMode.Never;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuConfineMouseMode.Always:
|
||||||
|
frameworkConfineMode.Value = ConfineMouseMode.Always;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
osu.Game/Input/OsuConfineMouseMode.cs
Normal file
37
osu.Game/Input/OsuConfineMouseMode.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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.ComponentModel;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Input
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the situations in which the mouse cursor should be confined to the window.
|
||||||
|
/// Expands upon <see cref="ConfineMouseMode"/> by providing the option to confine during gameplay.
|
||||||
|
/// </summary>
|
||||||
|
public enum OsuConfineMouseMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will be free to move outside the game window.
|
||||||
|
/// </summary>
|
||||||
|
Never,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will be locked to the window bounds while in fullscreen mode.
|
||||||
|
/// </summary>
|
||||||
|
Fullscreen,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will be locked to the window bounds during gameplay,
|
||||||
|
/// but may otherwise move freely.
|
||||||
|
/// </summary>
|
||||||
|
[Description("During Gameplay")]
|
||||||
|
DuringGameplay,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The mouse cursor will always be locked to the window bounds while the game has focus.
|
||||||
|
/// </summary>
|
||||||
|
Always
|
||||||
|
}
|
||||||
|
}
|
@ -95,6 +95,15 @@ namespace osu.Game
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
|
public readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the local user is currently interacting with the game in a way that should not be interrupted.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is exclusively managed by <see cref="Player"/>. If other components are mutating this state, a more
|
||||||
|
/// resilient method should be used to ensure correct state.
|
||||||
|
/// </remarks>
|
||||||
|
public Bindable<bool> LocalUserPlaying = new BindableBool();
|
||||||
|
|
||||||
protected OsuScreenStack ScreenStack;
|
protected OsuScreenStack ScreenStack;
|
||||||
|
|
||||||
protected BackButton BackButton;
|
protected BackButton BackButton;
|
||||||
@ -577,7 +586,8 @@ namespace osu.Game
|
|||||||
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
idleTracker
|
idleTracker,
|
||||||
|
new ConfineMouseTracker()
|
||||||
});
|
});
|
||||||
|
|
||||||
ScreenStack.ScreenPushed += screenPushed;
|
ScreenStack.ScreenPushed += screenPushed;
|
||||||
@ -947,6 +957,9 @@ namespace osu.Game
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset on screen change for sanity.
|
||||||
|
LocalUserPlaying.Value = false;
|
||||||
|
|
||||||
if (current is IOsuScreen currentOsuScreen)
|
if (current is IOsuScreen currentOsuScreen)
|
||||||
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
|
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
|
|
||||||
updateItems();
|
updateItems();
|
||||||
|
|
||||||
dropdown.Bindable = audio.AudioDevice;
|
dropdown.Current = audio.AudioDevice;
|
||||||
|
|
||||||
audio.OnNewDevice += onDeviceChanged;
|
audio.OnNewDevice += onDeviceChanged;
|
||||||
audio.OnLostDevice += onDeviceChanged;
|
audio.OnLostDevice += onDeviceChanged;
|
||||||
|
@ -21,23 +21,23 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Interface voices",
|
LabelText = "Interface voices",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.MenuVoice)
|
Current = config.GetBindable<bool>(OsuSetting.MenuVoice)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "osu! music theme",
|
LabelText = "osu! music theme",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.MenuMusic)
|
Current = config.GetBindable<bool>(OsuSetting.MenuMusic)
|
||||||
},
|
},
|
||||||
new SettingsDropdown<IntroSequence>
|
new SettingsDropdown<IntroSequence>
|
||||||
{
|
{
|
||||||
LabelText = "Intro sequence",
|
LabelText = "Intro sequence",
|
||||||
Bindable = config.GetBindable<IntroSequence>(OsuSetting.IntroSequence),
|
Current = config.GetBindable<IntroSequence>(OsuSetting.IntroSequence),
|
||||||
Items = Enum.GetValues(typeof(IntroSequence)).Cast<IntroSequence>()
|
Items = Enum.GetValues(typeof(IntroSequence)).Cast<IntroSequence>()
|
||||||
},
|
},
|
||||||
new SettingsDropdown<BackgroundSource>
|
new SettingsDropdown<BackgroundSource>
|
||||||
{
|
{
|
||||||
LabelText = "Background source",
|
LabelText = "Background source",
|
||||||
Bindable = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource),
|
Current = config.GetBindable<BackgroundSource>(OsuSetting.MenuBackgroundSource),
|
||||||
Items = Enum.GetValues(typeof(BackgroundSource)).Cast<BackgroundSource>()
|
Items = Enum.GetValues(typeof(BackgroundSource)).Cast<BackgroundSource>()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
new SettingsSlider<double, OffsetSlider>
|
new SettingsSlider<double, OffsetSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Audio offset",
|
LabelText = "Audio offset",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.AudioOffset),
|
Current = config.GetBindable<double>(OsuSetting.AudioOffset),
|
||||||
KeyboardStep = 1f
|
KeyboardStep = 1f
|
||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
|
@ -20,28 +20,28 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
new SettingsSlider<double>
|
new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = "Master",
|
LabelText = "Master",
|
||||||
Bindable = audio.Volume,
|
Current = audio.Volume,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<double>
|
new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = "Master (window inactive)",
|
LabelText = "Master (window inactive)",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive),
|
Current = config.GetBindable<double>(OsuSetting.VolumeInactive),
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<double>
|
new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = "Effect",
|
LabelText = "Effect",
|
||||||
Bindable = audio.VolumeSample,
|
Current = audio.VolumeSample,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<double>
|
new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = "Music",
|
LabelText = "Music",
|
||||||
Bindable = audio.VolumeTrack,
|
Current = audio.VolumeTrack,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
|
@ -19,12 +19,12 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show log overlay",
|
LabelText = "Show log overlay",
|
||||||
Bindable = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay)
|
Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Bypass front-to-back render pass",
|
LabelText = "Bypass front-to-back render pass",
|
||||||
Bindable = config.GetBindable<bool>(DebugSetting.BypassFrontToBackPass)
|
Current = config.GetBindable<bool>(DebugSetting.BypassFrontToBackPass)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -21,62 +21,62 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
new SettingsSlider<double>
|
new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = "Background dim",
|
LabelText = "Background dim",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.DimLevel),
|
Current = config.GetBindable<double>(OsuSetting.DimLevel),
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<double>
|
new SettingsSlider<double>
|
||||||
{
|
{
|
||||||
LabelText = "Background blur",
|
LabelText = "Background blur",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.BlurLevel),
|
Current = config.GetBindable<double>(OsuSetting.BlurLevel),
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Lighten playfield during breaks",
|
LabelText = "Lighten playfield during breaks",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks)
|
Current = config.GetBindable<bool>(OsuSetting.LightenDuringBreaks)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show score overlay",
|
LabelText = "Show score overlay",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ShowInterface)
|
Current = config.GetBindable<bool>(OsuSetting.ShowInterface)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show difficulty graph on progress bar",
|
LabelText = "Show difficulty graph on progress bar",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ShowProgressGraph)
|
Current = config.GetBindable<bool>(OsuSetting.ShowProgressGraph)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show health display even when you can't fail",
|
LabelText = "Show health display even when you can't fail",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
Current = config.GetBindable<bool>(OsuSetting.ShowHealthDisplayWhenCantFail),
|
||||||
Keywords = new[] { "hp", "bar" }
|
Keywords = new[] { "hp", "bar" }
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Fade playfield to red when health is low",
|
LabelText = "Fade playfield to red when health is low",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.FadePlayfieldWhenHealthLow),
|
Current = config.GetBindable<bool>(OsuSetting.FadePlayfieldWhenHealthLow),
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Always show key overlay",
|
LabelText = "Always show key overlay",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.KeyOverlay)
|
Current = config.GetBindable<bool>(OsuSetting.KeyOverlay)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Positional hitsounds",
|
LabelText = "Positional hitsounds",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.PositionalHitSounds)
|
Current = config.GetBindable<bool>(OsuSetting.PositionalHitSounds)
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ScoreMeterType>
|
new SettingsEnumDropdown<ScoreMeterType>
|
||||||
{
|
{
|
||||||
LabelText = "Score meter type",
|
LabelText = "Score meter type",
|
||||||
Bindable = config.GetBindable<ScoreMeterType>(OsuSetting.ScoreMeter)
|
Current = config.GetBindable<ScoreMeterType>(OsuSetting.ScoreMeter)
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ScoringMode>
|
new SettingsEnumDropdown<ScoringMode>
|
||||||
{
|
{
|
||||||
LabelText = "Score display mode",
|
LabelText = "Score display mode",
|
||||||
Bindable = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode)
|
Current = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
Add(new SettingsCheckbox
|
Add(new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Disable Windows key during gameplay",
|
LabelText = "Disable Windows key during gameplay",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey)
|
Current = config.GetBindable<bool>(OsuSetting.GameplayDisableWinKey)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Increase visibility of first object when visual impairment mods are enabled",
|
LabelText = "Increase visibility of first object when visual impairment mods are enabled",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility),
|
Current = config.GetBindable<bool>(OsuSetting.IncreaseFirstObjectVisibility),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -31,31 +31,31 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Right mouse drag to absolute scroll",
|
LabelText = "Right mouse drag to absolute scroll",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
|
Current = config.GetBindable<bool>(OsuSetting.SongSelectRightMouseScroll),
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show converted beatmaps",
|
LabelText = "Show converted beatmaps",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps),
|
Current = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps),
|
||||||
},
|
},
|
||||||
new SettingsSlider<double, StarsSlider>
|
new SettingsSlider<double, StarsSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Display beatmaps from",
|
LabelText = "Display beatmaps from",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum),
|
Current = config.GetBindable<double>(OsuSetting.DisplayStarsMinimum),
|
||||||
KeyboardStep = 0.1f,
|
KeyboardStep = 0.1f,
|
||||||
Keywords = new[] { "minimum", "maximum", "star", "difficulty" }
|
Keywords = new[] { "minimum", "maximum", "star", "difficulty" }
|
||||||
},
|
},
|
||||||
new SettingsSlider<double, MaximumStarsSlider>
|
new SettingsSlider<double, MaximumStarsSlider>
|
||||||
{
|
{
|
||||||
LabelText = "up to",
|
LabelText = "up to",
|
||||||
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum),
|
Current = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum),
|
||||||
KeyboardStep = 0.1f,
|
KeyboardStep = 0.1f,
|
||||||
Keywords = new[] { "minimum", "maximum", "star", "difficulty" }
|
Keywords = new[] { "minimum", "maximum", "star", "difficulty" }
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<RandomSelectAlgorithm>
|
new SettingsEnumDropdown<RandomSelectAlgorithm>
|
||||||
{
|
{
|
||||||
LabelText = "Random selection algorithm",
|
LabelText = "Random selection algorithm",
|
||||||
Bindable = config.GetBindable<RandomSelectAlgorithm>(OsuSetting.RandomSelectAlgorithm),
|
Current = config.GetBindable<RandomSelectAlgorithm>(OsuSetting.RandomSelectAlgorithm),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Prefer metadata in original language",
|
LabelText = "Prefer metadata in original language",
|
||||||
Bindable = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowUnicode)
|
Current = frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowUnicode)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -240,12 +240,12 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Remember username",
|
LabelText = "Remember username",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.SaveUsername),
|
Current = config.GetBindable<bool>(OsuSetting.SaveUsername),
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Stay signed in",
|
LabelText = "Stay signed in",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.SavePassword),
|
Current = config.GetBindable<bool>(OsuSetting.SavePassword),
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
Add(new SettingsEnumDropdown<ReleaseStream>
|
Add(new SettingsEnumDropdown<ReleaseStream>
|
||||||
{
|
{
|
||||||
LabelText = "Release stream",
|
LabelText = "Release stream",
|
||||||
Bindable = config.GetBindable<ReleaseStream>(OsuSetting.ReleaseStream),
|
Current = config.GetBindable<ReleaseStream>(OsuSetting.ReleaseStream),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (updateManager?.CanCheckForUpdate == true)
|
if (updateManager?.CanCheckForUpdate == true)
|
||||||
|
@ -19,22 +19,22 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Storyboard / Video",
|
LabelText = "Storyboard / Video",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ShowStoryboard)
|
Current = config.GetBindable<bool>(OsuSetting.ShowStoryboard)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Hit Lighting",
|
LabelText = "Hit Lighting",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.HitLighting)
|
Current = config.GetBindable<bool>(OsuSetting.HitLighting)
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ScreenshotFormat>
|
new SettingsEnumDropdown<ScreenshotFormat>
|
||||||
{
|
{
|
||||||
LabelText = "Screenshot format",
|
LabelText = "Screenshot format",
|
||||||
Bindable = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat)
|
Current = config.GetBindable<ScreenshotFormat>(OsuSetting.ScreenshotFormat)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show menu cursor in screenshots",
|
LabelText = "Show menu cursor in screenshots",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor)
|
Current = config.GetBindable<bool>(OsuSetting.ScreenshotCaptureMenuCursor)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
windowModeDropdown = new SettingsDropdown<WindowMode>
|
windowModeDropdown = new SettingsDropdown<WindowMode>
|
||||||
{
|
{
|
||||||
LabelText = "Screen mode",
|
LabelText = "Screen mode",
|
||||||
Bindable = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
|
Current = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
|
||||||
ItemSource = windowModes,
|
ItemSource = windowModes,
|
||||||
},
|
},
|
||||||
resolutionSettingsContainer = new Container
|
resolutionSettingsContainer = new Container
|
||||||
@ -74,14 +74,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
{
|
{
|
||||||
LabelText = "UI Scaling",
|
LabelText = "UI Scaling",
|
||||||
TransferValueOnCommit = true,
|
TransferValueOnCommit = true,
|
||||||
Bindable = osuConfig.GetBindable<float>(OsuSetting.UIScale),
|
Current = osuConfig.GetBindable<float>(OsuSetting.UIScale),
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
Keywords = new[] { "scale", "letterbox" },
|
Keywords = new[] { "scale", "letterbox" },
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ScalingMode>
|
new SettingsEnumDropdown<ScalingMode>
|
||||||
{
|
{
|
||||||
LabelText = "Screen Scaling",
|
LabelText = "Screen Scaling",
|
||||||
Bindable = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling),
|
Current = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling),
|
||||||
Keywords = new[] { "scale", "letterbox" },
|
Keywords = new[] { "scale", "letterbox" },
|
||||||
},
|
},
|
||||||
scalingSettings = new FillFlowContainer<SettingsSlider<float>>
|
scalingSettings = new FillFlowContainer<SettingsSlider<float>>
|
||||||
@ -97,28 +97,28 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
new SettingsSlider<float>
|
new SettingsSlider<float>
|
||||||
{
|
{
|
||||||
LabelText = "Horizontal position",
|
LabelText = "Horizontal position",
|
||||||
Bindable = scalingPositionX,
|
Current = scalingPositionX,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<float>
|
new SettingsSlider<float>
|
||||||
{
|
{
|
||||||
LabelText = "Vertical position",
|
LabelText = "Vertical position",
|
||||||
Bindable = scalingPositionY,
|
Current = scalingPositionY,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<float>
|
new SettingsSlider<float>
|
||||||
{
|
{
|
||||||
LabelText = "Horizontal scale",
|
LabelText = "Horizontal scale",
|
||||||
Bindable = scalingSizeX,
|
Current = scalingSizeX,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
new SettingsSlider<float>
|
new SettingsSlider<float>
|
||||||
{
|
{
|
||||||
LabelText = "Vertical scale",
|
LabelText = "Vertical scale",
|
||||||
Bindable = scalingSizeY,
|
Current = scalingSizeY,
|
||||||
KeyboardStep = 0.01f,
|
KeyboardStep = 0.01f,
|
||||||
DisplayAsPercentage = true
|
DisplayAsPercentage = true
|
||||||
},
|
},
|
||||||
@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
scalingSettings.ForEach(s => bindPreviewEvent(s.Bindable));
|
scalingSettings.ForEach(s => bindPreviewEvent(s.Current));
|
||||||
|
|
||||||
var resolutions = getResolutions();
|
var resolutions = getResolutions();
|
||||||
|
|
||||||
@ -137,10 +137,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
LabelText = "Resolution",
|
LabelText = "Resolution",
|
||||||
ShowsDefaultIndicator = false,
|
ShowsDefaultIndicator = false,
|
||||||
Items = resolutions,
|
Items = resolutions,
|
||||||
Bindable = sizeFullscreen
|
Current = sizeFullscreen
|
||||||
};
|
};
|
||||||
|
|
||||||
windowModeDropdown.Bindable.BindValueChanged(mode =>
|
windowModeDropdown.Current.BindValueChanged(mode =>
|
||||||
{
|
{
|
||||||
if (mode.NewValue == WindowMode.Fullscreen)
|
if (mode.NewValue == WindowMode.Fullscreen)
|
||||||
{
|
{
|
||||||
|
@ -23,17 +23,17 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
new SettingsEnumDropdown<FrameSync>
|
new SettingsEnumDropdown<FrameSync>
|
||||||
{
|
{
|
||||||
LabelText = "Frame limiter",
|
LabelText = "Frame limiter",
|
||||||
Bindable = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync)
|
Current = config.GetBindable<FrameSync>(FrameworkSetting.FrameSync)
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ExecutionMode>
|
new SettingsEnumDropdown<ExecutionMode>
|
||||||
{
|
{
|
||||||
LabelText = "Threading mode",
|
LabelText = "Threading mode",
|
||||||
Bindable = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode)
|
Current = config.GetBindable<ExecutionMode>(FrameworkSetting.ExecutionMode)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show FPS",
|
LabelText = "Show FPS",
|
||||||
Bindable = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay)
|
Current = osuConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,17 +20,17 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Rotate cursor when dragging",
|
LabelText = "Rotate cursor when dragging",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.CursorRotation)
|
Current = config.GetBindable<bool>(OsuSetting.CursorRotation)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Parallax",
|
LabelText = "Parallax",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.MenuParallax)
|
Current = config.GetBindable<bool>(OsuSetting.MenuParallax)
|
||||||
},
|
},
|
||||||
new SettingsSlider<float, TimeSlider>
|
new SettingsSlider<float, TimeSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Hold-to-confirm activation time",
|
LabelText = "Hold-to-confirm activation time",
|
||||||
Bindable = config.GetBindable<float>(OsuSetting.UIHoldActivationDelay),
|
Current = config.GetBindable<float>(OsuSetting.UIHoldActivationDelay),
|
||||||
KeyboardStep = 50
|
KeyboardStep = 50
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -6,9 +6,9 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Input;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||||
{
|
{
|
||||||
@ -35,32 +35,32 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Raw input",
|
LabelText = "Raw input",
|
||||||
Bindable = rawInputToggle
|
Current = rawInputToggle
|
||||||
},
|
},
|
||||||
new SensitivitySetting
|
new SensitivitySetting
|
||||||
{
|
{
|
||||||
LabelText = "Cursor sensitivity",
|
LabelText = "Cursor sensitivity",
|
||||||
Bindable = sensitivityBindable
|
Current = sensitivityBindable
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Map absolute input to window",
|
LabelText = "Map absolute input to window",
|
||||||
Bindable = config.GetBindable<bool>(FrameworkSetting.MapAbsoluteInputToWindow)
|
Current = config.GetBindable<bool>(FrameworkSetting.MapAbsoluteInputToWindow)
|
||||||
},
|
},
|
||||||
new SettingsEnumDropdown<ConfineMouseMode>
|
new SettingsEnumDropdown<OsuConfineMouseMode>
|
||||||
{
|
{
|
||||||
LabelText = "Confine mouse cursor to window",
|
LabelText = "Confine mouse cursor to window",
|
||||||
Bindable = config.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode),
|
Current = osuConfig.GetBindable<OsuConfineMouseMode>(OsuSetting.ConfineMouseMode)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Disable mouse wheel during gameplay",
|
LabelText = "Disable mouse wheel during gameplay",
|
||||||
Bindable = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableWheel)
|
Current = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableWheel)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Disable mouse buttons during gameplay",
|
LabelText = "Disable mouse buttons during gameplay",
|
||||||
Bindable = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons)
|
Current = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ namespace osu.Game.Overlays.Settings.Sections.Online
|
|||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Warn about opening external links",
|
LabelText = "Warn about opening external links",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.ExternalLinkWarning)
|
Current = config.GetBindable<bool>(OsuSetting.ExternalLinkWarning)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Prefer downloads without video",
|
LabelText = "Prefer downloads without video",
|
||||||
Keywords = new[] { "no-video" },
|
Keywords = new[] { "no-video" },
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.PreferNoVideo)
|
Current = config.GetBindable<bool>(OsuSetting.PreferNoVideo)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -47,29 +47,29 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
new SettingsSlider<float, SizeSlider>
|
new SettingsSlider<float, SizeSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Menu cursor size",
|
LabelText = "Menu cursor size",
|
||||||
Bindable = config.GetBindable<float>(OsuSetting.MenuCursorSize),
|
Current = config.GetBindable<float>(OsuSetting.MenuCursorSize),
|
||||||
KeyboardStep = 0.01f
|
KeyboardStep = 0.01f
|
||||||
},
|
},
|
||||||
new SettingsSlider<float, SizeSlider>
|
new SettingsSlider<float, SizeSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Gameplay cursor size",
|
LabelText = "Gameplay cursor size",
|
||||||
Bindable = config.GetBindable<float>(OsuSetting.GameplayCursorSize),
|
Current = config.GetBindable<float>(OsuSetting.GameplayCursorSize),
|
||||||
KeyboardStep = 0.01f
|
KeyboardStep = 0.01f
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Adjust gameplay cursor size based on current beatmap",
|
LabelText = "Adjust gameplay cursor size based on current beatmap",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.AutoCursorSize)
|
Current = config.GetBindable<bool>(OsuSetting.AutoCursorSize)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Beatmap skins",
|
LabelText = "Beatmap skins",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.BeatmapSkins)
|
Current = config.GetBindable<bool>(OsuSetting.BeatmapSkins)
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Beatmap hitsounds",
|
LabelText = "Beatmap hitsounds",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds)
|
Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
|
|
||||||
config.BindWith(OsuSetting.Skin, configBindable);
|
config.BindWith(OsuSetting.Skin, configBindable);
|
||||||
|
|
||||||
skinDropdown.Bindable = dropdownBindable;
|
skinDropdown.Current = dropdownBindable;
|
||||||
skinDropdown.Items = skins.GetAllUsableSkins().ToArray();
|
skinDropdown.Items = skins.GetAllUsableSkins().ToArray();
|
||||||
|
|
||||||
// Todo: This should not be necessary when OsuConfigManager is databased
|
// Todo: This should not be necessary when OsuConfigManager is databased
|
||||||
|
@ -21,7 +21,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Overlays.Settings
|
namespace osu.Game.Overlays.Settings
|
||||||
{
|
{
|
||||||
public abstract class SettingsItem<T> : Container, IFilterable, ISettingsItem
|
public abstract class SettingsItem<T> : Container, IFilterable, ISettingsItem, IHasCurrentValue<T>
|
||||||
{
|
{
|
||||||
protected abstract Drawable CreateControl();
|
protected abstract Drawable CreateControl();
|
||||||
|
|
||||||
@ -54,7 +54,14 @@ namespace osu.Game.Overlays.Settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Bindable<T> Bindable
|
[Obsolete("Use Current instead")] // Can be removed 20210406
|
||||||
|
public Bindable<T> Bindable
|
||||||
|
{
|
||||||
|
get => Current;
|
||||||
|
set => Current = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Bindable<T> Current
|
||||||
{
|
{
|
||||||
get => controlWithCurrent.Current;
|
get => controlWithCurrent.Current;
|
||||||
set => controlWithCurrent.Current = value;
|
set => controlWithCurrent.Current = value;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
@ -16,19 +16,16 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
protected readonly DifficultyAttributes Attributes;
|
protected readonly DifficultyAttributes Attributes;
|
||||||
|
|
||||||
protected readonly Ruleset Ruleset;
|
protected readonly Ruleset Ruleset;
|
||||||
protected readonly IBeatmap Beatmap;
|
|
||||||
protected readonly ScoreInfo Score;
|
protected readonly ScoreInfo Score;
|
||||||
|
|
||||||
protected double TimeRate { get; private set; } = 1;
|
protected double TimeRate { get; private set; } = 1;
|
||||||
|
|
||||||
protected PerformanceCalculator(Ruleset ruleset, WorkingBeatmap beatmap, ScoreInfo score)
|
protected PerformanceCalculator(Ruleset ruleset, DifficultyAttributes attributes, ScoreInfo score)
|
||||||
{
|
{
|
||||||
Ruleset = ruleset;
|
Ruleset = ruleset;
|
||||||
Score = score;
|
Score = score;
|
||||||
|
|
||||||
Beatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods);
|
Attributes = attributes ?? throw new ArgumentNullException(nameof(attributes));
|
||||||
|
|
||||||
Attributes = ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods);
|
|
||||||
|
|
||||||
ApplyMods(score.Mods);
|
ApplyMods(score.Mods);
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
// apply any custom state overrides
|
// apply any custom state overrides
|
||||||
ApplyCustomUpdateState?.Invoke(this, newState);
|
ApplyCustomUpdateState?.Invoke(this, newState);
|
||||||
|
|
||||||
if (newState == ArmedState.Hit)
|
if (!force && newState == ArmedState.Hit)
|
||||||
PlaySamples();
|
PlaySamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hit windows for this <see cref="HitObject"/>.
|
/// The hit windows for this <see cref="HitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
public HitWindows HitWindows { get; set; }
|
public HitWindows HitWindows { get; set; }
|
||||||
|
|
||||||
private readonly List<HitObject> nestedHitObjects = new List<HitObject>();
|
private readonly List<HitObject> nestedHitObjects = new List<HitObject>();
|
||||||
|
@ -158,7 +158,28 @@ namespace osu.Game.Rulesets
|
|||||||
|
|
||||||
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);
|
||||||
|
|
||||||
public virtual PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => null;
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="PerformanceCalculator"/> to generate performance data from the provided score.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attributes">Difficulty attributes for the beatmap related to the provided score.</param>
|
||||||
|
/// <param name="score">The score to be processed.</param>
|
||||||
|
/// <returns>A performance calculator instance for the provided score.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public virtual PerformanceCalculator CreatePerformanceCalculator(DifficultyAttributes attributes, ScoreInfo score) => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optionally creates a <see cref="PerformanceCalculator"/> to generate performance data from the provided score.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to use as a source for generating <see cref="DifficultyAttributes"/>.</param>
|
||||||
|
/// <param name="score">The score to be processed.</param>
|
||||||
|
/// <returns>A performance calculator instance for the provided score.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score)
|
||||||
|
{
|
||||||
|
var difficultyCalculator = CreateDifficultyCalculator(beatmap);
|
||||||
|
var difficultyAttributes = difficultyCalculator.Calculate(score.Mods);
|
||||||
|
return CreatePerformanceCalculator(difficultyAttributes, score);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual HitObjectComposer CreateHitObjectComposer() => null;
|
public virtual HitObjectComposer CreateHitObjectComposer() => null;
|
||||||
|
|
||||||
|
@ -239,10 +239,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
private void deleteSelected()
|
private void deleteSelected()
|
||||||
{
|
{
|
||||||
ChangeHandler?.BeginChange();
|
ChangeHandler?.BeginChange();
|
||||||
|
EditorBeatmap?.RemoveRange(selectedBlueprints.Select(b => b.HitObject));
|
||||||
foreach (var h in selectedBlueprints.ToList())
|
|
||||||
EditorBeatmap?.Remove(h.HitObject);
|
|
||||||
|
|
||||||
ChangeHandler?.EndChange();
|
ChangeHandler?.EndChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,40 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
// no bindable so we perform this every update
|
// no bindable so we perform this every update
|
||||||
Width = (float)(HitObject.GetEndTime() - HitObject.StartTime);
|
float duration = (float)(HitObject.GetEndTime() - HitObject.StartTime);
|
||||||
|
|
||||||
|
if (Width != duration)
|
||||||
|
{
|
||||||
|
Width = duration;
|
||||||
|
|
||||||
|
// kind of haphazard but yeah, no bindables.
|
||||||
|
if (HitObject is IHasRepeats repeats)
|
||||||
|
updateRepeats(repeats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Container repeatsContainer;
|
||||||
|
|
||||||
|
private void updateRepeats(IHasRepeats repeats)
|
||||||
|
{
|
||||||
|
repeatsContainer?.Expire();
|
||||||
|
|
||||||
|
mainComponents.Add(repeatsContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < repeats.RepeatCount; i++)
|
||||||
|
{
|
||||||
|
repeatsContainer.Add(new Circle
|
||||||
|
{
|
||||||
|
Size = new Vector2(circle_size / 2),
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativePositionAxes = Axes.X,
|
||||||
|
X = (float)(i + 1) / (repeats.RepeatCount + 1),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ShouldBeConsideredForInput(Drawable child) => true;
|
protected override bool ShouldBeConsideredForInput(Drawable child) => true;
|
||||||
|
@ -484,8 +484,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
protected void Cut()
|
protected void Cut()
|
||||||
{
|
{
|
||||||
Copy();
|
Copy();
|
||||||
foreach (var h in editorBeatmap.SelectedHitObjects.ToArray())
|
editorBeatmap.RemoveRange(editorBeatmap.SelectedHitObjects.ToArray());
|
||||||
editorBeatmap.Remove(h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Copy()
|
protected void Copy()
|
||||||
@ -589,7 +588,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private void seek(UIEvent e, int direction)
|
private void seek(UIEvent e, int direction)
|
||||||
{
|
{
|
||||||
double amount = e.ShiftPressed ? 2 : 1;
|
double amount = e.ShiftPressed ? 4 : 1;
|
||||||
|
|
||||||
if (direction < 1)
|
if (direction < 1)
|
||||||
clock.SeekBackward(!clock.IsRunning, amount);
|
clock.SeekBackward(!clock.IsRunning, amount);
|
||||||
|
@ -91,14 +91,19 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private readonly HashSet<HitObject> pendingUpdates = new HashSet<HitObject>();
|
private readonly HashSet<HitObject> pendingUpdates = new HashSet<HitObject>();
|
||||||
|
|
||||||
|
private bool isBatchApplying;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>.
|
/// Adds a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hitObjects">The <see cref="HitObject"/>s to add.</param>
|
/// <param name="hitObjects">The <see cref="HitObject"/>s to add.</param>
|
||||||
public void AddRange(IEnumerable<HitObject> hitObjects)
|
public void AddRange(IEnumerable<HitObject> hitObjects)
|
||||||
{
|
{
|
||||||
foreach (var h in hitObjects)
|
ApplyBatchChanges(_ =>
|
||||||
Add(h);
|
{
|
||||||
|
foreach (var h in hitObjects)
|
||||||
|
Add(h);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -126,12 +131,17 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
mutableHitObjects.Insert(index, hitObject);
|
mutableHitObjects.Insert(index, hitObject);
|
||||||
|
|
||||||
// must be run after any change to hitobject ordering
|
if (isBatchApplying)
|
||||||
beatmapProcessor?.PreProcess();
|
batchPendingInserts.Add(hitObject);
|
||||||
processHitObject(hitObject);
|
else
|
||||||
beatmapProcessor?.PostProcess();
|
{
|
||||||
|
// must be run after any change to hitobject ordering
|
||||||
|
beatmapProcessor?.PreProcess();
|
||||||
|
processHitObject(hitObject);
|
||||||
|
beatmapProcessor?.PostProcess();
|
||||||
|
|
||||||
HitObjectAdded?.Invoke(hitObject);
|
HitObjectAdded?.Invoke(hitObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -159,6 +169,19 @@ namespace osu.Game.Screens.Edit
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a collection of <see cref="HitObject"/>s to this <see cref="EditorBeatmap"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObjects">The <see cref="HitObject"/>s to remove.</param>
|
||||||
|
public void RemoveRange(IEnumerable<HitObject> hitObjects)
|
||||||
|
{
|
||||||
|
ApplyBatchChanges(_ =>
|
||||||
|
{
|
||||||
|
foreach (var h in hitObjects)
|
||||||
|
Remove(h);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the index of a <see cref="HitObject"/> in this <see cref="EditorBeatmap"/>.
|
/// Finds the index of a <see cref="HitObject"/> in this <see cref="EditorBeatmap"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -180,22 +203,56 @@ namespace osu.Game.Screens.Edit
|
|||||||
bindable.UnbindAll();
|
bindable.UnbindAll();
|
||||||
startTimeBindables.Remove(hitObject);
|
startTimeBindables.Remove(hitObject);
|
||||||
|
|
||||||
// must be run after any change to hitobject ordering
|
if (isBatchApplying)
|
||||||
|
batchPendingDeletes.Add(hitObject);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// must be run after any change to hitobject ordering
|
||||||
|
beatmapProcessor?.PreProcess();
|
||||||
|
processHitObject(hitObject);
|
||||||
|
beatmapProcessor?.PostProcess();
|
||||||
|
|
||||||
|
HitObjectRemoved?.Invoke(hitObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<HitObject> batchPendingInserts = new List<HitObject>();
|
||||||
|
|
||||||
|
private readonly List<HitObject> batchPendingDeletes = new List<HitObject>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply a batch of operations in one go, without performing Pre/Postprocessing each time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="applyFunction">The function which will apply the batch changes.</param>
|
||||||
|
public void ApplyBatchChanges(Action<EditorBeatmap> applyFunction)
|
||||||
|
{
|
||||||
|
if (isBatchApplying)
|
||||||
|
throw new InvalidOperationException("Attempting to perform a batch application from within an existing batch");
|
||||||
|
|
||||||
|
isBatchApplying = true;
|
||||||
|
|
||||||
|
applyFunction(this);
|
||||||
|
|
||||||
beatmapProcessor?.PreProcess();
|
beatmapProcessor?.PreProcess();
|
||||||
processHitObject(hitObject);
|
|
||||||
|
foreach (var h in batchPendingDeletes) processHitObject(h);
|
||||||
|
foreach (var h in batchPendingInserts) processHitObject(h);
|
||||||
|
|
||||||
beatmapProcessor?.PostProcess();
|
beatmapProcessor?.PostProcess();
|
||||||
|
|
||||||
HitObjectRemoved?.Invoke(hitObject);
|
foreach (var h in batchPendingDeletes) HitObjectRemoved?.Invoke(h);
|
||||||
|
foreach (var h in batchPendingInserts) HitObjectAdded?.Invoke(h);
|
||||||
|
|
||||||
|
batchPendingDeletes.Clear();
|
||||||
|
batchPendingInserts.Clear();
|
||||||
|
|
||||||
|
isBatchApplying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears all <see cref="HitObjects"/> from this <see cref="EditorBeatmap"/>.
|
/// Clears all <see cref="HitObjects"/> from this <see cref="EditorBeatmap"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Clear()
|
public void Clear() => RemoveRange(HitObjects.ToArray());
|
||||||
{
|
|
||||||
foreach (var h in HitObjects.ToArray())
|
|
||||||
Remove(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
@ -258,5 +315,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
public double GetBeatLengthAtTime(double referenceTime) => ControlPointInfo.TimingPointAt(referenceTime).BeatLength / BeatDivisor;
|
public double GetBeatLengthAtTime(double referenceTime) => ControlPointInfo.TimingPointAt(referenceTime).BeatLength / BeatDivisor;
|
||||||
|
|
||||||
public int BeatDivisor => beatDivisor?.Value ?? 1;
|
public int BeatDivisor => beatDivisor?.Value ?? 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update all hit objects with potentially changed difficulty or control point data.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateBeatmap()
|
||||||
|
{
|
||||||
|
foreach (var h in HitObjects)
|
||||||
|
pendingUpdates.Add(h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="snapped">Whether to snap to the closest beat after seeking.</param>
|
/// <param name="snapped">Whether to snap to the closest beat after seeking.</param>
|
||||||
/// <param name="amount">The relative amount (magnitude) which should be seeked.</param>
|
/// <param name="amount">The relative amount (magnitude) which should be seeked.</param>
|
||||||
public void SeekBackward(bool snapped = false, double amount = 1) => seek(-1, snapped, amount);
|
public void SeekBackward(bool snapped = false, double amount = 1) => seek(-1, snapped, amount + (IsRunning ? 1.5 : 0));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seeks forwards by one beat length.
|
/// Seeks forwards by one beat length.
|
||||||
|
@ -68,16 +68,19 @@ namespace osu.Game.Screens.Edit
|
|||||||
toRemove.Sort();
|
toRemove.Sort();
|
||||||
toAdd.Sort();
|
toAdd.Sort();
|
||||||
|
|
||||||
// Apply the changes.
|
editorBeatmap.ApplyBatchChanges(eb =>
|
||||||
for (int i = toRemove.Count - 1; i >= 0; i--)
|
|
||||||
editorBeatmap.RemoveAt(toRemove[i]);
|
|
||||||
|
|
||||||
if (toAdd.Count > 0)
|
|
||||||
{
|
{
|
||||||
IBeatmap newBeatmap = readBeatmap(newState);
|
// Apply the changes.
|
||||||
foreach (var i in toAdd)
|
for (int i = toRemove.Count - 1; i >= 0; i--)
|
||||||
editorBeatmap.Insert(i, newBeatmap.HitObjects[i]);
|
eb.RemoveAt(toRemove[i]);
|
||||||
}
|
|
||||||
|
if (toAdd.Count > 0)
|
||||||
|
{
|
||||||
|
IBeatmap newBeatmap = readBeatmap(newState);
|
||||||
|
foreach (var i in toAdd)
|
||||||
|
eb.Insert(i, newBeatmap.HitObjects[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private string readString(byte[] state) => Encoding.UTF8.GetString(state);
|
private string readString(byte[] state) => Encoding.UTF8.GetString(state);
|
||||||
|
99
osu.Game/Screens/Edit/Setup/DifficultySection.cs
Normal file
99
osu.Game/Screens/Edit/Setup/DifficultySection.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
|
{
|
||||||
|
internal class DifficultySection : SetupSection
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private EditorBeatmap editorBeatmap { get; set; }
|
||||||
|
|
||||||
|
private LabelledSliderBar<float> circleSizeSlider;
|
||||||
|
private LabelledSliderBar<float> healthDrainSlider;
|
||||||
|
private LabelledSliderBar<float> approachRateSlider;
|
||||||
|
private LabelledSliderBar<float> overallDifficultySlider;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Difficulty settings"
|
||||||
|
},
|
||||||
|
circleSizeSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Object Size",
|
||||||
|
Description = "The size of all hit objects",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 2,
|
||||||
|
MaxValue = 7,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
healthDrainSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Health Drain",
|
||||||
|
Description = "The rate of passive health drain throughout playable time",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
approachRateSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Approach Rate",
|
||||||
|
Description = "The speed at which objects are presented to the player",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
overallDifficultySlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Overall Difficulty",
|
||||||
|
Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)",
|
||||||
|
Current = new BindableFloat(Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var item in Children.OfType<LabelledSliderBar<float>>())
|
||||||
|
item.Current.ValueChanged += onValueChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onValueChanged(ValueChangedEvent<float> args)
|
||||||
|
{
|
||||||
|
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
||||||
|
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize = circleSizeSlider.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.DrainRate = healthDrainSlider.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.ApproachRate = approachRateSlider.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.BaseDifficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
|
||||||
|
|
||||||
|
editorBeatmap.UpdateBeatmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs
Normal file
73
osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// 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 System.IO;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A labelled textbox which reveals an inline file chooser when clicked.
|
||||||
|
/// </summary>
|
||||||
|
internal class FileChooserLabelledTextBox : LabelledTextBox
|
||||||
|
{
|
||||||
|
public Container Target;
|
||||||
|
|
||||||
|
private readonly IBindable<FileInfo> currentFile = new Bindable<FileInfo>();
|
||||||
|
|
||||||
|
public FileChooserLabelledTextBox()
|
||||||
|
{
|
||||||
|
currentFile.BindValueChanged(onFileSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFileSelected(ValueChangedEvent<FileInfo> file)
|
||||||
|
{
|
||||||
|
if (file.NewValue == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Target.Clear();
|
||||||
|
Current.Value = file.NewValue.FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override OsuTextBox CreateTextBox() =>
|
||||||
|
new FileChooserOsuTextBox
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
CornerRadius = CORNER_RADIUS,
|
||||||
|
OnFocused = DisplayFileChooser
|
||||||
|
};
|
||||||
|
|
||||||
|
public void DisplayFileChooser()
|
||||||
|
{
|
||||||
|
Target.Child = new FileSelector(validFileExtensions: ResourcesSection.AudioExtensions)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 400,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
CurrentFile = { BindTarget = currentFile }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FileChooserOsuTextBox : OsuTextBox
|
||||||
|
{
|
||||||
|
public Action OnFocused;
|
||||||
|
|
||||||
|
protected override void OnFocus(FocusEvent e)
|
||||||
|
{
|
||||||
|
OnFocused?.Invoke();
|
||||||
|
base.OnFocus(e);
|
||||||
|
|
||||||
|
GetContainingInputManager().TriggerFocusContention(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
osu.Game/Screens/Edit/Setup/MetadataSection.cs
Normal file
71
osu.Game/Screens/Edit/Setup/MetadataSection.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
|
{
|
||||||
|
internal class MetadataSection : SetupSection
|
||||||
|
{
|
||||||
|
private LabelledTextBox artistTextBox;
|
||||||
|
private LabelledTextBox titleTextBox;
|
||||||
|
private LabelledTextBox creatorTextBox;
|
||||||
|
private LabelledTextBox difficultyTextBox;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Beatmap metadata"
|
||||||
|
},
|
||||||
|
artistTextBox = new LabelledTextBox
|
||||||
|
{
|
||||||
|
Label = "Artist",
|
||||||
|
Current = { Value = Beatmap.Value.Metadata.Artist },
|
||||||
|
TabbableContentContainer = this
|
||||||
|
},
|
||||||
|
titleTextBox = new LabelledTextBox
|
||||||
|
{
|
||||||
|
Label = "Title",
|
||||||
|
Current = { Value = Beatmap.Value.Metadata.Title },
|
||||||
|
TabbableContentContainer = this
|
||||||
|
},
|
||||||
|
creatorTextBox = new LabelledTextBox
|
||||||
|
{
|
||||||
|
Label = "Creator",
|
||||||
|
Current = { Value = Beatmap.Value.Metadata.AuthorString },
|
||||||
|
TabbableContentContainer = this
|
||||||
|
},
|
||||||
|
difficultyTextBox = new LabelledTextBox
|
||||||
|
{
|
||||||
|
Label = "Difficulty Name",
|
||||||
|
Current = { Value = Beatmap.Value.BeatmapInfo.Version },
|
||||||
|
TabbableContentContainer = this
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var item in Children.OfType<LabelledTextBox>())
|
||||||
|
item.OnCommit += onCommit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCommit(TextBox sender, bool newText)
|
||||||
|
{
|
||||||
|
if (!newText) return;
|
||||||
|
|
||||||
|
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
||||||
|
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
||||||
|
Beatmap.Value.Metadata.Artist = artistTextBox.Current.Value;
|
||||||
|
Beatmap.Value.Metadata.Title = titleTextBox.Current.Value;
|
||||||
|
Beatmap.Value.Metadata.AuthorString = creatorTextBox.Current.Value;
|
||||||
|
Beatmap.Value.BeatmapInfo.Version = difficultyTextBox.Current.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
211
osu.Game/Screens/Edit/Setup/ResourcesSection.cs
Normal file
211
osu.Game/Screens/Edit/Setup/ResourcesSection.cs
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
// 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;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
|
{
|
||||||
|
internal class ResourcesSection : SetupSection, ICanAcceptFiles
|
||||||
|
{
|
||||||
|
private LabelledTextBox audioTrackTextBox;
|
||||||
|
private Container backgroundSpriteContainer;
|
||||||
|
|
||||||
|
public IEnumerable<string> HandledExtensions => ImageExtensions.Concat(AudioExtensions);
|
||||||
|
|
||||||
|
public static string[] ImageExtensions { get; } = { ".jpg", ".jpeg", ".png" };
|
||||||
|
|
||||||
|
public static string[] AudioExtensions { get; } = { ".mp3", ".ogg" };
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuGameBase game { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private MusicController music { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private Editor editor { get; set; }
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Container audioTrackFileChooserContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
};
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
backgroundSpriteContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 250,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 10,
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Resources"
|
||||||
|
},
|
||||||
|
audioTrackTextBox = new FileChooserLabelledTextBox
|
||||||
|
{
|
||||||
|
Label = "Audio Track",
|
||||||
|
Current = { Value = Beatmap.Value.Metadata.AudioFile ?? "Click to select a track" },
|
||||||
|
Target = audioTrackFileChooserContainer,
|
||||||
|
TabbableContentContainer = this
|
||||||
|
},
|
||||||
|
audioTrackFileChooserContainer,
|
||||||
|
};
|
||||||
|
|
||||||
|
updateBackgroundSprite();
|
||||||
|
|
||||||
|
audioTrackTextBox.Current.BindValueChanged(audioTrackChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task ICanAcceptFiles.Import(params string[] paths)
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
var firstFile = new FileInfo(paths.First());
|
||||||
|
|
||||||
|
if (ImageExtensions.Contains(firstFile.Extension))
|
||||||
|
{
|
||||||
|
ChangeBackgroundImage(firstFile.FullName);
|
||||||
|
}
|
||||||
|
else if (AudioExtensions.Contains(firstFile.Extension))
|
||||||
|
{
|
||||||
|
audioTrackTextBox.Text = firstFile.FullName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
game.RegisterImportHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeBackgroundImage(string path)
|
||||||
|
{
|
||||||
|
var info = new FileInfo(path);
|
||||||
|
|
||||||
|
if (!info.Exists)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var set = Beatmap.Value.BeatmapSetInfo;
|
||||||
|
|
||||||
|
// remove the previous background for now.
|
||||||
|
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
|
||||||
|
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.BackgroundFile);
|
||||||
|
|
||||||
|
using (var stream = info.OpenRead())
|
||||||
|
{
|
||||||
|
if (oldFile != null)
|
||||||
|
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
|
||||||
|
else
|
||||||
|
beatmaps.AddFile(set, stream, info.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Beatmap.Value.Metadata.BackgroundFile = info.Name;
|
||||||
|
updateBackgroundSprite();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
game?.UnregisterImportHandler(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeAudioTrack(string path)
|
||||||
|
{
|
||||||
|
var info = new FileInfo(path);
|
||||||
|
|
||||||
|
if (!info.Exists)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var set = Beatmap.Value.BeatmapSetInfo;
|
||||||
|
|
||||||
|
// remove the previous audio track for now.
|
||||||
|
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
|
||||||
|
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.AudioFile);
|
||||||
|
|
||||||
|
using (var stream = info.OpenRead())
|
||||||
|
{
|
||||||
|
if (oldFile != null)
|
||||||
|
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
|
||||||
|
else
|
||||||
|
beatmaps.AddFile(set, stream, info.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Beatmap.Value.Metadata.AudioFile = info.Name;
|
||||||
|
|
||||||
|
music.ReloadCurrentTrack();
|
||||||
|
|
||||||
|
editor?.UpdateClockSource();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void audioTrackChanged(ValueChangedEvent<string> filePath)
|
||||||
|
{
|
||||||
|
if (!ChangeAudioTrack(filePath.NewValue))
|
||||||
|
audioTrackTextBox.Current.Value = filePath.OldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBackgroundSprite()
|
||||||
|
{
|
||||||
|
LoadComponentAsync(new BeatmapBackgroundSprite(Beatmap.Value)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
FillMode = FillMode.Fill,
|
||||||
|
}, background =>
|
||||||
|
{
|
||||||
|
if (background.Texture != null)
|
||||||
|
backgroundSpriteContainer.Child = background;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backgroundSpriteContainer.Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Colours.GreySeafoamDarker,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 24))
|
||||||
|
{
|
||||||
|
Text = "Drag image here to set beatmap background!",
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
background.FadeInFromZero(500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,73 +1,33 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.Drawables;
|
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Setup
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
{
|
{
|
||||||
public class SetupScreen : EditorScreen, ICanAcceptFiles
|
public class SetupScreen : EditorScreen
|
||||||
{
|
{
|
||||||
public IEnumerable<string> HandledExtensions => ImageExtensions.Concat(AudioExtensions);
|
|
||||||
|
|
||||||
public static string[] ImageExtensions { get; } = { ".jpg", ".jpeg", ".png" };
|
|
||||||
|
|
||||||
public static string[] AudioExtensions { get; } = { ".mp3", ".ogg" };
|
|
||||||
|
|
||||||
private FillFlowContainer flow;
|
|
||||||
private LabelledTextBox artistTextBox;
|
|
||||||
private LabelledTextBox titleTextBox;
|
|
||||||
private LabelledTextBox creatorTextBox;
|
|
||||||
private LabelledTextBox difficultyTextBox;
|
|
||||||
private LabelledTextBox audioTrackTextBox;
|
|
||||||
private Container backgroundSpriteContainer;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuGameBase game { get; set; }
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Cached]
|
||||||
private MusicController music { get; set; }
|
protected readonly OverlayColourProvider ColourProvider;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private BeatmapManager beatmaps { get; set; }
|
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private Editor editor { get; set; }
|
|
||||||
|
|
||||||
public SetupScreen()
|
public SetupScreen()
|
||||||
: base(EditorScreenMode.SongSetup)
|
: base(EditorScreenMode.SongSetup)
|
||||||
{
|
{
|
||||||
|
ColourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load()
|
||||||
{
|
{
|
||||||
Container audioTrackFileChooserContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
};
|
|
||||||
|
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -84,253 +44,34 @@ namespace osu.Game.Screens.Edit.Setup
|
|||||||
Colour = colours.GreySeafoamDark,
|
Colour = colours.GreySeafoamDark,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
new OsuScrollContainer
|
new SectionsContainer<SetupSection>
|
||||||
{
|
{
|
||||||
|
FixedHeader = new SetupScreenHeader(),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding(10),
|
Children = new SetupSection[]
|
||||||
Child = flow = new FillFlowContainer
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
new ResourcesSection(),
|
||||||
AutoSizeAxes = Axes.Y,
|
new MetadataSection(),
|
||||||
Spacing = new Vector2(20),
|
new DifficultySection(),
|
||||||
Direction = FillDirection.Vertical,
|
}
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
backgroundSpriteContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 250,
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 10,
|
|
||||||
},
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = "Resources"
|
|
||||||
},
|
|
||||||
audioTrackTextBox = new FileChooserLabelledTextBox
|
|
||||||
{
|
|
||||||
Label = "Audio Track",
|
|
||||||
Current = { Value = Beatmap.Value.Metadata.AudioFile ?? "Click to select a track" },
|
|
||||||
Target = audioTrackFileChooserContainer,
|
|
||||||
TabbableContentContainer = this
|
|
||||||
},
|
|
||||||
audioTrackFileChooserContainer,
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = "Beatmap metadata"
|
|
||||||
},
|
|
||||||
artistTextBox = new LabelledTextBox
|
|
||||||
{
|
|
||||||
Label = "Artist",
|
|
||||||
Current = { Value = Beatmap.Value.Metadata.Artist },
|
|
||||||
TabbableContentContainer = this
|
|
||||||
},
|
|
||||||
titleTextBox = new LabelledTextBox
|
|
||||||
{
|
|
||||||
Label = "Title",
|
|
||||||
Current = { Value = Beatmap.Value.Metadata.Title },
|
|
||||||
TabbableContentContainer = this
|
|
||||||
},
|
|
||||||
creatorTextBox = new LabelledTextBox
|
|
||||||
{
|
|
||||||
Label = "Creator",
|
|
||||||
Current = { Value = Beatmap.Value.Metadata.AuthorString },
|
|
||||||
TabbableContentContainer = this
|
|
||||||
},
|
|
||||||
difficultyTextBox = new LabelledTextBox
|
|
||||||
{
|
|
||||||
Label = "Difficulty Name",
|
|
||||||
Current = { Value = Beatmap.Value.BeatmapInfo.Version },
|
|
||||||
TabbableContentContainer = this
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateBackgroundSprite();
|
|
||||||
|
|
||||||
audioTrackTextBox.Current.BindValueChanged(audioTrackChanged);
|
|
||||||
|
|
||||||
foreach (var item in flow.OfType<LabelledTextBox>())
|
|
||||||
item.OnCommit += onCommit;
|
|
||||||
}
|
|
||||||
|
|
||||||
Task ICanAcceptFiles.Import(params string[] paths)
|
|
||||||
{
|
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
var firstFile = new FileInfo(paths.First());
|
|
||||||
|
|
||||||
if (ImageExtensions.Contains(firstFile.Extension))
|
|
||||||
{
|
|
||||||
ChangeBackgroundImage(firstFile.FullName);
|
|
||||||
}
|
|
||||||
else if (AudioExtensions.Contains(firstFile.Extension))
|
|
||||||
{
|
|
||||||
audioTrackTextBox.Text = firstFile.FullName;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBackgroundSprite()
|
|
||||||
{
|
|
||||||
LoadComponentAsync(new BeatmapBackgroundSprite(Beatmap.Value)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
FillMode = FillMode.Fill,
|
|
||||||
}, background =>
|
|
||||||
{
|
|
||||||
backgroundSpriteContainer.Child = background;
|
|
||||||
background.FadeInFromZero(500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
game.RegisterImportHandler(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ChangeBackgroundImage(string path)
|
|
||||||
{
|
|
||||||
var info = new FileInfo(path);
|
|
||||||
|
|
||||||
if (!info.Exists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var set = Beatmap.Value.BeatmapSetInfo;
|
|
||||||
|
|
||||||
// remove the previous background for now.
|
|
||||||
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
|
|
||||||
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.BackgroundFile);
|
|
||||||
|
|
||||||
using (var stream = info.OpenRead())
|
|
||||||
{
|
|
||||||
if (oldFile != null)
|
|
||||||
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
|
|
||||||
else
|
|
||||||
beatmaps.AddFile(set, stream, info.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Beatmap.Value.Metadata.BackgroundFile = info.Name;
|
|
||||||
updateBackgroundSprite();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ChangeAudioTrack(string path)
|
|
||||||
{
|
|
||||||
var info = new FileInfo(path);
|
|
||||||
|
|
||||||
if (!info.Exists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var set = Beatmap.Value.BeatmapSetInfo;
|
|
||||||
|
|
||||||
// remove the previous audio track for now.
|
|
||||||
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
|
|
||||||
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.AudioFile);
|
|
||||||
|
|
||||||
using (var stream = info.OpenRead())
|
|
||||||
{
|
|
||||||
if (oldFile != null)
|
|
||||||
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
|
|
||||||
else
|
|
||||||
beatmaps.AddFile(set, stream, info.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Beatmap.Value.Metadata.AudioFile = info.Name;
|
|
||||||
|
|
||||||
music.ReloadCurrentTrack();
|
|
||||||
|
|
||||||
editor?.UpdateClockSource();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void audioTrackChanged(ValueChangedEvent<string> filePath)
|
|
||||||
{
|
|
||||||
if (!ChangeAudioTrack(filePath.NewValue))
|
|
||||||
audioTrackTextBox.Current.Value = filePath.OldValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onCommit(TextBox sender, bool newText)
|
|
||||||
{
|
|
||||||
if (!newText) return;
|
|
||||||
|
|
||||||
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
|
||||||
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
|
||||||
Beatmap.Value.Metadata.Artist = artistTextBox.Current.Value;
|
|
||||||
Beatmap.Value.Metadata.Title = titleTextBox.Current.Value;
|
|
||||||
Beatmap.Value.Metadata.AuthorString = creatorTextBox.Current.Value;
|
|
||||||
Beatmap.Value.BeatmapInfo.Version = difficultyTextBox.Current.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
|
||||||
{
|
|
||||||
base.Dispose(isDisposing);
|
|
||||||
game?.UnregisterImportHandler(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class FileChooserLabelledTextBox : LabelledTextBox
|
internal class SetupScreenHeader : OverlayHeader
|
||||||
{
|
{
|
||||||
public Container Target;
|
protected override OverlayTitle CreateTitle() => new SetupScreenTitle();
|
||||||
|
|
||||||
private readonly IBindable<FileInfo> currentFile = new Bindable<FileInfo>();
|
private class SetupScreenTitle : OverlayTitle
|
||||||
|
|
||||||
public FileChooserLabelledTextBox()
|
|
||||||
{
|
{
|
||||||
currentFile.BindValueChanged(onFileSelected);
|
public SetupScreenTitle()
|
||||||
}
|
|
||||||
|
|
||||||
private void onFileSelected(ValueChangedEvent<FileInfo> file)
|
|
||||||
{
|
|
||||||
if (file.NewValue == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Target.Clear();
|
|
||||||
Current.Value = file.NewValue.FullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override OsuTextBox CreateTextBox() =>
|
|
||||||
new FileChooserOsuTextBox
|
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Title = "beatmap setup";
|
||||||
Origin = Anchor.Centre,
|
Description = "change general settings of your beatmap";
|
||||||
RelativeSizeAxes = Axes.X,
|
IconTexture = "Icons/Hexacons/social";
|
||||||
CornerRadius = CORNER_RADIUS,
|
|
||||||
OnFocused = DisplayFileChooser
|
|
||||||
};
|
|
||||||
|
|
||||||
public void DisplayFileChooser()
|
|
||||||
{
|
|
||||||
Target.Child = new FileSelector(validFileExtensions: SetupScreen.AudioExtensions)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 400,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
CurrentFile = { BindTarget = currentFile }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class FileChooserOsuTextBox : OsuTextBox
|
|
||||||
{
|
|
||||||
public Action OnFocused;
|
|
||||||
|
|
||||||
protected override void OnFocus(FocusEvent e)
|
|
||||||
{
|
|
||||||
OnFocused?.Invoke();
|
|
||||||
base.OnFocus(e);
|
|
||||||
|
|
||||||
GetContainingInputManager().TriggerFocusContention(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
osu.Game/Screens/Edit/Setup/SetupSection.cs
Normal file
42
osu.Game/Screens/Edit/Setup/SetupSection.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 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.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit.Setup
|
||||||
|
{
|
||||||
|
internal class SetupSection : Container
|
||||||
|
{
|
||||||
|
private readonly FillFlowContainer flow;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
protected OsuColour Colours { get; private set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => flow;
|
||||||
|
|
||||||
|
public SetupSection()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
Padding = new MarginPadding(10);
|
||||||
|
|
||||||
|
InternalChild = flow = new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Spacing = new Vector2(20),
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -113,7 +113,6 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
};
|
};
|
||||||
|
|
||||||
controlPoints = group.ControlPoints.GetBoundCopy();
|
controlPoints = group.ControlPoints.GetBoundCopy();
|
||||||
controlPoints.CollectionChanged += (_, __) => createChildren();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -125,6 +124,12 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
createChildren();
|
createChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
controlPoints.CollectionChanged += (_, __) => createChildren();
|
||||||
|
}
|
||||||
|
|
||||||
private void createChildren()
|
private void createChildren()
|
||||||
{
|
{
|
||||||
fill.ChildrenEnumerable = controlPoints.Select(createAttribute).Where(c => c != null);
|
fill.ChildrenEnumerable = controlPoints.Select(createAttribute).Where(c => c != null);
|
||||||
|
@ -111,7 +111,8 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
foreach (var cp in currentGroupItems)
|
foreach (var cp in currentGroupItems)
|
||||||
Beatmap.Value.Beatmap.ControlPointInfo.Add(time, cp);
|
Beatmap.Value.Beatmap.ControlPointInfo.Add(time, cp);
|
||||||
|
|
||||||
SelectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(time);
|
// the control point might not necessarily exist yet, if currentGroupItems was empty.
|
||||||
|
SelectedGroup.Value = Beatmap.Value.Beatmap.ControlPointInfo.GroupAt(time, true);
|
||||||
|
|
||||||
changeHandler?.EndChange();
|
changeHandler?.EndChange();
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Timing
|
namespace osu.Game.Screens.Edit.Timing
|
||||||
{
|
{
|
||||||
internal class SliderWithTextBoxInput<T> : CompositeDrawable, IHasCurrentValue<T>
|
public class SliderWithTextBoxInput<T> : CompositeDrawable, IHasCurrentValue<T>
|
||||||
where T : struct, IEquatable<T>, IComparable<T>, IConvertible
|
where T : struct, IEquatable<T>, IComparable<T>, IConvertible
|
||||||
{
|
{
|
||||||
private readonly SettingsSlider<T> slider;
|
private readonly SettingsSlider<T> slider;
|
||||||
@ -51,7 +51,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
slider.Bindable.Parse(t.Text);
|
slider.Current.Parse(t.Text);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -71,8 +71,8 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
|
|
||||||
public Bindable<T> Current
|
public Bindable<T> Current
|
||||||
{
|
{
|
||||||
get => slider.Bindable;
|
get => slider.Current;
|
||||||
set => slider.Bindable = value;
|
set => slider.Current = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,14 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
{
|
{
|
||||||
if (point.NewValue != null)
|
if (point.NewValue != null)
|
||||||
{
|
{
|
||||||
bpmSlider.Bindable = point.NewValue.BeatLengthBindable;
|
bpmSlider.Current = point.NewValue.BeatLengthBindable;
|
||||||
bpmSlider.Bindable.BindValueChanged(_ => ChangeHandler?.SaveState());
|
bpmSlider.Current.BindValueChanged(_ => ChangeHandler?.SaveState());
|
||||||
|
|
||||||
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
||||||
// no need to hook change handler here as it's the same bindable as above
|
// no need to hook change handler here as it's the same bindable as above
|
||||||
|
|
||||||
timeSignature.Bindable = point.NewValue.TimeSignatureBindable;
|
timeSignature.Current = point.NewValue.TimeSignatureBindable;
|
||||||
timeSignature.Bindable.BindValueChanged(_ => ChangeHandler?.SaveState());
|
timeSignature.Current.BindValueChanged(_ => ChangeHandler?.SaveState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,14 +121,14 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
beatLengthBindable.BindValueChanged(beatLength => updateCurrent(beatLengthToBpm(beatLength.NewValue)), true);
|
beatLengthBindable.BindValueChanged(beatLength => updateCurrent(beatLengthToBpm(beatLength.NewValue)), true);
|
||||||
bpmBindable.BindValueChanged(bpm => beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
|
bpmBindable.BindValueChanged(bpm => beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
|
||||||
|
|
||||||
base.Bindable = bpmBindable;
|
base.Current = bpmBindable;
|
||||||
|
|
||||||
TransferValueOnCommit = true;
|
TransferValueOnCommit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Bindable<double> Bindable
|
public override Bindable<double> Current
|
||||||
{
|
{
|
||||||
get => base.Bindable;
|
get => base.Current;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
// incoming will be beat length, not bpm
|
// incoming will be beat length, not bpm
|
||||||
|
@ -42,8 +42,11 @@ namespace osu.Game.Screens.Menu
|
|||||||
ValidForResume = false;
|
ValidForResume = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, IAPIProvider api)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -104,7 +107,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
iconColour = colours.Yellow;
|
iconColour = colours.Yellow;
|
||||||
|
|
||||||
currentUser.BindTo(api.LocalUser);
|
// manually transfer the user once, but only do the final bind in LoadComplete to avoid thread woes (API scheduler could run while this screen is still loading).
|
||||||
|
// the manual transfer is here to ensure all text content is loaded ahead of time as this is very early in the game load process and we want to avoid stutters.
|
||||||
|
currentUser.Value = api.LocalUser.Value;
|
||||||
currentUser.BindValueChanged(e =>
|
currentUser.BindValueChanged(e =>
|
||||||
{
|
{
|
||||||
supportFlow.Children.ForEach(d => d.FadeOut().Expire());
|
supportFlow.Children.ForEach(d => d.FadeOut().Expire());
|
||||||
@ -141,6 +146,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
if (nextScreen != null)
|
if (nextScreen != null)
|
||||||
LoadComponentAsync(nextScreen);
|
LoadComponentAsync(nextScreen);
|
||||||
|
|
||||||
|
currentUser.BindTo(api.LocalUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnEntering(IScreen last)
|
public override void OnEntering(IScreen last)
|
||||||
|
@ -68,6 +68,8 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private readonly Bindable<bool> storyboardReplacesBackground = new Bindable<bool>();
|
private readonly Bindable<bool> storyboardReplacesBackground = new Bindable<bool>();
|
||||||
|
|
||||||
|
protected readonly Bindable<bool> LocalUserPlaying = new Bindable<bool>();
|
||||||
|
|
||||||
public int RestartCount;
|
public int RestartCount;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -155,8 +157,8 @@ namespace osu.Game.Screens.Play
|
|||||||
DrawableRuleset.SetRecordTarget(recordingReplay = new Replay());
|
DrawableRuleset.SetRecordTarget(recordingReplay = new Replay());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(AudioManager audio, OsuConfigManager config)
|
private void load(AudioManager audio, OsuConfigManager config, OsuGame game)
|
||||||
{
|
{
|
||||||
Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray();
|
Mods.Value = base.Mods.Value.Select(m => m.CreateCopy()).ToArray();
|
||||||
|
|
||||||
@ -172,6 +174,9 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||||
|
|
||||||
|
if (game != null)
|
||||||
|
LocalUserPlaying.BindTo(game.LocalUserPlaying);
|
||||||
|
|
||||||
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);
|
DrawableRuleset = ruleset.CreateDrawableRulesetWith(playableBeatmap, Mods.Value);
|
||||||
|
|
||||||
ScoreProcessor = ruleset.CreateScoreProcessor();
|
ScoreProcessor = ruleset.CreateScoreProcessor();
|
||||||
@ -219,9 +224,9 @@ namespace osu.Game.Screens.Play
|
|||||||
skipOverlay.Hide();
|
skipOverlay.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawableRuleset.IsPaused.BindValueChanged(_ => updateOverlayActivationMode());
|
DrawableRuleset.IsPaused.BindValueChanged(_ => updateGameplayState());
|
||||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateOverlayActivationMode());
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateGameplayState());
|
||||||
breakTracker.IsBreakTime.BindValueChanged(_ => updateOverlayActivationMode());
|
breakTracker.IsBreakTime.BindValueChanged(_ => updateGameplayState());
|
||||||
|
|
||||||
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updatePauseOnFocusLostState(), true);
|
||||||
|
|
||||||
@ -353,14 +358,11 @@ namespace osu.Game.Screens.Play
|
|||||||
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
|
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOverlayActivationMode()
|
private void updateGameplayState()
|
||||||
{
|
{
|
||||||
bool canTriggerOverlays = DrawableRuleset.IsPaused.Value || breakTracker.IsBreakTime.Value;
|
bool inGameplay = !DrawableRuleset.HasReplayLoaded.Value && !DrawableRuleset.IsPaused.Value && !breakTracker.IsBreakTime.Value;
|
||||||
|
OverlayActivationMode.Value = inGameplay ? OverlayActivation.Disabled : OverlayActivation.UserTriggered;
|
||||||
if (DrawableRuleset.HasReplayLoaded.Value || canTriggerOverlays)
|
LocalUserPlaying.Value = inGameplay;
|
||||||
OverlayActivationMode.Value = OverlayActivation.UserTriggered;
|
|
||||||
else
|
|
||||||
OverlayActivationMode.Value = OverlayActivation.Disabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePauseOnFocusLostState() =>
|
private void updatePauseOnFocusLostState() =>
|
||||||
@ -441,6 +443,10 @@ namespace osu.Game.Screens.Play
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Restart()
|
public void Restart()
|
||||||
{
|
{
|
||||||
|
// at the point of restarting the track should either already be paused or the volume should be zero.
|
||||||
|
// stopping here is to ensure music doesn't become audible after exiting back to PlayerLoader.
|
||||||
|
musicController.Stop();
|
||||||
|
|
||||||
sampleRestart?.Play();
|
sampleRestart?.Play();
|
||||||
RestartRequested?.Invoke();
|
RestartRequested?.Invoke();
|
||||||
|
|
||||||
@ -657,7 +663,7 @@ namespace osu.Game.Screens.Play
|
|||||||
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
|
||||||
mod.ApplyToTrack(musicController.CurrentTrack);
|
mod.ApplyToTrack(musicController.CurrentTrack);
|
||||||
|
|
||||||
updateOverlayActivationMode();
|
updateGameplayState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSuspending(IScreen next)
|
public override void OnSuspending(IScreen next)
|
||||||
|
@ -51,14 +51,14 @@ namespace osu.Game.Screens.Play.PlayerSettings
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
rateSlider = new PlayerSliderBar<double> { Bindable = UserPlaybackRate }
|
rateSlider = new PlayerSliderBar<double> { Current = UserPlaybackRate }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
rateSlider.Bindable.BindValueChanged(multiplier => multiplierText.Text = $"{multiplier.NewValue:0.0}x", true);
|
rateSlider.Current.BindValueChanged(multiplier => multiplierText.Text = $"{multiplier.NewValue:0.0}x", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,8 @@ namespace osu.Game.Screens.Play.PlayerSettings
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
dimSliderBar.Bindable = config.GetBindable<double>(OsuSetting.DimLevel);
|
dimSliderBar.Current = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||||
blurSliderBar.Bindable = config.GetBindable<double>(OsuSetting.BlurLevel);
|
blurSliderBar.Current = config.GetBindable<double>(OsuSetting.BlurLevel);
|
||||||
showStoryboardToggle.Current = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
showStoryboardToggle.Current = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||||
beatmapSkinsToggle.Current = config.GetBindable<bool>(OsuSetting.BeatmapSkins);
|
beatmapSkinsToggle.Current = config.GetBindable<bool>(OsuSetting.BeatmapSkins);
|
||||||
beatmapHitsoundsToggle.Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds);
|
beatmapHitsoundsToggle.Current = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds);
|
||||||
|
@ -84,6 +84,11 @@ namespace osu.Game.Updater
|
|||||||
bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".AppImage"));
|
bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".AppImage"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RuntimeInfo.Platform.iOS:
|
||||||
|
// iOS releases are available via testflight. this link seems to work well enough for now.
|
||||||
|
// see https://stackoverflow.com/a/32960501
|
||||||
|
return "itms-beta://beta.itunes.apple.com/v1/app/1447765923";
|
||||||
|
|
||||||
case RuntimeInfo.Platform.Android:
|
case RuntimeInfo.Platform.Android:
|
||||||
// on our testing device this causes the download to magically disappear.
|
// on our testing device this causes the download to magically disappear.
|
||||||
//bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk"));
|
//bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".apk"));
|
||||||
|
@ -11,5 +11,7 @@ namespace osu.iOS
|
|||||||
public class OsuGameIOS : OsuGame
|
public class OsuGameIOS : OsuGame
|
||||||
{
|
{
|
||||||
public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString());
|
public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString());
|
||||||
|
|
||||||
|
protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user