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

Compare commits

...

50 Commits

Author SHA1 Message Date
Tim Schumacher
a9572f16a8
Merge e920cfa187 into ce4aac4184 2024-12-02 20:18:04 -08:00
Dean Herbert
ce4aac4184
Merge pull request #30917 from bdach/fix-incorrect-taiko-legacy-combo
Fix strong drum rolls being counted for double the combo in legacy scoring attributes
2024-12-02 20:08:49 -08: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
1d610a0f1b
Merge pull request #30928 from peppy/stop-logging-backwards-seek
Stop loudly logging backwards seek bug to sentry
2024-11-30 16:35:35 -05:00
Dean Herbert
1e2e364cd3
Stop loudly logging backwards seek bug to sentry
Several users have reported stutters when this happens. It's potentially
from the error report overhead. We now know that this is a BASS level
issue anyway, so having this logging is not helpful.
2024-11-30 21:01:22 +09:00
Bartłomiej Dach
3cfa455369
Fix strong drum rolls being counted for double the combo in legacy scoring attributes 2024-11-29 10:54:32 +01: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
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
58 changed files with 563 additions and 242 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

@ -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

@ -144,6 +144,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
foreach (var nested in hitObject.NestedHitObjects)
simulateHit(nested, ref attributes);
return;
case StrongNestedHitObject:
// we never need to deal with these directly.
// the only thing strong hits do in terms of scoring is double their object's score increase,
// which is already handled at the parent object level via the `strongable.IsStrong` check lower down in this method.
// not handling these here can lead to them falsely being counted as combo-increasing when handling strong drum rolls!
return;
}
if (hitObject is DrumRollTick tick)

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

@ -3,19 +3,15 @@
using System;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Input.Handlers;
using osu.Game.Screens.Play;
using osu.Game.Utils;
namespace osu.Game.Rulesets.UI
{
@ -168,13 +164,7 @@ namespace osu.Game.Rulesets.UI
if (lastBackwardsSeekLogTime == null || Math.Abs(Clock.CurrentTime - lastBackwardsSeekLogTime.Value) > 1000)
{
lastBackwardsSeekLogTime = Clock.CurrentTime;
string loggableContent = $"Denying backwards seek during gameplay (reference: {referenceClock.CurrentTime:N2} stable: {proposedTime:N2})";
if (parentGameplayClock is GameplayClockContainer gcc)
loggableContent += $"\n{gcc.ChildrenOfType<FramedBeatmapClock>().Single().GetSnapshot()}";
Logger.Error(new SentryOnlyDiagnosticsException("backwards seek"), loggableContent);
Logger.Log($"Denying backwards seek during gameplay (reference: {referenceClock.CurrentTime:N2} stable: {proposedTime:N2})");
}
state = PlaybackState.NotValid;

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)
{