1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-05 03:22:55 +08:00

Compare commits

...

47 Commits

Author SHA1 Message Date
Dan Balasescu
5675bfc5b9
Merge 1d232dca8d into ce8e4120b7 2024-12-02 19:24:33 -06:00
Dean Herbert
ce8e4120b7
Merge pull request #30947 from bdach/undesirable-deselect-on-control-click
Do not deselect objects when control-clicking without hitting anything
2024-12-02 07:17:27 -08:00
Bartłomiej Dach
b505ecc7ba
Do not deselect objects when control-clicking without hitting anything
As per feedback in
https://discord.com/channels/90072389919997952/1259818301517725707/1310270647187935284.
2024-12-02 13:51:43 +01:00
Bartłomiej Dach
b14dde937d
Add failing test case 2024-12-02 13:51:41 +01:00
Bartłomiej Dach
6c0ccc5ebe
Merge pull request #30863 from frenzibyte/improve-back-button-display
Delay back button appearance when performing a quick restart
2024-12-02 11:49:45 +01:00
Bartłomiej Dach
52b8753a12
Merge pull request #30749 from Sheppsu/multi-spectator-settings-sidebar
Add player settings to multi spectator screen
2024-12-02 11:34:57 +01:00
Dean Herbert
5b2558cec2
Merge pull request #28473 from bdach/beatmap-info-purge
Move unnecessary properties from `BeatmapInfo` / realm to `IBeatmap`
2024-12-02 16:19:12 +09:00
Dean Herbert
23522b02d8
Use local instead of field for local only usage 2024-12-01 19:53:57 +09:00
Dean Herbert
6afe083ec9
Fix settings showing up during gameplay 2024-12-01 18:44:26 +09:00
Dean Herbert
ddac71628d
Merge branch 'master' into multi-spectator-settings-sidebar 2024-12-01 18:33:46 +09:00
Salman Alshamrani
932afcde01 Make editor make sense 2024-11-28 17:43:32 -05:00
Salman Alshamrani
f792b6de00 Fix comment 2024-11-27 06:07:10 -05:00
Salman Alshamrani
4ae3ccfe48 Make BackButtonVisibility in game class private 2024-11-27 06:05:02 -05:00
Dean Herbert
0f73941808
Combine new implementation back into the old one and use everywhere 2024-11-27 17:47:42 +09:00
Dean Herbert
7fdf13911b
Adjust the colour of non-pinned settings groups' headers to be more legible 2024-11-27 17:47:27 +09:00
Dean Herbert
782ce24ca6
Move player settings out of right flow 2024-11-27 17:09:15 +09:00
Dean Herbert
9c707ed341
Rename class and fix padding considerations 2024-11-27 16:47:54 +09:00
Dean Herbert
5ce55e9cb4
Merge branch 'master' into multi-spectator-settings-sidebar 2024-11-27 16:35:05 +09:00
Salman Alshamrani
3e1b4f4ac5 Rename AllowBackButton to AllowUserExit and rewrite visibility flow structure
Co-authored-by: Dean Herbert <pe@ppy.sh>
2024-11-26 16:52:39 -05:00
Bartłomiej Dach
46d1f00590
Fix Beatmap.Countdown not being copied on conversion 2024-11-26 11:39:03 +01:00
Bartłomiej Dach
cf905d0f5c
Merge branch 'master' into beatmap-info-purge 2024-11-26 10:21:16 +01:00
Salman Alshamrani
ae9119eef0 Hide back button when quick-restarting unless load time takes long 2024-11-24 05:40:06 -05:00
Salman Alshamrani
2420793466 Allow controlling back button visibility state from screens 2024-11-24 05:39:43 -05:00
Sheppsu
3713bb48b7 expand and contract settings from hover 2024-11-23 01:09:58 -05:00
Bartłomiej Dach
ead7e99c59
Fix incorrect comment 2024-11-22 11:06:36 +01:00
Dean Herbert
086a34f5c0
Merge branch 'master' into beatmap-info-purge 2024-11-22 18:47:32 +09:00
Sheppsu
7d4062d2ad remove redundant Scale attribute 2024-11-18 04:04:28 -05:00
Sheppsu
29e7adcd3b add player settings to multi spectator screen 2024-11-18 03:57:50 -05:00
Dan Balasescu
1d232dca8d
Add default multiplier for mania key mods 2024-11-05 14:16:36 +09:00
Dean Herbert
58fe502af4
Merge branch 'master' into beatmap-info-purge 2024-09-15 04:53:35 +09:00
Bartłomiej Dach
1d4d806362
Fix WidescreenStoryboard breakage after moving out of BeatmapInfo 2024-07-23 12:19:45 +02:00
Dean Herbert
d707e29ff7
Merge branch 'master' into beatmap-info-purge 2024-07-23 12:09:32 +09:00
Bartłomiej Dach
04527f3c9d
Fix TestBeatmap not transferring newly migrated properties 2024-06-13 09:30:09 +02:00
Bartłomiej Dach
c67e2dc301
Bump schema version 2024-06-13 09:30:08 +02:00
Bartłomiej Dach
9fbf2872e1
Remove no longer applicable region marking 2024-06-12 14:27:40 +02:00
Bartłomiej Dach
dd50d6fa6e
Move CountdownOffset out of BeatmapInfo 2024-06-12 14:15:00 +02:00
Bartłomiej Dach
d373f752d6
Move Countdown out of BeatmapInfo 2024-06-12 14:15:00 +02:00
Bartłomiej Dach
7f2a6f6f5a
Move TimelineZoom out of BeatmapInfo 2024-06-12 14:15:00 +02:00
Bartłomiej Dach
6685c5ab74
Move GridSize out of BeatmapInfo 2024-06-12 14:15:00 +02:00
Bartłomiej Dach
3634307d7c
Move DistanceSpacing out of BeatmapInfo 2024-06-12 14:14:58 +02:00
Bartłomiej Dach
c216283bf4
Move SamplesMatchPlaybackRate out of BeatmapInfo 2024-06-12 13:32:23 +02:00
Bartłomiej Dach
f64a0624a5
Move EpilepsyWarning out of BeatmapInfo 2024-06-12 13:28:41 +02:00
Bartłomiej Dach
1ab86ebd24
Move WidescreenStoryboard out of BeatmapInfo 2024-06-12 13:23:53 +02:00
Bartłomiej Dach
a6b7600bf2
Move LetterboxInBreaks out of BeatmapInfo 2024-06-12 13:18:44 +02:00
Bartłomiej Dach
011c2e3651
Move SpecialStyle out of BeatmapInfo 2024-06-12 13:12:30 +02:00
Bartłomiej Dach
0a4560a03e
Move StackLeniency out of BeatmapInfo 2024-06-12 13:04:33 +02:00
Bartłomiej Dach
4339e2dc4a
Move AudioLeadIn out of BeatmapInfo 2024-06-12 13:04:28 +02:00
57 changed files with 556 additions and 232 deletions

View File

@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
{
Caption = "Use special (N+1) style",
HintText = "Changes one column to act as a classic \"scratch\" or \"special\" column, which can be moved around by the user's skin (to the left/right/centre). Generally used in 6K (5+1) or 8K (7+1) configurations.",
Current = { Value = Beatmap.BeatmapInfo.SpecialStyle }
Current = { Value = Beatmap.SpecialStyle }
},
healthDrainSlider = new FormSliderBar<float>
{
@ -157,7 +157,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup
// 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.Difficulty.CircleSize = keyCountSlider.Current.Value;
Beatmap.BeatmapInfo.SpecialStyle = specialStyle.Current.Value;
Beatmap.SpecialStyle = specialStyle.Current.Value;
Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
Beatmap.Difficulty.SliderMultiplier = baseVelocitySlider.Current.Value;

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => Name;
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
public override double ScoreMultiplier => 0.9;
public override bool Ranked => UsesDefaultConfiguration;
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)

View File

@ -231,6 +231,36 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
AddAssert("slider still has 2 anchors", () => secondSlider.Path.ControlPoints.Count, () => Is.EqualTo(2));
}
[Test]
public void TestControlClickDoesNotDiscardExistingSelectionEvenIfNothingHit()
{
var firstSlider = new Slider
{
StartTime = 0,
Position = new Vector2(0, 0),
Path = new SliderPath
{
ControlPoints =
{
new PathControlPoint(),
new PathControlPoint(new Vector2(100))
}
}
};
AddStep("add object", () => EditorBeatmap.AddRange([firstSlider]));
AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.AddRange([firstSlider]));
AddStep("move mouse to middle of playfield", () => InputManager.MoveMouseTo(blueprintContainer.ScreenSpaceDrawQuad.Centre));
AddStep("control-click left mouse", () =>
{
InputManager.PressKey(Key.ControlLeft);
InputManager.Click(MouseButton.Left);
InputManager.ReleaseKey(Key.ControlLeft);
});
AddAssert("selection preserved", () => EditorBeatmap.SelectedHitObjects.Count, () => Is.EqualTo(1));
}
private ComposeBlueprintContainer blueprintContainer
=> Editor.ChildrenOfType<ComposeBlueprintContainer>().First();

View File

