Skip to content

Commit

Permalink
Merge branch 'master' into silly-thing
Browse files Browse the repository at this point in the history
  • Loading branch information
frenzibyte authored Dec 10, 2024
2 parents d69f5fd + 48bf2fa commit e6e79cb
Show file tree
Hide file tree
Showing 17 changed files with 242 additions and 19 deletions.
4 changes: 2 additions & 2 deletions osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ public void TestDecodeBeatmapEditor()
95901, 106450, 116999, 119637, 130186, 140735, 151285,
161834, 164471, 175020, 185570, 196119, 206669, 209306
};
Assert.AreEqual(expectedBookmarks.Length, beatmap.BeatmapInfo.Bookmarks.Length);
Assert.AreEqual(expectedBookmarks.Length, beatmap.Bookmarks.Length);
for (int i = 0; i < expectedBookmarks.Length; i++)
Assert.AreEqual(expectedBookmarks[i], beatmap.BeatmapInfo.Bookmarks[i]);
Assert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]);
Assert.AreEqual(1.8, beatmap.DistanceSpacing);
Assert.AreEqual(4, beatmap.BeatmapInfo.BeatDivisor);
Assert.AreEqual(4, beatmap.GridSize);
Expand Down
4 changes: 2 additions & 2 deletions osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ public void TestDecodeEditor()
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.Bookmarks.Length);
for (int i = 0; i < expectedBookmarks.Length; i++)
Assert.AreEqual(expectedBookmarks[i], beatmapInfo.Bookmarks[i]);
Assert.AreEqual(expectedBookmarks[i], beatmap.Bookmarks[i]);
Assert.AreEqual(1.8, beatmap.DistanceSpacing);
Assert.AreEqual(4, beatmapInfo.BeatDivisor);
Assert.AreEqual(4, beatmap.GridSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public TestSceneEditorSummaryTimeline()
beatmap.ControlPointInfo.Add(50000, new DifficultyControlPoint { SliderVelocity = 2 });
beatmap.ControlPointInfo.Add(80000, new EffectControlPoint { KiaiMode = true });
beatmap.ControlPointInfo.Add(110000, new EffectControlPoint { KiaiMode = false });
beatmap.BeatmapInfo.Bookmarks = new[] { 75000, 125000 };
beatmap.Bookmarks = new[] { 75000, 125000 };
beatmap.Breaks.Add(new ManualBreakPeriod(90000, 120000));

editorBeatmap = new EditorBeatmap(beatmap);
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Beatmaps/Beatmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ public double GetMostCommonBeatLength()

public int CountdownOffset { get; set; }

public int[] Bookmarks { get; set; } = Array.Empty<int>();

IBeatmap IBeatmap.Clone() => Clone();

public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
Expand Down
1 change: 1 addition & 0 deletions osu.Game/Beatmaps/BeatmapConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ protected virtual Beatmap<T> ConvertBeatmap(IBeatmap original, CancellationToken
beatmap.TimelineZoom = original.TimelineZoom;
beatmap.Countdown = original.Countdown;
beatmap.CountdownOffset = original.CountdownOffset;
beatmap.Bookmarks = original.Bookmarks;

return beatmap;
}
Expand Down
3 changes: 0 additions & 3 deletions osu.Game/Beatmaps/BeatmapInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@ public void UpdateLocalScores(Realm realm)
[Obsolete("Use ScoreManager.GetMaximumAchievableComboAsync instead.")]
public int? MaxCombo { get; set; }

[Ignored]
public int[] Bookmarks { get; set; } = Array.Empty<int>();

public int BeatmapVersion;

public BeatmapInfo Clone() => (BeatmapInfo)this.Detach().MemberwiseClone();
Expand Down
2 changes: 1 addition & 1 deletion osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ private void handleEditor(string line)
switch (pair.Key)
{
case @"Bookmarks":
beatmap.BeatmapInfo.Bookmarks = pair.Value.Split(',').Select(v =>
beatmap.Bookmarks = pair.Value.Split(',').Select(v =>
{
bool result = int.TryParse(v, out int val);
return new { result, val };
Expand Down
4 changes: 2 additions & 2 deletions osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ private void handleEditor(TextWriter writer)
{
writer.WriteLine("[Editor]");

if (beatmap.BeatmapInfo.Bookmarks.Length > 0)
writer.WriteLine(FormattableString.Invariant($"Bookmarks: {string.Join(',', beatmap.BeatmapInfo.Bookmarks)}"));
if (beatmap.Bookmarks.Length > 0)
writer.WriteLine(FormattableString.Invariant($"Bookmarks: {string.Join(',', beatmap.Bookmarks)}"));
writer.WriteLine(FormattableString.Invariant($"DistanceSpacing: {beatmap.DistanceSpacing}"));
writer.WriteLine(FormattableString.Invariant($"BeatDivisor: {beatmap.BeatmapInfo.BeatDivisor}"));
writer.WriteLine(FormattableString.Invariant($"GridSize: {beatmap.GridSize}"));
Expand Down
2 changes: 2 additions & 0 deletions osu.Game/Beatmaps/IBeatmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public interface IBeatmap
/// </summary>
int CountdownOffset { get; internal set; }

int[] Bookmarks { get; internal set; }

/// <summary>
/// Creates a shallow-clone of this beatmap and returns it.
/// </summary>
Expand Down
16 changes: 16 additions & 0 deletions osu.Game/Input/Bindings/GlobalActionContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ public static IEnumerable<GlobalAction> GetGlobalActionsFor(GlobalActionCategory
new KeyBinding(new[] { InputKey.Control, InputKey.Right }, GlobalAction.EditorSeekToNextHitObject),
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Left }, GlobalAction.EditorSeekToPreviousSamplePoint),
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Right }, GlobalAction.EditorSeekToNextSamplePoint),
new KeyBinding(new[] { InputKey.Control, InputKey.B }, GlobalAction.EditorAddBookmark),
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.B }, GlobalAction.EditorRemoveClosestBookmark),
new KeyBinding(new[] { InputKey.Alt, InputKey.Left }, GlobalAction.EditorSeekToPreviousBookmark),
new KeyBinding(new[] { InputKey.Alt, InputKey.Right }, GlobalAction.EditorSeekToNextBookmark),
};