@ -191,7 +191,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
private void gridSizeIs(int size)
=> AddAssert($"grid size is {size}", () => this.ChildrenOfType<RectangularPositionSnapGrid>().Single().Spacing.Value == new Vector2(size)
&& EditorBeatmap.BeatmapInfo.GridSize == size);
&& EditorBeatmap.GridSize == size);
[Test]
public void TestGridTypeToggling()

View File

@ -83,10 +83,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
})
}
},
BeatmapInfo =
{
StackLeniency = 0,
}
StackLeniency = 0,
},
ReplayFrames = new List<ReplayFrame>
{

View File

@ -74,12 +74,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
{
BeatmapInfo = new BeatmapInfo
{
StackLeniency = 0,
Difficulty = new BeatmapDifficulty
{
ApproachRate = 8.5f
}
},
StackLeniency = 0,
ControlPointInfo = controlPointInfo
};

View File

@ -465,7 +465,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void performTest(List<ReplayFrame> frames, Beatmap<OsuHitObject> beatmap)
{
beatmap.BeatmapInfo.Ruleset = new OsuRuleset().RulesetInfo;
beatmap.BeatmapInfo.StackLeniency = 0;
beatmap.StackLeniency = 0;
beatmap.BeatmapInfo.Difficulty = new BeatmapDifficulty
{
SliderMultiplier = 4,

View File

@ -56,13 +56,13 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
h.StackHeight = 0;
if (beatmap.BeatmapInfo.BeatmapVersion >= 6)
applyStacking(beatmap.BeatmapInfo, hitObjects, 0, hitObjects.Count - 1);
applyStacking(beatmap, hitObjects, 0, hitObjects.Count - 1);
else
applyStackingOld(beatmap.BeatmapInfo, hitObjects);
applyStackingOld(beatmap, hitObjects);
}
}
private static void applyStacking(BeatmapInfo beatmapInfo, List<OsuHitObject> hitObjects, int startIndex, int endIndex)
private static void applyStacking(IBeatmap beatmap, List<OsuHitObject> hitObjects, int startIndex, int endIndex)
{
ArgumentOutOfRangeException.ThrowIfGreaterThan(startIndex, endIndex);
ArgumentOutOfRangeException.ThrowIfNegative(startIndex);
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
continue;
double endTime = stackBaseObject.GetEndTime();
double stackThreshold = objectN.TimePreempt * beatmapInfo.StackLeniency;
double stackThreshold = objectN.TimePreempt * beatmap.StackLeniency;
if (objectN.StartTime - endTime > stackThreshold)
// We are no longer within stacking range of the next object.
@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
OsuHitObject objectI = hitObjects[i];
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
double stackThreshold = objectI.TimePreempt * beatmapInfo.StackLeniency;
double stackThreshold = objectI.TimePreempt * beatmap.StackLeniency;
/* If this object is a hitcircle, then we enter this "special" case.
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
@ -214,7 +214,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
}
}
private static void applyStackingOld(BeatmapInfo beatmapInfo, List<OsuHitObject> hitObjects)
private static void applyStackingOld(IBeatmap beatmap, List<OsuHitObject> hitObjects)
{
for (int i = 0; i < hitObjects.Count; i++)
{
@ -228,7 +228,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
for (int j = i + 1; j < hitObjects.Count; j++)
{
double stackThreshold = hitObjects[i].TimePreempt * beatmapInfo.StackLeniency;
double stackThreshold = hitObjects[i].TimePreempt * beatmap.StackLeniency;
if (hitObjects[j].StartTime - stackThreshold > startTime)
break;

View File

@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Edit
},
};
Spacing.Value = editorBeatmap.BeatmapInfo.GridSize;
Spacing.Value = editorBeatmap.GridSize;
}
protected override void LoadComplete()
@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.Osu.Edit
spacingSlider.ContractedLabelText = $"S: {spacing.NewValue:#,0.##}";
spacingSlider.ExpandedLabelText = $"Spacing: {spacing.NewValue:#,0.##}";
SpacingVector.Value = new Vector2(spacing.NewValue);
editorBeatmap.BeatmapInfo.GridSize = (int)spacing.NewValue;
editorBeatmap.GridSize = (int)spacing.NewValue;
}, true);
GridLinesRotation.BindValueChanged(rotation =>

View File

@ -119,7 +119,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Setup
{
Caption = "Stack Leniency",
HintText = "In play mode, osu! automatically stacks notes which occur at the same location. Increasing this value means it is more likely to snap notes of further time-distance.",
Current = new BindableFloat(Beatmap.BeatmapInfo.StackLeniency)
Current = new BindableFloat(Beatmap.StackLeniency)
{
Default = 0.7f,
MinValue = 0,
@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Setup
Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
Beatmap.Difficulty.SliderMultiplier = baseVelocitySlider.Current.Value;
Beatmap.Difficulty.SliderTickRate = tickRateSlider.Current.Value;
Beatmap.BeatmapInfo.StackLeniency = stackLeniency.Current.Value;
Beatmap.StackLeniency = stackLeniency.Current.Value;
Beatmap.UpdateAllHitObjects();
Beatmap.SaveState();

View File

@ -80,16 +80,16 @@ namespace osu.Game.Tests.Beatmaps.Formats
var metadata = beatmap.Metadata;
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", metadata.AudioFile);
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(0, beatmap.AudioLeadIn);
Assert.AreEqual(164471, metadata.PreviewTime);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(0.7f, beatmap.StackLeniency);
Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0);
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
Assert.IsFalse(beatmapInfo.SpecialStyle);
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
Assert.IsFalse(beatmapInfo.SamplesMatchPlaybackRate);
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
Assert.AreEqual(0, beatmapInfo.CountdownOffset);
Assert.IsFalse(beatmap.LetterboxInBreaks);
Assert.IsFalse(beatmap.SpecialStyle);
Assert.IsFalse(beatmap.WidescreenStoryboard);
Assert.IsFalse(beatmap.SamplesMatchPlaybackRate);
Assert.AreEqual(CountdownType.None, beatmap.Countdown);
Assert.AreEqual(0, beatmap.CountdownOffset);
}
}
@ -101,7 +101,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var resStream = TestResources.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
using (var stream = new LineBufferedReader(resStream))
{
var beatmapInfo = decoder.Decode(stream).BeatmapInfo;
var beatmap = decoder.Decode(stream);
int[] expectedBookmarks =
{
@ -109,13 +109,13 @@ namespace osu.Game.Tests.Beatmaps.Formats
95901, 106450, 116999, 119637, 130186, 140735, 151285,
161834, 164471, 175020, 185570, 196119, 206669, 209306
};
Assert.AreEqual(expectedBookmarks.Length, beatmapInfo.Bookmarks.Length);
Assert.AreEqual(expectedBookmarks.Length, beatmap.BeatmapInfo.Bookmarks.Length);
for (int i = 0; i < expectedBookmarks.Length; i++)
Assert.AreEqual(expectedBookmarks[i], beatmapInfo.Bookmarks[i]);
Assert.AreEqual(1.8, beatmapInfo.DistanceSpacing);
Assert.AreEqual(4, beatmapInfo.BeatDivisor);
Assert.AreEqual(4, beatmapInfo.GridSize);
Assert.AreEqual(2, beatmapInfo.TimelineZoom);
Assert.AreEqual(expectedBookmarks[i], beatmap.BeatmapInfo.Bookmarks[i]);
Assert.AreEqual(1.8, beatmap.DistanceSpacing);
Assert.AreEqual(4, beatmap.BeatmapInfo.BeatDivisor);
Assert.AreEqual(4, beatmap.GridSize);
Assert.AreEqual(2, beatmap.TimelineZoom);
}
}
@ -993,15 +993,15 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.Multiple(() =>
{
Assert.That(decoded.BeatmapInfo.AudioLeadIn, Is.EqualTo(0));
Assert.That(decoded.BeatmapInfo.StackLeniency, Is.EqualTo(0.7f));
Assert.That(decoded.BeatmapInfo.SpecialStyle, Is.False);
Assert.That(decoded.BeatmapInfo.LetterboxInBreaks, Is.False);
Assert.That(decoded.BeatmapInfo.WidescreenStoryboard, Is.False);
Assert.That(decoded.BeatmapInfo.EpilepsyWarning, Is.False);
Assert.That(decoded.BeatmapInfo.SamplesMatchPlaybackRate, Is.False);
Assert.That(decoded.BeatmapInfo.Countdown, Is.EqualTo(CountdownType.None));
Assert.That(decoded.BeatmapInfo.CountdownOffset, Is.EqualTo(0));
Assert.That(decoded.AudioLeadIn, Is.EqualTo(0));
Assert.That(decoded.StackLeniency, Is.EqualTo(0.7f));
Assert.That(decoded.SpecialStyle, Is.False);
Assert.That(decoded.LetterboxInBreaks, Is.False);
Assert.That(decoded.WidescreenStoryboard, Is.False);
Assert.That(decoded.EpilepsyWarning, Is.False);
Assert.That(decoded.SamplesMatchPlaybackRate, Is.False);
Assert.That(decoded.Countdown, Is.EqualTo(CountdownType.None));
Assert.That(decoded.CountdownOffset, Is.EqualTo(0));
Assert.That(decoded.BeatmapInfo.Metadata.PreviewTime, Is.EqualTo(-1));
Assert.That(decoded.BeatmapInfo.Ruleset.OnlineID, Is.EqualTo(0));
});

View File

@ -51,14 +51,14 @@ namespace osu.Game.Tests.Beatmaps.Formats
{
var beatmap = decodeAsJson(normal);
var beatmapInfo = beatmap.BeatmapInfo;
Assert.AreEqual(0, beatmapInfo.AudioLeadIn);
Assert.AreEqual(0.7f, beatmapInfo.StackLeniency);
Assert.AreEqual(false, beatmapInfo.SpecialStyle);
Assert.AreEqual(0, beatmap.AudioLeadIn);
Assert.AreEqual(0.7f, beatmap.StackLeniency);
Assert.AreEqual(false, beatmap.SpecialStyle);
Assert.IsTrue(beatmapInfo.Ruleset.OnlineID == 0);
Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks);
Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard);
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
Assert.AreEqual(0, beatmapInfo.CountdownOffset);
Assert.AreEqual(false, beatmap.LetterboxInBreaks);
Assert.AreEqual(false, beatmap.WidescreenStoryboard);
Assert.AreEqual(CountdownType.None, beatmap.Countdown);
Assert.AreEqual(0, beatmap.CountdownOffset);
}
[Test]
@ -76,10 +76,10 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(expectedBookmarks.Length, beatmapInfo.Bookmarks.Length);
for (int i = 0; i < expectedBookmarks.Length; i++)
Assert.AreEqual(expectedBookmarks[i], beatmapInfo.Bookmarks[i]);
Assert.AreEqual(1.8, beatmapInfo.DistanceSpacing);
Assert.AreEqual(1.8, beatmap.DistanceSpacing);
Assert.AreEqual(4, beatmapInfo.BeatDivisor);
Assert.AreEqual(4, beatmapInfo.GridSize);
Assert.AreEqual(2, beatmapInfo.TimelineZoom);
Assert.AreEqual(4, beatmap.GridSize);
Assert.AreEqual(2, beatmap.TimelineZoom);
}
[Test]

View File

@ -41,7 +41,7 @@ namespace osu.Game.Tests.Database
Assert.That(lastChanges?.ModifiedIndices, Is.Empty);
Assert.That(lastChanges?.NewModifiedIndices, Is.Empty);
realm.Write(r => r.All<BeatmapSetInfo>().First().Beatmaps.First().CountdownOffset = 5);
realm.Write(r => r.All<BeatmapSetInfo>().First().Beatmaps.First().EditorTimestamp = 5);
realm.Run(r => r.Refresh());
Assert.That(collectionChanges, Is.EqualTo(1));

View File

@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Editing
{
AddStep("turn countdown off", () => designSection.EnableCountdown.Current.Value = false);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.None);
AddAssert("beatmap has correct type", () => editorBeatmap.Countdown == CountdownType.None);
AddUntilStep("other controls hidden", () => !designSection.CountdownSettings.IsPresent);
}
@ -65,12 +65,12 @@ namespace osu.Game.Tests.Visual.Editing
{
AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal);
AddAssert("beatmap has correct type", () => editorBeatmap.Countdown == CountdownType.Normal);
AddUntilStep("other controls shown", () => designSection.CountdownSettings.IsPresent);
AddStep("change countdown speed", () => designSection.CountdownSpeed.Current.Value = CountdownType.DoubleSpeed);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.DoubleSpeed);
AddAssert("beatmap has correct type", () => editorBeatmap.Countdown == CountdownType.DoubleSpeed);
AddUntilStep("other controls still shown", () => designSection.CountdownSettings.IsPresent);
}
@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.Editing
{
AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true);
AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal);
AddAssert("beatmap has correct type", () => editorBeatmap.Countdown == CountdownType.Normal);
checkOffsetAfter("1", 1);
checkOffsetAfter(string.Empty, 0);
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("commit text", () => InputManager.Key(Key.Enter));
AddAssert($"displayed value is {expectedFinalValue}", () => designSection.CountdownOffset.Current.Value == expectedFinalValue.ToString(CultureInfo.InvariantCulture));
AddAssert($"beatmap value is {expectedFinalValue}", () => editorBeatmap.BeatmapInfo.CountdownOffset == expectedFinalValue);
AddAssert($"beatmap value is {expectedFinalValue}", () => editorBeatmap.CountdownOffset == expectedFinalValue);
}
private partial class TestDesignSection : DesignSection

View File

@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("Set beat divisor", () => Editor.Dependencies.Get<BindableBeatDivisor>().Value = 16);
AddStep("Set timeline zoom", () =>
{
originalTimelineZoom = EditorBeatmap.BeatmapInfo.TimelineZoom;
originalTimelineZoom = EditorBeatmap.TimelineZoom;
var timeline = Editor.ChildrenOfType<Timeline>().Single();
InputManager.MoveMouseTo(timeline);
@ -81,19 +81,19 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("Ensure timeline zoom changed", () =>
{
changedTimelineZoom = EditorBeatmap.BeatmapInfo.TimelineZoom;
changedTimelineZoom = EditorBeatmap.TimelineZoom;
return !Precision.AlmostEquals(changedTimelineZoom, originalTimelineZoom);
});
SaveEditor();
AddAssert("Beatmap has correct beat divisor", () => EditorBeatmap.BeatmapInfo.BeatDivisor == 16);
AddAssert("Beatmap has correct timeline zoom", () => EditorBeatmap.BeatmapInfo.TimelineZoom == changedTimelineZoom);
AddAssert("Beatmap has correct timeline zoom", () => EditorBeatmap.TimelineZoom == changedTimelineZoom);
ReloadEditorToSameBeatmap();
AddAssert("Beatmap still has correct beat divisor", () => EditorBeatmap.BeatmapInfo.BeatDivisor == 16);
AddAssert("Beatmap still has correct timeline zoom", () => EditorBeatmap.BeatmapInfo.TimelineZoom == changedTimelineZoom);
AddAssert("Beatmap still has correct timeline zoom", () => EditorBeatmap.TimelineZoom == changedTimelineZoom);
}
[Test]

View File

@ -205,7 +205,7 @@ namespace osu.Game.Tests.Visual.Editing
{
double originalSpacing = 0;
AddStep("retrieve original spacing", () => originalSpacing = editorBeatmap.BeatmapInfo.DistanceSpacing);
AddStep("retrieve original spacing", () => originalSpacing = editorBeatmap.DistanceSpacing);
AddStep("hold ctrl", () => InputManager.PressKey(Key.LControl));
AddStep("hold alt", () => InputManager.PressKey(Key.LAlt));
@ -215,7 +215,7 @@ namespace osu.Game.Tests.Visual.Editing
AddStep("release alt", () => InputManager.ReleaseKey(Key.LAlt));
AddStep("release ctrl", () => InputManager.ReleaseKey(Key.LControl));
AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5);
AddAssert("distance spacing increased by 0.5", () => editorBeatmap.DistanceSpacing == originalSpacing + 0.5);
}
public partial class EditorBeatmapContainer : PopoverContainer

View File

@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo = { AudioLeadIn = leadIn }
AudioLeadIn = leadIn
});
checkFirstFrameTime(expectedStartTime);
@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
Text = $"GameplayStartTime: {DrawableRuleset.GameplayStartTime} "
+ $"FirstHitObjectTime: {FirstHitObjectTime} "
+ $"LeadInTime: {Beatmap.Value.BeatmapInfo.AudioLeadIn} "
+ $"LeadInTime: {Beatmap.Value.Beatmap.AudioLeadIn} "
+ $"FirstFrameClockTime: {FirstFrameClockTime}"
});
}

View File

@ -136,10 +136,10 @@ namespace osu.Game.Tests.Visual.Gameplay
var workingBeatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
// Add intro time to test quick retry skipping (TestQuickRetry).
workingBeatmap.BeatmapInfo.AudioLeadIn = 60000;
workingBeatmap.Beatmap.AudioLeadIn = 60000;
// Set up data for testing disclaimer display.
workingBeatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning ?? false;
workingBeatmap.Beatmap.EpilepsyWarning = epilepsyWarning ?? false;
workingBeatmap.BeatmapInfo.Status = onlineStatus ?? BeatmapOnlineStatus.Ranked;
Beatmap.Value = workingBeatmap;

View File

@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay
{
loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo = { AudioLeadIn = 60000 }
AudioLeadIn = 60000
});
AddUntilStep("wait for skip overlay", () => Player.ChildrenOfType<SkipOverlay>().First().IsButtonVisible);

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("load storyboard with only video", () =>
{
// LegacyStoryboardDecoder doesn't parse WidescreenStoryboard, so it is set manually
loadStoryboard("storyboard_only_video.osu", s => s.BeatmapInfo.WidescreenStoryboard = false);
loadStoryboard("storyboard_only_video.osu", s => s.Beatmap.WidescreenStoryboard = false);
});
AddAssert("storyboard is correct width", () => Precision.AlmostEquals(storyboard?.Width ?? 0f, 480 * 16 / 9f));

View File

@ -406,13 +406,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
}
/// <summary>
/// Tests spectating with a beatmap that has a high <see cref="BeatmapInfo.AudioLeadIn"/> value.
/// Tests spectating with a beatmap that has a high <see cref="IBeatmap.AudioLeadIn"/> value.
///
/// This test is not intended not to check the correct initial time value, but only to guard against
/// gameplay potentially getting stuck in a stopped state due to lead in time being present.
/// </summary>
[Test]
public void TestAudioLeadIn() => testLeadIn(b => b.BeatmapInfo.AudioLeadIn = 2000);
public void TestAudioLeadIn() => testLeadIn(b => b.Beatmap.AudioLeadIn = 2000);
/// <summary>
/// Tests spectating with a beatmap that has a storyboard element with a negative start time (i.e. intro storyboard element).

View File

@ -115,6 +115,30 @@ namespace osu.Game.Beatmaps
return mostCommon.beatLength;
}
public double AudioLeadIn { get; set; }
public float StackLeniency { get; set; } = 0.7f;
public bool SpecialStyle { get; set; }
public bool LetterboxInBreaks { get; set; }
public bool WidescreenStoryboard { get; set; } = true;
public bool EpilepsyWarning { get; set; }
public bool SamplesMatchPlaybackRate { get; set; }
public double DistanceSpacing { get; set; } = 1.0;
public int GridSize { get; set; }
public double TimelineZoom { get; set; } = 1.0;
public CountdownType Countdown { get; set; } = CountdownType.None;
public int CountdownOffset { get; set; }
IBeatmap IBeatmap.Clone() => Clone();
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();

View File

@ -73,6 +73,18 @@ namespace osu.Game.Beatmaps
beatmap.HitObjects = convertHitObjects(original.HitObjects, original, cancellationToken).OrderBy(s => s.StartTime).ToList();
beatmap.Breaks = original.Breaks;
beatmap.UnhandledEventLines = original.UnhandledEventLines;
beatmap.AudioLeadIn = original.AudioLeadIn;
beatmap.StackLeniency = original.StackLeniency;
beatmap.SpecialStyle = original.SpecialStyle;
beatmap.LetterboxInBreaks = original.LetterboxInBreaks;
beatmap.WidescreenStoryboard = original.WidescreenStoryboard;
beatmap.EpilepsyWarning = original.EpilepsyWarning;
beatmap.SamplesMatchPlaybackRate = original.SamplesMatchPlaybackRate;
beatmap.DistanceSpacing = original.DistanceSpacing;
beatmap.GridSize = original.GridSize;
beatmap.TimelineZoom = original.TimelineZoom;
beatmap.Countdown = original.Countdown;
beatmap.CountdownOffset = original.CountdownOffset;
return beatmap;
}

View File

@ -428,17 +428,7 @@ namespace osu.Game.Beatmaps
Hash = hash,
DifficultyName = decodedInfo.DifficultyName,
OnlineID = decodedInfo.OnlineID,
AudioLeadIn = decodedInfo.AudioLeadIn,
StackLeniency = decodedInfo.StackLeniency,
SpecialStyle = decodedInfo.SpecialStyle,
LetterboxInBreaks = decodedInfo.LetterboxInBreaks,
WidescreenStoryboard = decodedInfo.WidescreenStoryboard,
EpilepsyWarning = decodedInfo.EpilepsyWarning,
SamplesMatchPlaybackRate = decodedInfo.SamplesMatchPlaybackRate,
DistanceSpacing = decodedInfo.DistanceSpacing,
BeatDivisor = decodedInfo.BeatDivisor,
GridSize = decodedInfo.GridSize,
TimelineZoom = decodedInfo.TimelineZoom,
MD5Hash = memoryStream.ComputeMD5Hash(),
EndTimeObjectCount = decoded.HitObjects.Count(h => h is IHasDuration),
TotalObjectCount = decoded.HitObjects.Count

View File

@ -6,14 +6,12 @@ using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Collections;
using osu.Game.Database;
using osu.Game.Models;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit;
using osu.Game.Scoring;
using Realms;
@ -136,60 +134,18 @@ namespace osu.Game.Beatmaps
Status = BeatmapOnlineStatus.None;
}
#region Properties we may not want persisted (but also maybe no harm?)
public double AudioLeadIn { get; set; }
public float StackLeniency { get; set; } = 0.7f;
public bool SpecialStyle { get; set; }
public bool LetterboxInBreaks { get; set; }
public bool WidescreenStoryboard { get; set; } = true;
public bool EpilepsyWarning { get; set; }
public bool SamplesMatchPlaybackRate { get; set; }
/// <summary>
/// The time at which this beatmap was last played by the local user.
/// </summary>
public DateTimeOffset? LastPlayed { get; set; }
/// <summary>
/// The ratio of distance travelled per time unit.
/// Generally used to decouple the spacing between hit objects from the enforced "velocity" of the beatmap (see <see cref="DifficultyControlPoint.SliderVelocity"/>).
/// </summary>
/// <remarks>
/// The most common method of understanding is that at a default value of 1.0, the time-to-distance ratio will match the slider velocity of the beatmap
/// at the current point in time. Increasing this value will make hit objects more spaced apart when compared to the cursor movement required to track a slider.
///
/// This is only a hint property, used by the editor in <see cref="IDistanceSnapProvider"/> implementations. It does not directly affect the beatmap or gameplay.
/// </remarks>
public double DistanceSpacing { get; set; } = 1.0;
public int BeatDivisor { get; set; } = 4;
public int GridSize { get; set; }
public double TimelineZoom { get; set; } = 1.0;
/// <summary>
/// The time in milliseconds when last exiting the editor with this beatmap loaded.
/// </summary>
public double? EditorTimestamp { get; set; }
[Ignored]
public CountdownType Countdown { get; set; } = CountdownType.None;
/// <summary>
/// The number of beats to move the countdown backwards (compared to its default location).
/// </summary>
public int CountdownOffset { get; set; }
#endregion
public bool Equals(BeatmapInfo? other)
{
if (ReferenceEquals(this, other)) return true;

View File

@ -82,7 +82,7 @@ namespace osu.Game.Beatmaps.Formats
this.beatmap.BeatmapInfo.BeatmapVersion = FormatVersion;
parser = new ConvertHitObjectParser(getOffsetTime(), FormatVersion);
applyLegacyDefaults(this.beatmap.BeatmapInfo);
ApplyLegacyDefaults(this.beatmap);
base.ParseStreamInto(stream, beatmap);
@ -190,9 +190,9 @@ namespace osu.Game.Beatmaps.Formats
/// This method's intention is to restore those legacy defaults.
/// See also: https://osu.ppy.sh/wiki/en/Client/File_formats/Osu_%28file_format%29
/// </summary>
private static void applyLegacyDefaults(BeatmapInfo beatmapInfo)
internal static void ApplyLegacyDefaults(Beatmap beatmap)
{
beatmapInfo.WidescreenStoryboard = false;
beatmap.WidescreenStoryboard = false;
}
protected override void ParseLine(Beatmap beatmap, Section section, string line)
@ -244,7 +244,7 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"AudioLeadIn":
beatmap.BeatmapInfo.AudioLeadIn = Parsing.ParseInt(pair.Value);
beatmap.AudioLeadIn = Parsing.ParseInt(pair.Value);
break;
case @"PreviewTime":
@ -261,7 +261,7 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"StackLeniency":
beatmap.BeatmapInfo.StackLeniency = Parsing.ParseFloat(pair.Value);
beatmap.StackLeniency = Parsing.ParseFloat(pair.Value);
break;
case @"Mode":
@ -269,31 +269,31 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"LetterboxInBreaks":
beatmap.BeatmapInfo.LetterboxInBreaks = Parsing.ParseInt(pair.Value) == 1;
beatmap.LetterboxInBreaks = Parsing.ParseInt(pair.Value) == 1;
break;
case @"SpecialStyle":
beatmap.BeatmapInfo.SpecialStyle = Parsing.ParseInt(pair.Value) == 1;
beatmap.SpecialStyle = Parsing.ParseInt(pair.Value) == 1;
break;
case @"WidescreenStoryboard":
beatmap.BeatmapInfo.WidescreenStoryboard = Parsing.ParseInt(pair.Value) == 1;
beatmap.WidescreenStoryboard = Parsing.ParseInt(pair.Value) == 1;
break;
case @"EpilepsyWarning":
beatmap.BeatmapInfo.EpilepsyWarning = Parsing.ParseInt(pair.Value) == 1;
beatmap.EpilepsyWarning = Parsing.ParseInt(pair.Value) == 1;
break;
case @"SamplesMatchPlaybackRate":
beatmap.BeatmapInfo.SamplesMatchPlaybackRate = Parsing.ParseInt(pair.Value) == 1;
beatmap.SamplesMatchPlaybackRate = Parsing.ParseInt(pair.Value) == 1;
break;
case @"Countdown":
beatmap.BeatmapInfo.Countdown = Enum.Parse<CountdownType>(pair.Value);
beatmap.Countdown = Enum.Parse<CountdownType>(pair.Value);
break;
case @"CountdownOffset":
beatmap.BeatmapInfo.CountdownOffset = Parsing.ParseInt(pair.Value);
beatmap.CountdownOffset = Parsing.ParseInt(pair.Value);
break;
}
}
@ -313,7 +313,7 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"DistanceSpacing":
beatmap.BeatmapInfo.DistanceSpacing = Math.Max(0, Parsing.ParseDouble(pair.Value));
beatmap.DistanceSpacing = Math.Max(0, Parsing.ParseDouble(pair.Value));
break;
case @"BeatDivisor":
@ -321,11 +321,11 @@ namespace osu.Game.Beatmaps.Formats
break;
case @"GridSize":
beatmap.BeatmapInfo.GridSize = Parsing.ParseInt(pair.Value);
beatmap.GridSize = Parsing.ParseInt(pair.Value);
break;
case @"TimelineZoom":
beatmap.BeatmapInfo.TimelineZoom = Math.Max(0, Parsing.ParseDouble(pair.Value));
beatmap.TimelineZoom = Math.Max(0, Parsing.ParseDouble(pair.Value));
break;
}
}

View File

@ -79,14 +79,14 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine("[General]");
if (!string.IsNullOrEmpty(beatmap.Metadata.AudioFile)) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}"));
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}"));
writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.AudioLeadIn}"));
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}"));
writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.Countdown}"));
writer.WriteLine(FormattableString.Invariant(
$"SampleSet: {toLegacySampleBank(((beatmap.ControlPointInfo as LegacyControlPointInfo)?.SamplePoints.FirstOrDefault() ?? SampleControlPoint.DEFAULT).SampleBank)}"));
writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}"));
writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.StackLeniency}"));
writer.WriteLine(FormattableString.Invariant($"Mode: {onlineRulesetID}"));
writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.BeatmapInfo.LetterboxInBreaks ? '1' : '0')}"));
writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.LetterboxInBreaks ? '1' : '0')}"));
// if (beatmap.BeatmapInfo.UseSkinSprites)
// writer.WriteLine(@"UseSkinSprites: 1");
// if (b.AlwaysShowPlayfield)
@ -95,14 +95,14 @@ namespace osu.Game.Beatmaps.Formats
// writer.WriteLine(@"OverlayPosition: " + b.OverlayPosition);
// if (!string.IsNullOrEmpty(b.SkinPreference))
// writer.WriteLine(@"SkinPreference:" + b.SkinPreference);
if (beatmap.BeatmapInfo.EpilepsyWarning)
if (beatmap.EpilepsyWarning)
writer.WriteLine(@"EpilepsyWarning: 1");
if (beatmap.BeatmapInfo.CountdownOffset > 0)
writer.WriteLine(FormattableString.Invariant($@"CountdownOffset: {beatmap.BeatmapInfo.CountdownOffset}"));
if (beatmap.CountdownOffset > 0)
writer.WriteLine(FormattableString.Invariant($@"CountdownOffset: {beatmap.CountdownOffset}"));
if (onlineRulesetID == 3)
writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.BeatmapInfo.SpecialStyle ? '1' : '0')}"));
writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.BeatmapInfo.WidescreenStoryboard ? '1' : '0')}"));
if (beatmap.BeatmapInfo.SamplesMatchPlaybackRate)
writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.SpecialStyle ? '1' : '0')}"));
writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.WidescreenStoryboard ? '1' : '0')}"));
if (beatmap.SamplesMatchPlaybackRate)
writer.WriteLine(@"SamplesMatchPlaybackRate: 1");
}
@ -112,10 +112,10 @@ namespace osu.Game.Beatmaps.Formats
if (beatmap.BeatmapInfo.Bookmarks.Length > 0)
writer.WriteLine(FormattableString.Invariant($"Bookmarks: {string.Join(',', beatmap.BeatmapInfo.Bookmarks)}"));
writer.WriteLine(FormattableString.Invariant($"DistanceSpacing: {beatmap.BeatmapInfo.DistanceSpacing}"));
writer.WriteLine(FormattableString.Invariant($"DistanceSpacing: {beatmap.DistanceSpacing}"));
writer.WriteLine(FormattableString.Invariant($"BeatDivisor: {beatmap.BeatmapInfo.BeatDivisor}"));
writer.WriteLine(FormattableString.Invariant($"GridSize: {beatmap.BeatmapInfo.GridSize}"));
writer.WriteLine(FormattableString.Invariant($"TimelineZoom: {beatmap.BeatmapInfo.TimelineZoom}"));
writer.WriteLine(FormattableString.Invariant($"GridSize: {beatmap.GridSize}"));
writer.WriteLine(FormattableString.Invariant($"TimelineZoom: {beatmap.TimelineZoom}"));
}
private void handleMetadata(TextWriter writer)

View File

@ -38,6 +38,17 @@ namespace osu.Game.Beatmaps.Formats
SetFallbackDecoder<Storyboard>(() => new LegacyStoryboardDecoder());
}
protected override Storyboard CreateTemplateObject()
{
var sb = base.CreateTemplateObject();
var beatmap = new Beatmap();
LegacyBeatmapDecoder.ApplyLegacyDefaults(beatmap);
sb.Beatmap = beatmap;
return sb;
}
protected override void ParseStreamInto(LineBufferedReader stream, Storyboard storyboard)
{
this.storyboard = storyboard;
@ -73,6 +84,10 @@ namespace osu.Game.Beatmaps.Formats
case "UseSkinSprites":
storyboard.UseSkinSprites = pair.Value == "1";
break;
case @"WidescreenStoryboard":
storyboard.Beatmap.WidescreenStoryboard = Parsing.ParseInt(pair.Value) == 1;
break;
}
}

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Framework.Lists;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
@ -69,6 +70,43 @@ namespace osu.Game.Beatmaps
/// </summary>
double GetMostCommonBeatLength();
double AudioLeadIn { get; internal set; }
float StackLeniency { get; internal set; }
bool SpecialStyle { get; internal set; }
bool LetterboxInBreaks { get; internal set; }
bool WidescreenStoryboard { get; internal set; }
bool EpilepsyWarning { get; internal set; }
bool SamplesMatchPlaybackRate { get; internal set; }
/// <summary>
/// The ratio of distance travelled per time unit.
/// Generally used to decouple the spacing between hit objects from the enforced "velocity" of the beatmap (see <see cref="DifficultyControlPoint.SliderVelocity"/>).
/// </summary>
/// <remarks>
/// The most common method of understanding is that at a default value of 1.0, the time-to-distance ratio will match the slider velocity of the beatmap
/// at the current point in time. Increasing this value will make hit objects more spaced apart when compared to the cursor movement required to track a slider.
///
/// This is only a hint property, used by the editor in <see cref="IDistanceSnapProvider"/> implementations. It does not directly affect the beatmap or gameplay.
/// </remarks>
double DistanceSpacing { get; internal set; }
int GridSize { get; internal set; }
double TimelineZoom { get; internal set; }
CountdownType Countdown { get; internal set; }
/// <summary>
/// The number of beats to move the countdown backwards (compared to its default location).
/// </summary>
int CountdownOffset { get; internal set; }
/// <summary>
/// Creates a shallow-clone of this beatmap and returns it.
/// </summary>

View File

@ -62,7 +62,12 @@ namespace osu.Game.Beatmaps
#region Resource getters
protected virtual Waveform GetWaveform() => new Waveform(null);
protected virtual Storyboard GetStoryboard() => new Storyboard { BeatmapInfo = BeatmapInfo };
protected virtual Storyboard GetStoryboard() => new Storyboard
{
BeatmapInfo = BeatmapInfo,
Beatmap = Beatmap,
};
protected abstract IBeatmap GetBeatmap();
public abstract Texture GetBackground();

View File

@ -94,8 +94,9 @@ namespace osu.Game.Database
/// 41 2024-04-17 Add ScoreInfo.TotalScoreWithoutMods for future mod multiplier rebalances.
/// 42 2024-08-07 Update mania key bindings to reflect changes to ManiaAction
/// 43 2024-10-14 Reset keybind for toggling FPS display to avoid conflict with "convert to stream" in the editor, if not already changed by user.
/// 44 2024-11-22 Removed several properties from BeatmapInfo which did not need to be persisted to realm.
/// </summary>
private const int schema_version = 43;
private const int schema_version = 44;
/// <summary>
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.

View File

@ -174,6 +174,11 @@ namespace osu.Game
/// </summary>
public readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>();
/// <summary>
/// Whether the back button is currently displayed.
/// </summary>
private readonly IBindable<bool> backButtonVisibility = new Bindable<bool>();
IBindable<LocalUserPlayingState> ILocalUserPlayInfo.PlayingState => playingState;
private readonly Bindable<LocalUserPlayingState> playingState = new Bindable<LocalUserPlayingState>();
@ -1019,7 +1024,7 @@ namespace osu.Game
if (!(ScreenStack.CurrentScreen is IOsuScreen currentScreen))
return;
if (!((Drawable)currentScreen).IsLoaded || (currentScreen.AllowBackButton && !currentScreen.OnBackButton()))
if (!((Drawable)currentScreen).IsLoaded || (currentScreen.AllowUserExit && !currentScreen.OnBackButton()))
ScreenStack.Exit();
}
},
@ -1189,6 +1194,14 @@ namespace osu.Game
if (mode.NewValue != OverlayActivation.All) CloseAllOverlays();
};
backButtonVisibility.ValueChanged += visible =>
{
if (visible.NewValue)
BackButton.Show();
else
BackButton.Hide();
};
// Importantly, this should be run after binding PostNotification to the import handlers so they can present the import after game startup.
handleStartupImport();
}
@ -1581,12 +1594,14 @@ namespace osu.Game
if (current is IOsuScreen currentOsuScreen)
{
backButtonVisibility.UnbindFrom(currentOsuScreen.BackButtonVisibility);
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
API.Activity.UnbindFrom(currentOsuScreen.Activity);
}
if (newScreen is IOsuScreen newOsuScreen)
{
backButtonVisibility.BindTo(newOsuScreen.BackButtonVisibility);
OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode);
API.Activity.BindTo(newOsuScreen.Activity);
@ -1597,11 +1612,6 @@ namespace osu.Game
else
Toolbar.Show();
if (newOsuScreen.AllowBackButton)
BackButton.Show();
else
BackButton.Hide();
if (newOsuScreen.ShowFooter)
{
BackButton.Hide();

View File

@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
[Resolved(canBeNull: true)]
private OsuGame game { get; set; }
public override bool AllowBackButton => false;
public override bool AllowUserExit => false;
public override bool AllowExternalScreenChange => false;

View File

@ -184,7 +184,7 @@ namespace osu.Game.Overlays
content.ResizeHeightTo(0, animate ? transition_duration : 0, Easing.OutQuint);
}
headerContent.FadeColour(Expanded.Value ? Color4.White : OsuColour.Gray(0.5f), 200, Easing.OutQuint);
headerContent.FadeColour(Expanded.Value ? Color4.White : OsuColour.Gray(0.7f), 200, Easing.OutQuint);
}
private void updateFadeState()

View File

@ -341,6 +341,78 @@ namespace osu.Game.Rulesets.Difficulty
public double GetMostCommonBeatLength() => baseBeatmap.GetMostCommonBeatLength();
public IBeatmap Clone() => new ProgressiveCalculationBeatmap(baseBeatmap.Clone());
public double AudioLeadIn
{
get => baseBeatmap.AudioLeadIn;
set => baseBeatmap.AudioLeadIn = value;
}
public float StackLeniency
{
get => baseBeatmap.StackLeniency;
set => baseBeatmap.StackLeniency = value;
}
public bool SpecialStyle
{
get => baseBeatmap.SpecialStyle;
set => baseBeatmap.SpecialStyle = value;
}
public bool LetterboxInBreaks
{
get => baseBeatmap.LetterboxInBreaks;
set => baseBeatmap.LetterboxInBreaks = value;
}
public bool WidescreenStoryboard
{
get => baseBeatmap.WidescreenStoryboard;
set => baseBeatmap.WidescreenStoryboard = value;
}
public bool EpilepsyWarning
{
get => baseBeatmap.EpilepsyWarning;
set => baseBeatmap.EpilepsyWarning = value;
}
public bool SamplesMatchPlaybackRate
{
get => baseBeatmap.SamplesMatchPlaybackRate;
set => baseBeatmap.SamplesMatchPlaybackRate = value;
}
public double DistanceSpacing
{
get => baseBeatmap.DistanceSpacing;
set => baseBeatmap.DistanceSpacing = value;
}
public int GridSize
{
get => baseBeatmap.GridSize;
set => baseBeatmap.GridSize = value;
}
public double TimelineZoom
{
get => baseBeatmap.TimelineZoom;
set => baseBeatmap.TimelineZoom = value;
}
public CountdownType Countdown
{
get => baseBeatmap.Countdown;
set => baseBeatmap.Countdown = value;
}
public int CountdownOffset
{
get => baseBeatmap.CountdownOffset;
set => baseBeatmap.CountdownOffset = value;
}
#endregion
}
}

View File

@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Edit
}
});
DistanceSpacingMultiplier.Value = editorBeatmap.BeatmapInfo.DistanceSpacing;
DistanceSpacingMultiplier.Value = editorBeatmap.DistanceSpacing;
DistanceSpacingMultiplier.BindValueChanged(multiplier =>
{
distanceSpacingSlider.ContractedLabelText = $"D. S. ({multiplier.NewValue:0.##x})";
@ -109,7 +109,7 @@ namespace osu.Game.Rulesets.Edit
if (multiplier.NewValue != multiplier.OldValue)
onScreenDisplay?.Display(new DistanceSpacingToast(multiplier.NewValue.ToLocalisableString(@"0.##x"), multiplier));
editorBeatmap.BeatmapInfo.DistanceSpacing = multiplier.NewValue;
editorBeatmap.DistanceSpacing = multiplier.NewValue;
}, true);
DistanceSpacingMultiplier.BindDisabledChanged(disabled => distanceSpacingSlider.Alpha = disabled ? 0 : 1, true);

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Edit
/// A multiplier which changes the ratio of distance travelled per time unit.
/// Importantly, this is provided for manual usage, and not multiplied into any of the methods exposed by this interface.
/// </summary>
/// <seealso cref="BeatmapInfo.DistanceSpacing"/>
/// <seealso cref="IBeatmap.DistanceSpacing"/>
Bindable<double> DistanceSpacingMultiplier { get; }
/// <summary>

View File

@ -433,7 +433,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// Finishes the current blueprint selection.
/// </summary>
/// <param name="e">The mouse event which triggered end of selection.</param>
/// <returns>Whether a click selection was active.</returns>
/// <returns>
/// Whether the mouse event is considered to be fully handled.
/// If the return value is <see langword="false"/>, the standard click / mouse up action will follow.
/// </returns>
private bool endClickSelection(MouseButtonEvent e)
{
// If already handled a selection, double-click, or drag, we don't want to perform a mouse up / click action.
@ -443,14 +446,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (e.ControlPressed)
{
// if a selection didn't occur, we may want to trigger a deselection.
// Iterate from the top of the input stack (blueprints closest to the front of the screen first).
// Priority is given to already-selected blueprints.
foreach (SelectionBlueprint<T> blueprint in SelectionBlueprints.AliveChildren.Where(b => b.IsHovered).OrderByDescending(b => b.IsSelected))
return clickSelectionHandled = SelectionHandler.MouseUpSelectionRequested(blueprint, e);
return false;
// can only be reached if there are no hovered blueprints.
// in that case, we still want to suppress mouse up / click handling, because when control is pressed,
// it is presumed we want to add to existing selection, not remove from it
// (unless explicitly control-clicking a selected object, which is handled above).
return true;
}
if (selectedBlueprintAlreadySelectedOnMouseDown && SelectedItems.Count == 1)

View File

@ -157,7 +157,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
Scheduler.AddOnce(applyVisualOffset, beatmap);
}, true);
Zoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom);
Zoom = (float)(defaultTimelineZoom * editorBeatmap.TimelineZoom);
}
private void applyVisualOffset(IBindable<WorkingBeatmap> beatmap)
@ -212,7 +212,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
float minimumZoom = getZoomLevelForVisibleMilliseconds(10000);
float maximumZoom = getZoomLevelForVisibleMilliseconds(500);
float initialZoom = (float)Math.Clamp(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom), minimumZoom, maximumZoom);
float initialZoom = (float)Math.Clamp(defaultTimelineZoom * (editorBeatmap.TimelineZoom == 0 ? 1 : editorBeatmap.TimelineZoom), minimumZoom, maximumZoom);
SetupZoom(initialZoom, minimumZoom, maximumZoom);
@ -234,7 +234,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
protected override void OnZoomChanged()
{
base.OnZoomChanged();
editorBeatmap.BeatmapInfo.TimelineZoom = Zoom / defaultTimelineZoom;
editorBeatmap.TimelineZoom = Zoom / defaultTimelineZoom;
}
protected override void UpdateAfterChildren()

View File

@ -80,8 +80,6 @@ namespace osu.Game.Screens.Edit
public override float BackgroundParallaxAmount => 0.1f;
public override bool AllowBackButton => false;
public override bool HideOverlaysOnEnter => true;
public override bool DisallowExternalBeatmapRulesetChanges => true;
@ -194,6 +192,8 @@ namespace osu.Game.Screens.Edit
}
}
protected override bool InitialBackButtonVisibility => false;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
=> dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
@ -760,11 +760,6 @@ namespace osu.Game.Screens.Edit
switch (e.Action)
{
case GlobalAction.Back:
// as we don't want to display the back button, manual handling of exit action is required.
this.Exit();
return true;
case GlobalAction.EditorCloneSelection:
Clone();
return true;

View File

@ -198,6 +198,78 @@ namespace osu.Game.Screens.Edit
public double GetMostCommonBeatLength() => PlayableBeatmap.GetMostCommonBeatLength();
public double AudioLeadIn
{
get => PlayableBeatmap.AudioLeadIn;
set => PlayableBeatmap.AudioLeadIn = value;
}
public float StackLeniency
{
get => PlayableBeatmap.StackLeniency;
set => PlayableBeatmap.StackLeniency = value;
}
public bool SpecialStyle
{
get => PlayableBeatmap.SpecialStyle;
set => PlayableBeatmap.SpecialStyle = value;
}
public bool LetterboxInBreaks
{
get => PlayableBeatmap.LetterboxInBreaks;
set => PlayableBeatmap.LetterboxInBreaks = value;
}
public bool WidescreenStoryboard
{
get => PlayableBeatmap.WidescreenStoryboard;
set => PlayableBeatmap.WidescreenStoryboard = value;
}
public bool EpilepsyWarning
{
get => PlayableBeatmap.EpilepsyWarning;
set => PlayableBeatmap.EpilepsyWarning = value;
}
public bool SamplesMatchPlaybackRate
{
get => PlayableBeatmap.SamplesMatchPlaybackRate;
set => PlayableBeatmap.SamplesMatchPlaybackRate = value;
}
public double DistanceSpacing
{
get => PlayableBeatmap.DistanceSpacing;
set => PlayableBeatmap.DistanceSpacing = value;
}
public int GridSize
{
get => PlayableBeatmap.GridSize;
set => PlayableBeatmap.GridSize = value;
}
public double TimelineZoom
{
get => PlayableBeatmap.TimelineZoom;
set => PlayableBeatmap.TimelineZoom = value;
}
public CountdownType Countdown
{
get => PlayableBeatmap.Countdown;
set => PlayableBeatmap.Countdown = value;
}
public int CountdownOffset
{
get => PlayableBeatmap.CountdownOffset;
set => PlayableBeatmap.CountdownOffset = value;
}
public IBeatmap Clone() => (EditorBeatmap)MemberwiseClone();
private IList mutableHitObjects => (IList)PlayableBeatmap.HitObjects;

View File

@ -36,7 +36,7 @@ namespace osu.Game.Screens.Edit
public override float BackgroundParallaxAmount => 0.1f;
public override bool AllowBackButton => false;
public override bool AllowUserExit => false;
public override bool HideOverlaysOnEnter => true;

View File

@ -39,7 +39,7 @@ namespace osu.Game.Screens.Edit.Setup
{
Caption = EditorSetupStrings.EnableCountdown,
HintText = EditorSetupStrings.CountdownDescription,
Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None },
Current = { Value = Beatmap.Countdown != CountdownType.None },
},
CountdownSettings = new FillFlowContainer
{
@ -52,14 +52,14 @@ namespace osu.Game.Screens.Edit.Setup
CountdownSpeed = new FormEnumDropdown<CountdownType>
{
Caption = EditorSetupStrings.CountdownSpeed,
Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal },
Current = { Value = Beatmap.Countdown != CountdownType.None ? Beatmap.Countdown : CountdownType.Normal },
Items = Enum.GetValues<CountdownType>().Where(type => type != CountdownType.None)
},
CountdownOffset = new FormNumberBox
{
Caption = EditorSetupStrings.CountdownOffset,
HintText = EditorSetupStrings.CountdownOffsetDescription,
Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() },
Current = { Value = Beatmap.CountdownOffset.ToString() },
TabbableContentContainer = this,
}
}
@ -68,25 +68,25 @@ namespace osu.Game.Screens.Edit.Setup
{
Caption = EditorSetupStrings.WidescreenSupport,
HintText = EditorSetupStrings.WidescreenSupportDescription,
Current = { Value = Beatmap.BeatmapInfo.WidescreenStoryboard }
Current = { Value = Beatmap.WidescreenStoryboard }
},
epilepsyWarning = new FormCheckBox
{
Caption = EditorSetupStrings.EpilepsyWarning,
HintText = EditorSetupStrings.EpilepsyWarningDescription,
Current = { Value = Beatmap.BeatmapInfo.EpilepsyWarning }
Current = { Value = Beatmap.EpilepsyWarning }
},
letterboxDuringBreaks = new FormCheckBox
{
Caption = EditorSetupStrings.LetterboxDuringBreaks,
HintText = EditorSetupStrings.LetterboxDuringBreaksDescription,
Current = { Value = Beatmap.BeatmapInfo.LetterboxInBreaks }
Current = { Value = Beatmap.LetterboxInBreaks }
},
samplesMatchPlaybackRate = new FormCheckBox
{
Caption = EditorSetupStrings.SamplesMatchPlaybackRate,
HintText = EditorSetupStrings.SamplesMatchPlaybackRateDescription,
Current = { Value = Beatmap.BeatmapInfo.SamplesMatchPlaybackRate }
Current = { Value = Beatmap.SamplesMatchPlaybackRate }
}
};
}
@ -113,18 +113,18 @@ namespace osu.Game.Screens.Edit.Setup
{
updateBeatmap();
// update displayed text to ensure parsed value matches display (i.e. if empty string was provided).
CountdownOffset.Current.Value = Beatmap.BeatmapInfo.CountdownOffset.ToString(CultureInfo.InvariantCulture);
CountdownOffset.Current.Value = Beatmap.CountdownOffset.ToString(CultureInfo.InvariantCulture);
}
private void updateBeatmap()
{
Beatmap.BeatmapInfo.Countdown = EnableCountdown.Current.Value ? CountdownSpeed.Current.Value : CountdownType.None;
Beatmap.BeatmapInfo.CountdownOffset = int.TryParse(CountdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0;
Beatmap.Countdown = EnableCountdown.Current.Value ? CountdownSpeed.Current.Value : CountdownType.None;
Beatmap.CountdownOffset = int.TryParse(CountdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0;
Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value;
Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value;
Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value;
Beatmap.BeatmapInfo.SamplesMatchPlaybackRate = samplesMatchPlaybackRate.Current.Value;
Beatmap.WidescreenStoryboard = widescreenSupport.Current.Value;
Beatmap.EpilepsyWarning = epilepsyWarning.Current.Value;
Beatmap.LetterboxInBreaks = letterboxDuringBreaks.Current.Value;
Beatmap.SamplesMatchPlaybackRate = samplesMatchPlaybackRate.Current.Value;
Beatmap.SaveState();
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Input.Bindings;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Screens.Footer;
@ -21,15 +22,21 @@ namespace osu.Game.Screens
bool DisallowExternalBeatmapRulesetChanges { get; }
/// <summary>
/// Whether the user can exit this <see cref="IOsuScreen"/> by pressing the back button.
/// Whether the user can exit this <see cref="IOsuScreen"/>.
/// </summary>
bool AllowBackButton { get; }
/// <remarks>
/// When overriden to <c>false</c>,
/// the user is blocked from exiting the screen via the <see cref="GlobalAction.Back"/> action,
/// and the back button is hidden from this screen by the initial state of <see cref="BackButtonVisibility"/> being set to hidden.
/// </remarks>
bool AllowUserExit { get; }
/// <summary>
/// Whether a footer (and a back button) should be displayed underneath the screen.
/// </summary>
/// <remarks>
/// Temporarily, the back button is shown regardless of whether <see cref="AllowBackButton"/> is true.
/// Temporarily, the footer's own back button is shown regardless of whether <see cref="BackButtonVisibility"/> is set to hidden.
/// This will be corrected as the footer becomes used more commonly.
/// </remarks>
bool ShowFooter { get; }
@ -59,6 +66,11 @@ namespace osu.Game.Screens
/// </summary>
IBindable<OverlayActivation> OverlayActivationMode { get; }
/// <summary>
/// Whether the back button should be displayed in this screen.
/// </summary>
IBindable<bool> BackButtonVisibility { get; }
/// <summary>
/// The current <see cref="UserActivity"/> for this screen.
/// </summary>

View File

@ -48,7 +48,7 @@ namespace osu.Game.Screens.Menu
public override bool HideOverlaysOnEnter => Buttons == null || Buttons.State == ButtonSystemState.Initial;
public override bool AllowBackButton => false;
public override bool AllowUserExit => false;
public override bool AllowExternalScreenChange => true;

View File

@ -126,7 +126,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
syncManager = new SpectatorSyncManager(masterClockContainer)
{
ReadyToStart = performInitialSeek,
}
},
new PlayerSettingsOverlay()
};
for (int i = 0; i < Users.Count; i++)

View File

@ -180,7 +180,7 @@ namespace osu.Game.Screens.OnlinePlay
if (!(screenStack.CurrentScreen is IOnlinePlaySubScreen onlineSubScreen))
return false;
if (((Drawable)onlineSubScreen).IsLoaded && onlineSubScreen.AllowBackButton && onlineSubScreen.OnBackButton())
if (((Drawable)onlineSubScreen).IsLoaded && onlineSubScreen.AllowUserExit && onlineSubScreen.OnBackButton())
return true;
if (screenStack.CurrentScreen != null && !(screenStack.CurrentScreen is LoungeSubScreen))

View File

@ -37,7 +37,7 @@ namespace osu.Game.Screens
public string Description => Title;
public virtual bool AllowBackButton => true;
public virtual bool AllowUserExit => true;
public virtual bool ShowFooter => false;
@ -56,6 +56,15 @@ namespace osu.Game.Screens
IBindable<OverlayActivation> IOsuScreen.OverlayActivationMode => OverlayActivationMode;
/// <summary>
/// The initial visibility state of the back button when this screen is entered for the first time.
/// </summary>
protected virtual bool InitialBackButtonVisibility => AllowUserExit;
public readonly Bindable<bool> BackButtonVisibility;
IBindable<bool> IOsuScreen.BackButtonVisibility => BackButtonVisibility;
public virtual bool CursorVisible => true;
protected new OsuGameBase Game => base.Game as OsuGameBase;
@ -154,6 +163,7 @@ namespace osu.Game.Screens
Origin = Anchor.Centre;
OverlayActivationMode = new Bindable<OverlayActivation>(InitialOverlayActivationMode);
BackButtonVisibility = new Bindable<bool>(InitialBackButtonVisibility);
}
[BackgroundDependencyLoader(true)]

View File

@ -1,46 +1,102 @@
// 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.
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osuTK;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play.PlayerSettings;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Play.HUD
{
public partial class PlayerSettingsOverlay : VisibilityContainer
public partial class PlayerSettingsOverlay : ExpandingContainer
{
public VisualSettings VisualSettings { get; private set; }
private const float padding = 10;
public const float EXPANDED_WIDTH = player_settings_width + padding * 2;
private const float player_settings_width = 270;
private const int fade_duration = 200;
public readonly VisualSettings VisualSettings;
public override void Show() => this.FadeIn(fade_duration);
public override void Hide() => this.FadeOut(fade_duration);
// we'll handle this ourselves because we have slightly custom logic.
protected override bool ExpandOnHover => false;
protected override Container<Drawable> Content => content;
private readonly FillFlowContainer content;
public PlayerSettingsOverlay()
{
Anchor = Anchor.TopRight;
Origin = Anchor.TopRight;
AutoSizeAxes = Axes.Both;
private readonly IconButton button;
InternalChild = content = new FillFlowContainer
private InputManager inputManager = null!;
public PlayerSettingsOverlay()
: base(0, EXPANDED_WIDTH)
{
Origin = Anchor.TopRight;
Anchor = Anchor.TopRight;
base.Content.Add(content = new FillFlowContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding(padding),
Children = new PlayerSettingsGroup[]
{
VisualSettings = new VisualSettings { Expanded = { Value = false } },
new AudioSettings { Expanded = { Value = false } }
}
};
});
AddInternal(button = new IconButton
{
Icon = FontAwesome.Solid.Cog,
Origin = Anchor.TopRight,
Anchor = Anchor.TopLeft,
Margin = new MarginPadding(5),
Action = () => Expanded.Toggle()
});
AddInternal(new Box
{
Colour = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0), Color4.Black.Opacity(0.8f)),
Depth = float.MaxValue,
RelativeSizeAxes = Axes.Both,
});
}
protected override void PopIn() => this.FadeIn(fade_duration);
protected override void PopOut() => this.FadeOut(fade_duration);
protected override void LoadComplete()
{
base.LoadComplete();
inputManager = GetContainingInputManager()!;
}
protected override void Update()
{
base.Update();
Expanded.Value = inputManager.CurrentState.Mouse.Position.X >= button.ScreenSpaceDrawQuad.TopLeft.X;
}
protected override void OnHoverLost(HoverLostEvent e)
{
// handle un-expanding manually because our children do weird hover blocking stuff.
}
public void AddAtStart(PlayerSettingsGroup drawable) => content.Insert(-1, drawable);
}

View File

@ -115,6 +115,8 @@ namespace osu.Game.Screens.Play
public HUDOverlay([CanBeNull] DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods, bool alwaysShowLeaderboard = true)
{
Container rightSettings;
this.drawableRuleset = drawableRuleset;
this.mods = mods;
@ -146,7 +148,6 @@ namespace osu.Game.Screens.Play
Children = new Drawable[]
{
ModDisplay = CreateModsContainer(),
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
}
},
bottomRightElements = new FillFlowContainer
@ -164,6 +165,14 @@ namespace osu.Game.Screens.Play
HoldToQuit = CreateHoldForMenuButton(),
}
},
rightSettings = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
PlayerSettingsOverlay = new PlayerSettingsOverlay(),
}
},
LeaderboardFlow = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
@ -173,7 +182,7 @@ namespace osu.Game.Screens.Play
},
};
hideTargets = new List<Drawable> { mainComponents, topRightElements };
hideTargets = new List<Drawable> { mainComponents, topRightElements, rightSettings };
if (rulesetComponents != null)
hideTargets.Add(rulesetComponents);
@ -389,8 +398,6 @@ namespace osu.Game.Screens.Play
Origin = Anchor.TopRight,
};
protected PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{
if (e.Repeat)

View File

@ -95,8 +95,8 @@ namespace osu.Game.Screens.Play
// some beatmaps specify a current lead-in time which should be used instead of the ruleset-provided value when available.
// this is not available as an option in the live editor but can still be applied via .osu editing.
double firstHitObjectTime = beatmap.Beatmap.HitObjects.First().StartTime;
if (beatmap.BeatmapInfo.AudioLeadIn > 0)
time = Math.Min(time, firstHitObjectTime - beatmap.BeatmapInfo.AudioLeadIn);
if (beatmap.Beatmap.AudioLeadIn > 0)
time = Math.Min(time, firstHitObjectTime - beatmap.Beatmap.AudioLeadIn);
return time;
}

View File

@ -57,7 +57,7 @@ namespace osu.Game.Screens.Play
/// </summary>
public event Action OnGameplayStarted;
public override bool AllowBackButton => false; // handled by HoldForMenuButton
public override bool AllowUserExit => false; // handled by HoldForMenuButton
protected override bool PlayExitSound => !isRestarting;
@ -457,7 +457,7 @@ namespace osu.Game.Screens.Play
Anchor = Anchor.Centre,
Origin = Anchor.Centre
},
BreakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
BreakOverlay = new BreakOverlay(working.Beatmap.LetterboxInBreaks, ScoreProcessor)
{
Clock = DrawableRuleset.FrameStableClock,
ProcessCustomClock = false,

View File

@ -242,7 +242,7 @@ namespace osu.Game.Screens.Play
sampleRestart = new SkinnableSound(new SampleInfo(@"Gameplay/restart", @"pause-retry-click"))
};
if (Beatmap.Value.BeatmapInfo.EpilepsyWarning)
if (Beatmap.Value.Beatmap.EpilepsyWarning)
{
disclaimers.Add(epilepsyWarning = new PlayerLoaderDisclaimer(PlayerLoaderStrings.EpilepsyWarningTitle, PlayerLoaderStrings.EpilepsyWarningContent));
}
@ -485,6 +485,8 @@ namespace osu.Game.Screens.Play
if (quickRestart)
{
BackButtonVisibility.Value = false;
// A quick restart starts by triggering a fade to black
AddInternal(quickRestartBlackLayer = new Box
{
@ -503,6 +505,8 @@ namespace osu.Game.Screens.Play
.Delay(quick_restart_initial_delay)
.ScaleTo(1)
.FadeInFromZero(500, Easing.OutQuint);
this.Delay(quick_restart_initial_delay).Schedule(() => BackButtonVisibility.Value = true);
}
else
{

View File

@ -10,7 +10,7 @@ namespace osu.Game.Screens
/// </summary>
public abstract partial class StartupScreen : OsuScreen
{
public override bool AllowBackButton => false;
public override bool AllowUserExit => false;
public override bool HideOverlaysOnEnter => true;

View File

@ -67,7 +67,7 @@ namespace osu.Game.Storyboards.Drawables
bool onlyHasVideoElements = Storyboard.Layers.SelectMany(l => l.Elements).All(e => e is StoryboardVideo);
Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f);
Width = Height * (storyboard.Beatmap.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;

View File

@ -17,6 +17,7 @@ namespace osu.Game.Storyboards
public IEnumerable<StoryboardLayer> Layers => layers.Values;
public BeatmapInfo BeatmapInfo = new BeatmapInfo();
public IBeatmap Beatmap { get; set; } = new Beatmap();
/// <summary>
/// Whether the storyboard should prefer textures from the current skin before using local storyboard textures.

View File

@ -27,6 +27,17 @@ namespace osu.Game.Tests.Beatmaps
BeatmapInfo = baseBeatmap.BeatmapInfo;
ControlPointInfo = baseBeatmap.ControlPointInfo;
UnhandledEventLines = baseBeatmap.UnhandledEventLines;
AudioLeadIn = baseBeatmap.AudioLeadIn;
StackLeniency = baseBeatmap.StackLeniency;
SpecialStyle = baseBeatmap.SpecialStyle;
LetterboxInBreaks = baseBeatmap.LetterboxInBreaks;
WidescreenStoryboard = baseBeatmap.WidescreenStoryboard;
EpilepsyWarning = baseBeatmap.EpilepsyWarning;
SamplesMatchPlaybackRate = baseBeatmap.SamplesMatchPlaybackRate;
DistanceSpacing = baseBeatmap.DistanceSpacing;
GridSize = baseBeatmap.GridSize;
TimelineZoom = baseBeatmap.TimelineZoom;
CountdownOffset = baseBeatmap.CountdownOffset;
if (withHitObjects)
{