private static IEnumerable<KeyBinding> editorTestPlayKeyBindings => new[]
Expand Down Expand Up @@ -476,6 +480,18 @@ public enum GlobalAction

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCycleGridType))]
EditorCycleGridType,

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorAddBookmark))]
EditorAddBookmark,

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorRemoveClosestBookmark))]
EditorRemoveClosestBookmark,

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSeekToPreviousBookmark))]
EditorSeekToPreviousBookmark,

[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSeekToNextBookmark))]
EditorSeekToNextBookmark,
}

public enum GlobalActionCategory
Expand Down
32 changes: 31 additions & 1 deletion osu.Game/Localisation/EditorStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,36 @@ public static class EditorStrings
/// </summary>
public static LocalisableString TimelineShowTicks => new TranslatableString(getKey(@"timeline_show_ticks"), @"Show ticks");

/// <summary>
/// "Bookmarks"
/// </summary>
public static LocalisableString Bookmarks => new TranslatableString(getKey(@"bookmarks"), @"Bookmarks");

/// <summary>
/// "Add bookmark"
/// </summary>
public static LocalisableString AddBookmark => new TranslatableString(getKey(@"add_bookmark"), @"Add bookmark");

/// <summary>
/// "Remove closest bookmark"
/// </summary>
public static LocalisableString RemoveClosestBookmark => new TranslatableString(getKey(@"remove_closest_bookmark"), @"Remove closest bookmark");

/// <summary>
/// "Seek to previous bookmark"
/// </summary>
public static LocalisableString SeekToPreviousBookmark => new TranslatableString(getKey(@"seek_to_previous_bookmark"), @"Seek to previous bookmark");

/// <summary>
/// "Seek to next bookmark"
/// </summary>
public static LocalisableString SeekToNextBookmark => new TranslatableString(getKey(@"seek_to_next_bookmark"), @"Seek to next bookmark");

/// <summary>
/// "Reset bookmarks"
/// </summary>
public static LocalisableString ResetBookmarks => new TranslatableString(getKey(@"reset_bookmarks"), @"Reset bookmarks");

private static string getKey(string key) => $@"{prefix}:{key}";
}
}
}
20 changes: 20 additions & 0 deletions osu.Game/Localisation/GlobalActionKeyBindingStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,26 @@ public static class GlobalActionKeyBindingStrings
/// </summary>
public static LocalisableString EditorSeekToNextSamplePoint => new TranslatableString(getKey(@"editor_seek_to_next_sample_point"), @"Seek to next sample point");

/// <summary>
/// "Add bookmark"
/// </summary>
public static LocalisableString EditorAddBookmark => new TranslatableString(getKey(@"editor_add_bookmark"), @"Add bookmark");

/// <summary>
/// "Remove closest bookmark"
/// </summary>
public static LocalisableString EditorRemoveClosestBookmark => new TranslatableString(getKey(@"editor_remove_closest_bookmark"), @"Remove closest bookmark");

/// <summary>
/// "Seek to previous bookmark"
/// </summary>
public static LocalisableString EditorSeekToPreviousBookmark => new TranslatableString(getKey(@"editor_seek_to_previous_bookmark"), @"Seek to previous bookmark");

/// <summary>
/// "Seek to next bookmark"
/// </summary>
public static LocalisableString EditorSeekToNextBookmark => new TranslatableString(getKey(@"editor_seek_to_next_bookmark"), @"Seek to next bookmark");

private static string getKey(string key) => $@"{prefix}:{key}";
}
}
6 changes: 6 additions & 0 deletions osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ public int CountdownOffset
set => baseBeatmap.CountdownOffset = value;
}

public int[] Bookmarks
{
get => baseBeatmap.Bookmarks;
set => baseBeatmap.Bookmarks = value;
}

#endregion
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Extensions;
using osu.Game.Graphics;
Expand All @@ -15,24 +19,69 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
/// </summary>
public partial class BookmarkPart : TimelinePart
{
private readonly BindableList<int> bookmarks = new BindableList<int>();

private DrawablePool<BookmarkVisualisation> pool = null!;

[BackgroundDependencyLoader]
private void load()
{
AddInternal(pool = new DrawablePool<BookmarkVisualisation>(10));
}

protected override void LoadBeatmap(EditorBeatmap beatmap)
{
base.LoadBeatmap(beatmap);
foreach (int bookmark in beatmap.BeatmapInfo.Bookmarks)
Add(new BookmarkVisualisation(bookmark));

bookmarks.UnbindAll();
bookmarks.BindTo(beatmap.Bookmarks);
}

private partial class BookmarkVisualisation : PointVisualisation, IHasTooltip
protected override void LoadComplete()
{
public BookmarkVisualisation(double startTime)
: base(startTime)
base.LoadComplete();
bookmarks.BindCollectionChanged((_, _) =>
{
Clear(disposeChildren: false);
foreach (int bookmark in bookmarks)
Add(pool.Get(v => v.StartTime = bookmark));
}, true);
}

private partial class BookmarkVisualisation : PoolableDrawable, IHasTooltip
{
private int startTime;

public int StartTime
{
get => startTime;
set
{
if (startTime == value)
return;

startTime = value;
X = startTime;
}
}

[BackgroundDependencyLoader]
private void load(OsuColour colours) => Colour = colours.Blue;
private void load(OsuColour colours)
{
RelativePositionAxes = Axes.Both;
RelativeSizeAxes = Axes.Y;

Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;

Width = PointVisualisation.MAX_WIDTH;
Height = 0.4f;

Colour = colours.Blue;
InternalChild = new FastCircle { RelativeSizeAxes = Axes.Both };
}

public LocalisableString TooltipText => $"{StartTime.ToEditorFormattedString()} bookmark";
public LocalisableString TooltipText => $"{((double)StartTime).ToEditorFormattedString()} bookmark";
}
}
}
62 changes: 62 additions & 0 deletions osu.Game/Screens/Edit/Editor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,29 @@ private void load(OsuConfigManager config)
Items = new MenuItem[]
{
new EditorMenuItem(EditorStrings.SetPreviewPointToCurrent, MenuItemType.Standard, SetPreviewPointToCurrentTime),
new EditorMenuItem(EditorStrings.Bookmarks)
{
Items = new MenuItem[]
{
new EditorMenuItem(EditorStrings.AddBookmark, MenuItemType.Standard, addBookmarkAtCurrentTime)
{
Hotkey = new Hotkey(GlobalAction.EditorAddBookmark),
},
new EditorMenuItem(EditorStrings.RemoveClosestBookmark, MenuItemType.Destructive, removeBookmarksInProximityToCurrentTime)
{
Hotkey = new Hotkey(GlobalAction.EditorRemoveClosestBookmark)
},
new EditorMenuItem(EditorStrings.SeekToPreviousBookmark, MenuItemType.Standard, () => seekBookmark(-1))
{
Hotkey = new Hotkey(GlobalAction.EditorSeekToPreviousBookmark)
},
new EditorMenuItem(EditorStrings.SeekToNextBookmark, MenuItemType.Standard, () => seekBookmark(1))
{
Hotkey = new Hotkey(GlobalAction.EditorSeekToNextBookmark)
},
new EditorMenuItem(EditorStrings.ResetBookmarks, MenuItemType.Destructive, () => editorBeatmap.Bookmarks.Clear())
}
}
}
}
}
Expand Down Expand Up @@ -753,13 +776,29 @@ public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
case GlobalAction.EditorSeekToNextSamplePoint:
seekSamplePoint(1);
return true;

case GlobalAction.EditorSeekToPreviousBookmark:
seekBookmark(-1);
return true;

case GlobalAction.EditorSeekToNextBookmark:
seekBookmark(1);
return true;
}

if (e.Repeat)
return false;

switch (e.Action)
{
case GlobalAction.EditorAddBookmark:
addBookmarkAtCurrentTime();
return true;

case GlobalAction.EditorRemoveClosestBookmark:
removeBookmarksInProximityToCurrentTime();
return true;

case GlobalAction.EditorCloneSelection:
Clone();
return true;
Expand Down Expand Up @@ -792,6 +831,19 @@ public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
return false;
}

private void addBookmarkAtCurrentTime()
{
int bookmark = (int)clock.CurrentTimeAccurate;
int idx = editorBeatmap.Bookmarks.BinarySearch(bookmark);
if (idx < 0)
editorBeatmap.Bookmarks.Insert(~idx, bookmark);
}

private void removeBookmarksInProximityToCurrentTime()
{
editorBeatmap.Bookmarks.RemoveAll(b => Math.Abs(b - clock.CurrentTimeAccurate) < 2000);
}

public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}
Expand Down Expand Up @@ -1127,6 +1179,16 @@ private void seekHitObject(int direction)
clock.SeekSmoothlyTo(found.StartTime);
}

private void seekBookmark(int direction)
{
int? targetBookmark = direction < 1
? editorBeatmap.Bookmarks.Cast<int?>().LastOrDefault(b => b < clock.CurrentTimeAccurate)
: editorBeatmap.Bookmarks.Cast<int?>().FirstOrDefault(b => b > clock.CurrentTimeAccurate);

if (targetBookmark != null)
clock.SeekSmoothlyTo(targetBookmark.Value);
}

private void seekSamplePoint(int direction)
{
double currentTime = clock.CurrentTimeAccurate;
Expand Down
Loading

0 comments on commit e6e79cb

Please sign in to comment.