mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 19:12:54 +08:00
Merge branch 'master' into musiccontroller-canbeatmapchange
This commit is contained in:
commit
209d024caa
@ -1 +1 @@
|
|||||||
Subproject commit 6b44a9f807fadcb3b3f044780d7e27d62ffe80ac
|
Subproject commit 2204764944ff693e857649253547054cc91764a0
|
@ -177,9 +177,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
beatsPerMinute.Value = 60000 / timingPoint.BeatLength;
|
beatsPerMinute.Value = 60000 / timingPoint.BeatLength;
|
||||||
adjustedBeatLength.Value = timingPoint.BeatLength;
|
adjustedBeatLength.Value = timingPoint.BeatLength;
|
||||||
|
|
||||||
flashLayer.ClearTransforms();
|
flashLayer.FadeOutFromOne(timingPoint.BeatLength);
|
||||||
flashLayer.FadeTo(1);
|
|
||||||
flashLayer.FadeTo(0, timingPoint.BeatLength);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
|
@ -59,20 +59,13 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
using (container.BeginLoopedSequence())
|
// Move box along a square trajectory
|
||||||
{
|
container.Loop(c => c
|
||||||
container.MoveTo(new Vector2(0, 100), duration);
|
.MoveTo(new Vector2(0, 100), duration).Then()
|
||||||
using (container.BeginDelayedSequence(duration))
|
.MoveTo(new Vector2(100, 100), duration).Then()
|
||||||
{
|
.MoveTo(new Vector2(100, 0), duration).Then()
|
||||||
container.MoveTo(new Vector2(100, 100), duration);
|
.MoveTo(Vector2.Zero, duration)
|
||||||
using (container.BeginDelayedSequence(duration))
|
);
|
||||||
{
|
|
||||||
container.MoveTo(new Vector2(100, 0), duration);
|
|
||||||
using (container.BeginDelayedSequence(duration))
|
|
||||||
container.MoveTo(Vector2.Zero, duration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyContextMenuContainer : Container, IHasContextMenu
|
private class MyContextMenuContainer : Container, IHasContextMenu
|
||||||
@ -95,10 +88,10 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
new OsuContextMenuItem(@"Simple option"),
|
new OsuContextMenuItem(@"Simple option"),
|
||||||
new OsuContextMenuItem(@"Simple very very long option"),
|
new OsuContextMenuItem(@"Simple very very long option"),
|
||||||
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => ResizeWidthTo(Width * 2, 100, EasingTypes.OutQuint) },
|
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint) },
|
||||||
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => ResizeHeightTo(Height * 2, 100, EasingTypes.OutQuint) },
|
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint) },
|
||||||
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => ResizeWidthTo(Width / 2, 100, EasingTypes.OutQuint) },
|
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint) },
|
||||||
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => ResizeHeightTo(Height / 2, 100, EasingTypes.OutQuint) },
|
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint) },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -14,7 +15,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
public override string Description => @"osu!direct overlay";
|
public override string Description => @"osu!direct overlay";
|
||||||
|
|
||||||
private DirectOverlay direct;
|
private DirectOverlay direct;
|
||||||
private RulesetDatabase rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
@ -28,7 +29,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetDatabase rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ using osu.Framework.Testing;
|
|||||||
using osu.Game.Screens.Multiplayer;
|
using osu.Game.Screens.Multiplayer;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -16,7 +17,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
public override string Description => @"Select your favourite room";
|
public override string Description => @"Select your favourite room";
|
||||||
|
|
||||||
private RulesetDatabase rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
@ -124,7 +125,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetDatabase rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.MathUtils;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -19,17 +18,18 @@ using System.Collections.Generic;
|
|||||||
using osu.Desktop.VisualTests.Beatmaps;
|
using osu.Desktop.VisualTests.Beatmaps;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
internal class TestCaseGamefield : TestCase
|
internal class TestCaseGamefield : TestCase
|
||||||
{
|
{
|
||||||
private RulesetDatabase rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
public override string Description => @"Showing hitobjects and what not.";
|
public override string Description => @"Showing hitobjects and what not.";
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetDatabase rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
SelectionBox.ScaleTo(
|
SelectionBox.ScaleTo(
|
||||||
new Vector2(value, 1),
|
new Vector2(value, 1),
|
||||||
300, EasingTypes.OutQuint);
|
300, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
ColourInfo = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
|
Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
|
||||||
RelativeSizeAxes = Framework.Graphics.Axes.Both,
|
RelativeSizeAxes = Framework.Graphics.Axes.Both,
|
||||||
});
|
});
|
||||||
Add(new ButtonSystem());
|
Add(new ButtonSystem());
|
||||||
|
@ -5,7 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
@ -18,11 +18,11 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
private ModSelectOverlay modSelect;
|
private ModSelectOverlay modSelect;
|
||||||
private ModDisplay modDisplay;
|
private ModDisplay modDisplay;
|
||||||
|
|
||||||
private RulesetDatabase rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetDatabase rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,17 @@ using osu.Framework.Graphics.Containers;
|
|||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
internal class TestCaseNotificationManager : TestCase
|
internal class TestCaseNotificationOverlay : TestCase
|
||||||
{
|
{
|
||||||
public override string Description => @"I handle notifications";
|
public override string Description => @"I handle notifications";
|
||||||
|
|
||||||
private readonly NotificationManager manager;
|
private readonly NotificationOverlay manager;
|
||||||
|
|
||||||
public TestCaseNotificationManager()
|
public TestCaseNotificationOverlay()
|
||||||
{
|
{
|
||||||
progressingNotifications.Clear();
|
progressingNotifications.Clear();
|
||||||
|
|
||||||
Content.Add(manager = new NotificationManager
|
Content.Add(manager = new NotificationOverlay
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
@ -56,10 +56,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (remaining > 0)
|
if (remaining > 0)
|
||||||
{
|
Scheduler.AddDelayed(() => sendBarrage(remaining - 1), 80);
|
||||||
Delay(80);
|
|
||||||
Schedule(() => sendBarrage(remaining - 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
@ -5,7 +5,9 @@ using System.Collections.Generic;
|
|||||||
using osu.Desktop.VisualTests.Platform;
|
using osu.Desktop.VisualTests.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Screens.Select.Filter;
|
using osu.Game.Screens.Select.Filter;
|
||||||
|
|
||||||
@ -13,31 +15,28 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
internal class TestCasePlaySongSelect : TestCase
|
internal class TestCasePlaySongSelect : TestCase
|
||||||
{
|
{
|
||||||
private readonly BeatmapDatabase db;
|
private readonly BeatmapManager manager;
|
||||||
|
|
||||||
public override string Description => @"with fake data";
|
public override string Description => @"with fake data";
|
||||||
|
|
||||||
private readonly RulesetDatabase rulesets;
|
private readonly RulesetStore rulesets;
|
||||||
|
|
||||||
public TestCasePlaySongSelect()
|
public TestCasePlaySongSelect()
|
||||||
{
|
{
|
||||||
PlaySongSelect songSelect;
|
PlaySongSelect songSelect;
|
||||||
|
|
||||||
if (db == null)
|
if (manager == null)
|
||||||
{
|
{
|
||||||
var storage = new TestStorage(@"TestCasePlaySongSelect");
|
var storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||||
|
|
||||||
var backingDatabase = storage.GetDatabase(@"client");
|
var backingDatabase = storage.GetDatabase(@"client");
|
||||||
|
backingDatabase.CreateTable<StoreVersion>();
|
||||||
|
|
||||||
rulesets = new RulesetDatabase(storage, backingDatabase);
|
rulesets = new RulesetStore(backingDatabase);
|
||||||
db = new BeatmapDatabase(storage, backingDatabase, rulesets);
|
manager = new BeatmapManager(storage, null, backingDatabase, rulesets);
|
||||||
|
|
||||||
var sets = new List<BeatmapSetInfo>();
|
|
||||||
|
|
||||||
for (int i = 0; i < 100; i += 10)
|
for (int i = 0; i < 100; i += 10)
|
||||||
sets.Add(createTestBeatmapSet(i));
|
manager.Import(createTestBeatmapSet(i));
|
||||||
|
|
||||||
db.Import(sets);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Add(songSelect = new PlaySongSelect());
|
Add(songSelect = new PlaySongSelect());
|
||||||
@ -48,21 +47,12 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
|
||||||
}
|
}
|
||||||
|
|
||||||
//protected override void Dispose(bool isDisposing)
|
|
||||||
//{
|
|
||||||
// if (oldDb != null)
|
|
||||||
// db = null;
|
|
||||||
|
|
||||||
// base.Dispose(isDisposing);
|
|
||||||
//}
|
|
||||||
|
|
||||||
private BeatmapSetInfo createTestBeatmapSet(int i)
|
private BeatmapSetInfo createTestBeatmapSet(int i)
|
||||||
{
|
{
|
||||||
return new BeatmapSetInfo
|
return new BeatmapSetInfo
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1234 + i,
|
OnlineBeatmapSetID = 1234 + i,
|
||||||
Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249",
|
Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249",
|
||||||
Path = string.Empty,
|
|
||||||
Metadata = new BeatmapMetadata
|
Metadata = new BeatmapMetadata
|
||||||
{
|
{
|
||||||
OnlineBeatmapSetID = 1234 + i,
|
OnlineBeatmapSetID = 1234 + i,
|
||||||
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
@ -14,18 +13,19 @@ using OpenTK.Graphics;
|
|||||||
using osu.Desktop.VisualTests.Beatmaps;
|
using osu.Desktop.VisualTests.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
internal class TestCasePlayer : TestCase
|
internal class TestCasePlayer : TestCase
|
||||||
{
|
{
|
||||||
protected Player Player;
|
protected Player Player;
|
||||||
private RulesetDatabase rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
public override string Description => @"Showing everything to play the game.";
|
public override string Description => @"Showing everything to play the game.";
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetDatabase rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,9 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -16,14 +14,14 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
internal class TestCaseResults : TestCase
|
internal class TestCaseResults : TestCase
|
||||||
{
|
{
|
||||||
private BeatmapDatabase db;
|
private BeatmapManager beatmaps;
|
||||||
|
|
||||||
public override string Description => @"Results after playing.";
|
public override string Description => @"Results after playing.";
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(BeatmapDatabase db)
|
private void load(BeatmapManager beatmaps)
|
||||||
{
|
{
|
||||||
this.db = db;
|
this.beatmaps = beatmaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorkingBeatmap beatmap;
|
private WorkingBeatmap beatmap;
|
||||||
@ -34,9 +32,9 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
|
|
||||||
if (beatmap == null)
|
if (beatmap == null)
|
||||||
{
|
{
|
||||||
var beatmapInfo = db.Query<BeatmapInfo>().FirstOrDefault(b => b.RulesetID == 0);
|
var beatmapInfo = beatmaps.QueryBeatmap(b => b.RulesetID == 0);
|
||||||
if (beatmapInfo != null)
|
if (beatmapInfo != null)
|
||||||
beatmap = db.GetWorkingBeatmap(beatmapInfo);
|
beatmap = beatmaps.GetWorkingBeatmap(beatmapInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
Add(new Results(new Score
|
Add(new Results(new Score
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Screens.Multiplayer;
|
using osu.Game.Screens.Multiplayer;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -15,7 +16,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
{
|
{
|
||||||
public override string Description => @"from the multiplayer lobby";
|
public override string Description => @"from the multiplayer lobby";
|
||||||
|
|
||||||
private RulesetDatabase rulesets;
|
private RulesetStore rulesets;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
@ -135,7 +136,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(RulesetDatabase rulesets)
|
private void load(RulesetStore rulesets)
|
||||||
{
|
{
|
||||||
this.rulesets = rulesets;
|
this.rulesets = rulesets;
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
FadeInFromZero(250, EasingTypes.OutQuint);
|
this.FadeInFromZero(250, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -67,6 +67,8 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
|
|
||||||
private void changePlayfieldSize(int step)
|
private void changePlayfieldSize(int step)
|
||||||
{
|
{
|
||||||
|
double delay = 0;
|
||||||
|
|
||||||
// Add new hits
|
// Add new hits
|
||||||
switch (step)
|
switch (step)
|
||||||
{
|
{
|
||||||
@ -84,7 +86,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
addSwell(1000);
|
addSwell(1000);
|
||||||
playfieldContainer.Delay(scroll_time - 100);
|
delay = scroll_time - 100;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,10 +94,10 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
switch (step)
|
switch (step)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
playfieldContainer.ResizeTo(new Vector2(1, rng.Next(25, 400)), 500);
|
playfieldContainer.Delay(delay).ResizeTo(new Vector2(1, rng.Next(25, 400)), 500);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
playfieldContainer.ResizeTo(new Vector2(1, TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT), 500);
|
playfieldContainer.Delay(delay).ResizeTo(new Vector2(1, TaikoPlayfield.DEFAULT_PLAYFIELD_HEIGHT), 500);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@
|
|||||||
<Compile Include="Tests\TestCaseManiaPlayfield.cs" />
|
<Compile Include="Tests\TestCaseManiaPlayfield.cs" />
|
||||||
<Compile Include="Tests\TestCaseMenuOverlays.cs" />
|
<Compile Include="Tests\TestCaseMenuOverlays.cs" />
|
||||||
<Compile Include="Tests\TestCaseMusicController.cs" />
|
<Compile Include="Tests\TestCaseMusicController.cs" />
|
||||||
<Compile Include="Tests\TestCaseNotificationManager.cs" />
|
<Compile Include="Tests\TestCaseNotificationOverlay.cs" />
|
||||||
<Compile Include="Tests\TestCaseOnScreenDisplay.cs" />
|
<Compile Include="Tests\TestCaseOnScreenDisplay.cs" />
|
||||||
<Compile Include="Tests\TestCaseReplaySettingsOverlay.cs" />
|
<Compile Include="Tests\TestCaseReplaySettingsOverlay.cs" />
|
||||||
<Compile Include="Tests\TestCasePlayer.cs" />
|
<Compile Include="Tests\TestCasePlayer.cs" />
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Beatmaps.IO;
|
|
||||||
|
|
||||||
namespace osu.Desktop.Beatmaps.IO
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Reads an extracted legacy beatmap from disk.
|
|
||||||
/// </summary>
|
|
||||||
public class LegacyFilesystemReader : ArchiveReader
|
|
||||||
{
|
|
||||||
public static void Register() => AddReader<LegacyFilesystemReader>((storage, path) => Directory.Exists(path));
|
|
||||||
|
|
||||||
private readonly string basePath;
|
|
||||||
|
|
||||||
public LegacyFilesystemReader(string path)
|
|
||||||
{
|
|
||||||
basePath = path;
|
|
||||||
|
|
||||||
BeatmapFilenames = Directory.GetFiles(basePath, @"*.osu").Select(Path.GetFileName).ToArray();
|
|
||||||
|
|
||||||
if (BeatmapFilenames.Length == 0)
|
|
||||||
throw new FileNotFoundException(@"This directory contains no beatmaps");
|
|
||||||
|
|
||||||
StoryboardFilename = Directory.GetFiles(basePath, @"*.osb").Select(Path.GetFileName).FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Stream GetStream(string name)
|
|
||||||
{
|
|
||||||
return File.OpenRead(Path.Combine(basePath, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Stream GetUnderlyingStream() => null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -65,11 +65,11 @@ namespace osu.Desktop
|
|||||||
var filePaths = dropData.Select(f => f.ToString()).ToArray();
|
var filePaths = dropData.Select(f => f.ToString()).ToArray();
|
||||||
|
|
||||||
if (filePaths.All(f => Path.GetExtension(f) == @".osz"))
|
if (filePaths.All(f => Path.GetExtension(f) == @".osz"))
|
||||||
Task.Run(() => BeatmapDatabase.Import(filePaths));
|
Task.Run(() => BeatmapManager.Import(filePaths));
|
||||||
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
|
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var score = ScoreDatabase.ReadReplayFile(filePaths.First());
|
var score = ScoreStore.ReadReplayFile(filePaths.First());
|
||||||
Schedule(() => LoadScore(score));
|
Schedule(() => LoadScore(score));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,16 @@ namespace osu.Desktop.Overlays
|
|||||||
public class VersionManager : OverlayContainer
|
public class VersionManager : OverlayContainer
|
||||||
{
|
{
|
||||||
private UpdateManager updateManager;
|
private UpdateManager updateManager;
|
||||||
private NotificationManager notificationManager;
|
private NotificationOverlay notificationOverlay;
|
||||||
|
|
||||||
protected override bool HideOnEscape => false;
|
protected override bool HideOnEscape => false;
|
||||||
|
|
||||||
public override bool HandleInput => false;
|
public override bool HandleInput => false;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(NotificationManager notification, OsuColour colours, TextureStore textures, OsuGameBase game)
|
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game)
|
||||||
{
|
{
|
||||||
notificationManager = notification;
|
notificationOverlay = notification;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
Anchor = Anchor.BottomCentre;
|
Anchor = Anchor.BottomCentre;
|
||||||
@ -116,7 +116,7 @@ namespace osu.Desktop.Overlays
|
|||||||
if (notification == null)
|
if (notification == null)
|
||||||
{
|
{
|
||||||
notification = new UpdateProgressNotification { State = ProgressNotificationState.Active };
|
notification = new UpdateProgressNotification { State = ProgressNotificationState.Active };
|
||||||
Schedule(() => notificationManager.Post(notification));
|
Schedule(() => notificationOverlay.Post(notification));
|
||||||
}
|
}
|
||||||
|
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
@ -175,7 +175,7 @@ namespace osu.Desktop.Overlays
|
|||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
FadeIn(1000);
|
this.FadeIn(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
@ -207,7 +207,7 @@ namespace osu.Desktop.Overlays
|
|||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColourInfo = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
|
Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
|
||||||
},
|
},
|
||||||
new TextAwesome
|
new TextAwesome
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Desktop.Beatmaps.IO;
|
|
||||||
using osu.Framework.Desktop;
|
using osu.Framework.Desktop;
|
||||||
using osu.Framework.Desktop.Platform;
|
using osu.Framework.Desktop.Platform;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
@ -15,8 +14,6 @@ namespace osu.Desktop
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
LegacyFilesystemReader.Register();
|
|
||||||
|
|
||||||
// Back up the cwd before DesktopGameHost changes it
|
// Back up the cwd before DesktopGameHost changes it
|
||||||
var cwd = Environment.CurrentDirectory;
|
var cwd = Environment.CurrentDirectory;
|
||||||
|
|
||||||
|
@ -228,7 +228,6 @@
|
|||||||
<Compile Include="OsuGameDesktop.cs" />
|
<Compile Include="OsuGameDesktop.cs" />
|
||||||
<Compile Include="Overlays\VersionManager.cs" />
|
<Compile Include="Overlays\VersionManager.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Beatmaps\IO\LegacyFilesystemReader.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -10,7 +10,6 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
|
using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
|
||||||
using osu.Game.Rulesets.Mania.MathUtils;
|
using osu.Game.Rulesets.Mania.MathUtils;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
|
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Mania.MathUtils;
|
using osu.Game.Rulesets.Mania.MathUtils;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Judgements
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
{
|
{
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
Name = "Key gradient",
|
Name = "Key gradient",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColourInfo = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)),
|
Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)),
|
||||||
Alpha = 0.5f
|
Alpha = 0.5f
|
||||||
},
|
},
|
||||||
keyIcon = new Container
|
keyIcon = new Container
|
||||||
@ -206,8 +206,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
if (args.Key == Key)
|
if (args.Key == Key)
|
||||||
{
|
{
|
||||||
background.FadeTo(background.Alpha + 0.2f, 50, EasingTypes.OutQuint);
|
background.FadeTo(background.Alpha + 0.2f, 50, Easing.OutQuint);
|
||||||
keyIcon.ScaleTo(1.4f, 50, EasingTypes.OutQuint);
|
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -217,8 +217,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
if (args.Key == Key)
|
if (args.Key == Key)
|
||||||
{
|
{
|
||||||
background.FadeTo(0.2f, 800, EasingTypes.OutQuart);
|
background.FadeTo(0.2f, 800, Easing.OutQuart);
|
||||||
keyIcon.ScaleTo(1f, 400, EasingTypes.OutQuart);
|
keyIcon.ScaleTo(1f, 400, Easing.OutQuart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -16,8 +16,6 @@ using System.Linq;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Graphics.Transforms;
|
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Timing;
|
using osu.Game.Rulesets.Timing;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
@ -222,10 +220,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
switch (args.Key)
|
switch (args.Key)
|
||||||
{
|
{
|
||||||
case Key.Minus:
|
case Key.Minus:
|
||||||
transformVisibleTimeRangeTo(visibleTimeRange + time_span_step, 200, EasingTypes.OutQuint);
|
transformVisibleTimeRangeTo(visibleTimeRange + time_span_step, 200, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
case Key.Plus:
|
case Key.Plus:
|
||||||
transformVisibleTimeRangeTo(visibleTimeRange - time_span_step, 200, EasingTypes.OutQuint);
|
transformVisibleTimeRangeTo(visibleTimeRange - time_span_step, 200, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,9 +231,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void transformVisibleTimeRangeTo(double newTimeRange, double duration = 0, EasingTypes easing = EasingTypes.None)
|
private void transformVisibleTimeRangeTo(double newTimeRange, double duration = 0, Easing easing = Easing.None)
|
||||||
{
|
{
|
||||||
TransformTo(newTimeRange, duration, easing, new TransformTimeSpan());
|
this.TransformTo(nameof(visibleTimeRange), newTimeRange, duration, easing);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -244,23 +242,5 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
|
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
|
||||||
barLineContainer.Width = columns.Width;
|
barLineContainer.Width = columns.Width;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TransformTimeSpan : Transform<double, Drawable>
|
|
||||||
{
|
|
||||||
public double CurrentValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double time = Time?.Current ?? 0;
|
|
||||||
if (time < StartTime) return StartValue;
|
|
||||||
if (time >= EndTime) return EndValue;
|
|
||||||
|
|
||||||
return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Apply(Drawable d) => ((ManiaPlayfield)d).visibleTimeRange.Value = (float)CurrentValue;
|
|
||||||
public override void ReadIntoStartValue(Drawable d) => StartValue = ((ManiaPlayfield)d).visibleTimeRange.Value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,12 +94,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
using (fp.BeginAbsoluteSequence(fadeInTime))
|
using (fp.BeginAbsoluteSequence(fadeInTime))
|
||||||
{
|
{
|
||||||
fp.FadeIn(DrawableOsuHitObject.TIME_FADEIN);
|
fp.FadeIn(DrawableOsuHitObject.TIME_FADEIN);
|
||||||
fp.ScaleTo(1, DrawableOsuHitObject.TIME_FADEIN, EasingTypes.Out);
|
fp.ScaleTo(1, DrawableOsuHitObject.TIME_FADEIN, Easing.Out);
|
||||||
|
|
||||||
fp.MoveTo(pointEndPosition, DrawableOsuHitObject.TIME_FADEIN, EasingTypes.Out);
|
fp.MoveTo(pointEndPosition, DrawableOsuHitObject.TIME_FADEIN, Easing.Out);
|
||||||
|
|
||||||
fp.Delay(fadeOutTime - fadeInTime);
|
fp.Delay(fadeOutTime - fadeInTime).FadeOut(DrawableOsuHitObject.TIME_FADEIN);
|
||||||
fp.FadeOut(DrawableOsuHitObject.TIME_FADEIN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fp.Expire(true);
|
fp.Expire(true);
|
||||||
|
@ -112,29 +112,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
double duration = ((HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime) - HitObject.StartTime;
|
double duration = ((HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime) - HitObject.StartTime;
|
||||||
|
|
||||||
using (glow.BeginDelayedSequence(duration))
|
glow.Delay(duration).FadeOut(400);
|
||||||
glow.FadeOut(400);
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
using (BeginDelayedSequence(duration + TIME_PREEMPT))
|
this.Delay(duration + TIME_PREEMPT).FadeOut(TIME_FADEOUT);
|
||||||
FadeOut(TIME_FADEOUT);
|
|
||||||
Expire(true);
|
Expire(true);
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
ApproachCircle.FadeOut(50);
|
ApproachCircle.FadeOut(50);
|
||||||
FadeOut(TIME_FADEOUT / 5);
|
this.FadeOut(TIME_FADEOUT / 5);
|
||||||
Expire();
|
Expire();
|
||||||
break;
|
break;
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
ApproachCircle.FadeOut(50);
|
ApproachCircle.FadeOut(50);
|
||||||
|
|
||||||
const double flash_in = 40;
|
const double flash_in = 40;
|
||||||
|
flash.FadeTo(0.8f, flash_in)
|
||||||
flash.FadeTo(0.8f, flash_in);
|
.Then()
|
||||||
using (flash.BeginDelayedSequence(flash_in))
|
.FadeOut(100);
|
||||||
flash.FadeOut(100);
|
|
||||||
|
|
||||||
explode.FadeIn(flash_in);
|
explode.FadeIn(flash_in);
|
||||||
|
|
||||||
@ -145,8 +142,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
circle.FadeOut();
|
circle.FadeOut();
|
||||||
number.FadeOut();
|
number.FadeOut();
|
||||||
|
|
||||||
FadeOut(800);
|
this.FadeOut(800)
|
||||||
ScaleTo(Scale * 1.5f, 400, EasingTypes.OutQuad);
|
.ScaleTo(Scale * 1.5f, 400, Easing.OutQuad);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expire();
|
Expire();
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -24,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
protected sealed override void UpdateState(ArmedState state)
|
protected sealed override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
Flush();
|
FinishTransforms();
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true))
|
using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true))
|
||||||
{
|
{
|
||||||
@ -44,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
protected virtual void UpdatePreemptState()
|
protected virtual void UpdatePreemptState()
|
||||||
{
|
{
|
||||||
FadeIn(TIME_FADEIN);
|
this.FadeIn(TIME_FADEIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateCurrentState(ArmedState state)
|
protected virtual void UpdateCurrentState(ArmedState state)
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
if (Judgement.Result != HitResult.Miss)
|
if (Judgement.Result != HitResult.Miss)
|
||||||
JudgementText.TransformSpacingTo(new Vector2(14, 0), 1800, EasingTypes.OutQuint);
|
JudgementText.TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint);
|
||||||
|
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
}
|
}
|
||||||
|
@ -158,14 +158,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
ball.FadeIn();
|
ball.FadeIn();
|
||||||
|
|
||||||
Delay(slider.Duration, true);
|
using (BeginDelayedSequence(slider.Duration, true))
|
||||||
|
{
|
||||||
|
body.FadeOut(160);
|
||||||
|
ball.FadeOut(160);
|
||||||
|
|
||||||
body.FadeOut(160);
|
this.FadeOut(800)
|
||||||
ball.FadeOut(160);
|
.Expire();
|
||||||
|
}
|
||||||
FadeOut(800);
|
|
||||||
|
|
||||||
Expire();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable ProxiedLayer => initialCircle.ApproachCircle;
|
public Drawable ProxiedLayer => initialCircle.ApproachCircle;
|
||||||
|
@ -62,14 +62,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);
|
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);
|
||||||
|
|
||||||
ScaleTo(0.5f);
|
this.Animate(
|
||||||
ScaleTo(1.2f, animIn);
|
d => d.FadeIn(animIn),
|
||||||
FadeIn(animIn);
|
d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn)
|
||||||
|
).Then(
|
||||||
Delay(animIn);
|
d => d.ScaleTo(1, 150, Easing.Out)
|
||||||
ScaleTo(1, 150, EasingTypes.Out);
|
);
|
||||||
|
|
||||||
Delay(-animIn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateCurrentState(ArmedState state)
|
protected override void UpdateCurrentState(ArmedState state)
|
||||||
@ -77,16 +75,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
Delay(FadeOutTime - sliderTick.StartTime);
|
this.Delay(FadeOutTime - sliderTick.StartTime).FadeOut();
|
||||||
FadeOut();
|
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
FadeOut(160);
|
this.FadeOut(160)
|
||||||
FadeColour(Color4.Red, 80);
|
.FadeColour(Color4.Red, 80);
|
||||||
break;
|
break;
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
FadeOut(120, EasingTypes.OutQuint);
|
this.FadeOut(120, Easing.OutQuint)
|
||||||
ScaleTo(Scale * 1.5f, 120, EasingTypes.OutQuint);
|
.ScaleTo(Scale * 1.5f, 120, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,9 +174,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ticks.Rotation = disc.Rotation;
|
ticks.Rotation = disc.Rotation;
|
||||||
|
|
||||||
float relativeCircleScale = spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight;
|
float relativeCircleScale = spinner.Scale * circle.DrawHeight / mainContainer.DrawHeight;
|
||||||
disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, EasingTypes.OutQuint);
|
disc.ScaleTo(relativeCircleScale + (1 - relativeCircleScale) * Progress, 200, Easing.OutQuint);
|
||||||
|
|
||||||
symbol.RotateTo(disc.Rotation / 2, 500, EasingTypes.OutQuint);
|
symbol.RotateTo(disc.Rotation / 2, 500, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
@ -184,35 +184,33 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
base.UpdatePreemptState();
|
base.UpdatePreemptState();
|
||||||
|
|
||||||
circleContainer.ScaleTo(spinner.Scale * 0.3f);
|
circleContainer.ScaleTo(spinner.Scale * 0.3f);
|
||||||
circleContainer.ScaleTo(spinner.Scale, TIME_PREEMPT / 1.4f, EasingTypes.OutQuint);
|
circleContainer.ScaleTo(spinner.Scale, TIME_PREEMPT / 1.4f, Easing.OutQuint);
|
||||||
|
|
||||||
disc.RotateTo(-720);
|
disc.RotateTo(-720);
|
||||||
symbol.RotateTo(-720);
|
symbol.RotateTo(-720);
|
||||||
|
|
||||||
mainContainer.ScaleTo(0);
|
mainContainer
|
||||||
mainContainer.ScaleTo(spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, TIME_PREEMPT - 150, EasingTypes.OutQuint);
|
.ScaleTo(0)
|
||||||
|
.ScaleTo(spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, TIME_PREEMPT - 150, Easing.OutQuint)
|
||||||
mainContainer.Delay(TIME_PREEMPT - 150);
|
.Then()
|
||||||
mainContainer.ScaleTo(1, 500, EasingTypes.OutQuint);
|
.ScaleTo(1, 500, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateCurrentState(ArmedState state)
|
protected override void UpdateCurrentState(ArmedState state)
|
||||||
{
|
{
|
||||||
Delay(spinner.Duration, true);
|
var sequence = this.Delay(spinner.Duration).FadeOut(160);
|
||||||
|
|
||||||
FadeOut(160);
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
ScaleTo(Scale * 1.2f, 320, EasingTypes.Out);
|
sequence.ScaleTo(Scale * 1.2f, 320, Easing.Out);
|
||||||
Expire();
|
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
ScaleTo(Scale * 0.8f, 320, EasingTypes.In);
|
sequence.ScaleTo(Scale * 0.8f, 320, Easing.In);
|
||||||
Expire();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
tracking = value;
|
tracking = value;
|
||||||
|
|
||||||
follow.ScaleTo(tracking ? 2.8f : 1, 300, EasingTypes.OutQuint);
|
follow.ScaleTo(tracking ? 2.8f : 1, 300, Easing.OutQuint);
|
||||||
follow.FadeTo(tracking ? 0.2f : 0, 300, EasingTypes.OutQuint);
|
follow.FadeTo(tracking ? 0.2f : 0, 300, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
using (icon.BeginLoopedSequence())
|
icon.Spin(1000, RotationDirection.Clockwise);
|
||||||
icon.RotateTo(360, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateProgress(double progress, int repeat)
|
public void UpdateProgress(double progress, int repeat)
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Transforms;
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -127,13 +126,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
if (Complete && updateCompleteTick())
|
if (Complete && updateCompleteTick())
|
||||||
{
|
{
|
||||||
background.Flush(flushType: typeof(TransformAlpha));
|
background.FinishTransforms(false, nameof(Alpha));
|
||||||
background.FadeTo(tracking_alpha + 0.2f, 60, EasingTypes.OutExpo);
|
background
|
||||||
background.Delay(60);
|
.FadeTo(tracking_alpha + 0.2f, 60, Easing.OutExpo)
|
||||||
background.FadeTo(tracking_alpha, 250, EasingTypes.OutQuint);
|
.Then()
|
||||||
|
.FadeTo(tracking_alpha, 250, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
RotateTo(currentRotation / 2, validAndTracking ? 500 : 1500, EasingTypes.OutExpo);
|
this.RotateTo(currentRotation / 2, validAndTracking ? 500 : 1500, Easing.OutExpo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
|
@ -6,9 +6,9 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Database;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// What easing to use when moving between hitobjects
|
/// What easing to use when moving between hitobjects
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private EasingTypes preferredEasing => DelayedMovements ? EasingTypes.InOutCubic : EasingTypes.Out;
|
private Easing preferredEasing => DelayedMovements ? Easing.InOutCubic : Easing.Out;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
{
|
{
|
||||||
// Default values for circles/sliders
|
// Default values for circles/sliders
|
||||||
Vector2 startPosition = h.StackedPosition;
|
Vector2 startPosition = h.StackedPosition;
|
||||||
EasingTypes easing = preferredEasing;
|
Easing easing = preferredEasing;
|
||||||
float spinnerDirection = -1;
|
float spinnerDirection = -1;
|
||||||
|
|
||||||
// The startPosition for the slider should not be its .Position, but the point on the circle whose tangent crosses the current cursor position
|
// The startPosition for the slider should not be its .Position, but the point on the circle whose tangent crosses the current cursor position
|
||||||
@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
if (spinCentreOffset.Length > SPIN_RADIUS)
|
if (spinCentreOffset.Length > SPIN_RADIUS)
|
||||||
{
|
{
|
||||||
// If moving in from the outside, don't ease out (default eases out). This means auto will "start" spinning immediately after moving into position.
|
// If moving in from the outside, don't ease out (default eases out). This means auto will "start" spinning immediately after moving into position.
|
||||||
easing = EasingTypes.In;
|
easing = Easing.In;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void moveToHitObject(double targetTime, Vector2 targetPos, double hitObjectRadius, EasingTypes easing)
|
private void moveToHitObject(double targetTime, Vector2 targetPos, double hitObjectRadius, Easing easing)
|
||||||
{
|
{
|
||||||
ReplayFrame lastFrame = Frames[Frames.Count - 1];
|
ReplayFrame lastFrame = Frames[Frames.Count - 1];
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ using osu.Game.Rulesets.Taiko.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Beatmaps;
|
using osu.Game.Rulesets.Beatmaps;
|
||||||
|
@ -64,11 +64,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
Delay(BarLine.StartTime - Time.Current);
|
this.Delay(BarLine.StartTime - Time.Current).FadeOut(base_fadeout_time * BarLine.ScrollTime / 1000);
|
||||||
FadeOut(base_fadeout_time * BarLine.ScrollTime / 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateScrollPosition(double time) => MoveToX((float)((BarLine.StartTime - time) / BarLine.ScrollTime));
|
private void updateScrollPosition(double time) => this.MoveToX((float)((BarLine.StartTime - time) / BarLine.ScrollTime));
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
Content.ScaleTo(0, 100, EasingTypes.OutQuint);
|
Content.ScaleTo(0, 100, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,45 +65,42 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
Delay(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true);
|
|
||||||
|
|
||||||
var circlePiece = MainPiece as CirclePiece;
|
var circlePiece = MainPiece as CirclePiece;
|
||||||
|
circlePiece?.FlashBox.FinishTransforms();
|
||||||
|
|
||||||
circlePiece?.FlashBox.Flush();
|
using (BeginDelayedSequence(HitObject.StartTime - Time.Current + Judgement.TimeOffset, true))
|
||||||
|
|
||||||
switch (State)
|
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
switch (State)
|
||||||
Delay(HitObject.HitWindowMiss);
|
{
|
||||||
break;
|
case ArmedState.Idle:
|
||||||
case ArmedState.Miss:
|
this.Delay(HitObject.HitWindowMiss).Expire();
|
||||||
FadeOut(100);
|
break;
|
||||||
break;
|
case ArmedState.Miss:
|
||||||
case ArmedState.Hit:
|
this.FadeOut(100)
|
||||||
FadeOut(600);
|
.Expire();
|
||||||
|
break;
|
||||||
|
case ArmedState.Hit:
|
||||||
|
var flash = circlePiece?.FlashBox;
|
||||||
|
if (flash != null)
|
||||||
|
{
|
||||||
|
flash.FadeTo(0.9f);
|
||||||
|
flash.FadeOut(300);
|
||||||
|
}
|
||||||
|
|
||||||
var flash = circlePiece?.FlashBox;
|
const float gravity_time = 300;
|
||||||
if (flash != null)
|
const float gravity_travel_height = 200;
|
||||||
{
|
|
||||||
flash.FadeTo(0.9f);
|
|
||||||
flash.FadeOut(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Content.ScaleTo(0.8f, gravity_time * 2, Easing.OutQuad);
|
||||||
|
|
||||||
FadeOut(800);
|
this.FadeOut(800)
|
||||||
|
.MoveToY(-gravity_travel_height, gravity_time, Easing.Out)
|
||||||
|
.Then()
|
||||||
|
.MoveToY(gravity_travel_height * 2, gravity_time * 2, Easing.In);
|
||||||
|
|
||||||
const float gravity_time = 300;
|
Expire();
|
||||||
const float gravity_travel_height = 200;
|
break;
|
||||||
|
}
|
||||||
Content.ScaleTo(0.8f, gravity_time * 2, EasingTypes.OutQuad);
|
|
||||||
|
|
||||||
MoveToY(-gravity_travel_height, gravity_time, EasingTypes.Out);
|
|
||||||
Delay(gravity_time, true);
|
|
||||||
MoveToY(gravity_travel_height * 2, gravity_time * 2, EasingTypes.In);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expire();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,13 +147,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
var completion = (float)userHits / HitObject.RequiredHits;
|
var completion = (float)userHits / HitObject.RequiredHits;
|
||||||
|
|
||||||
expandingRing.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50);
|
expandingRing
|
||||||
using (expandingRing.BeginDelayedSequence(50))
|
.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50)
|
||||||
expandingRing.FadeTo(completion / 8, 2000, EasingTypes.OutQuint);
|
.Then()
|
||||||
|
.FadeTo(completion / 8, 2000, Easing.OutQuint);
|
||||||
|
|
||||||
symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, EasingTypes.OutQuint);
|
symbol.RotateTo((float)(completion * HitObject.Duration / 8), 4000, Easing.OutQuint);
|
||||||
|
|
||||||
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, EasingTypes.OutQuint);
|
expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint);
|
||||||
|
|
||||||
if (userHits == HitObject.RequiredHits)
|
if (userHits == HitObject.RequiredHits)
|
||||||
{
|
{
|
||||||
@ -180,26 +181,21 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
const float preempt = 100;
|
const float preempt = 100;
|
||||||
|
|
||||||
Delay(HitObject.StartTime - Time.Current - preempt, true);
|
|
||||||
|
|
||||||
targetRing.ScaleTo(target_ring_scale, preempt * 4, EasingTypes.OutQuint);
|
|
||||||
|
|
||||||
Delay(preempt, true);
|
|
||||||
|
|
||||||
Delay(Judgement.TimeOffset + HitObject.Duration, true);
|
|
||||||
|
|
||||||
const float out_transition_time = 300;
|
const float out_transition_time = 300;
|
||||||
|
|
||||||
|
double untilStartTime = HitObject.StartTime - Time.Current;
|
||||||
|
double untilJudgement = untilStartTime + Judgement.TimeOffset + HitObject.Duration;
|
||||||
|
|
||||||
|
targetRing.Delay(untilStartTime - preempt).ScaleTo(target_ring_scale, preempt * 4, Easing.OutQuint);
|
||||||
|
this.Delay(untilJudgement).FadeOut(out_transition_time, Easing.Out);
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
bodyContainer.ScaleTo(1.4f, out_transition_time);
|
bodyContainer.Delay(untilJudgement).ScaleTo(1.4f, out_transition_time);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
FadeOut(out_transition_time, EasingTypes.Out);
|
|
||||||
|
|
||||||
Expire();
|
Expire();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,9 +166,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
double duration = timingPoint.BeatLength * 2;
|
double duration = timingPoint.BeatLength * 2;
|
||||||
|
|
||||||
background.FadeEdgeEffectTo(1, pre_beat_transition_time, EasingTypes.OutQuint);
|
background
|
||||||
using (background.BeginDelayedSequence(pre_beat_transition_time))
|
.FadeEdgeEffectTo(1, pre_beat_transition_time, Easing.OutQuint)
|
||||||
background.FadeEdgeEffectTo(edge_alpha_kiai, duration, EasingTypes.OutQuint);
|
.Then()
|
||||||
|
.FadeEdgeEffectTo(edge_alpha_kiai, duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,8 +5,8 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
|
@ -6,6 +6,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.UI
|
namespace osu.Game.Rulesets.Taiko.UI
|
||||||
{
|
{
|
||||||
@ -47,7 +48,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
switch (Judgement.Result)
|
switch (Judgement.Result)
|
||||||
{
|
{
|
||||||
case HitResult.Hit:
|
case HitResult.Hit:
|
||||||
MoveToY(-100, 500);
|
this.MoveToY(-100, 500);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,8 +62,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
ScaleTo(3f, 1000, EasingTypes.OutQuint);
|
this.ScaleTo(3f, 1000, Easing.OutQuint);
|
||||||
FadeOut(500);
|
this.FadeOut(500);
|
||||||
|
|
||||||
Expire();
|
Expire();
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void VisualiseSecondHit()
|
public void VisualiseSecondHit()
|
||||||
{
|
{
|
||||||
ResizeTo(new Vector2(TaikoPlayfield.HIT_TARGET_OFFSET + TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER), 50);
|
this.ResizeTo(new Vector2(TaikoPlayfield.HIT_TARGET_OFFSET + TaikoHitObject.DEFAULT_STRONG_CIRCLE_DIAMETER), 50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,15 +149,17 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
const float down_time = 40;
|
const float down_time = 40;
|
||||||
const float up_time = 1000;
|
const float up_time = 1000;
|
||||||
|
|
||||||
back.ScaleTo(target.Scale.X - scale_amount, down_time, EasingTypes.OutQuint);
|
back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint)
|
||||||
back.Delay(down_time);
|
.Then()
|
||||||
back.ScaleTo(1, up_time, EasingTypes.OutQuint);
|
.ScaleTo(1, up_time, Easing.OutQuint);
|
||||||
|
|
||||||
target.ScaleTo(target.Scale.X - scale_amount, down_time, EasingTypes.OutQuint);
|
target.Animate(
|
||||||
target.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, EasingTypes.OutQuint);
|
t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint),
|
||||||
target.Delay(down_time);
|
t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint)
|
||||||
target.ScaleTo(1, up_time, EasingTypes.OutQuint);
|
).Then(
|
||||||
target.FadeOut(up_time, EasingTypes.OutQuint);
|
t => t.ScaleTo(1, up_time, Easing.OutQuint),
|
||||||
|
t => t.FadeOut(up_time, Easing.OutQuint)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -59,8 +59,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
ScaleTo(new Vector2(1, 3f), 500, EasingTypes.OutQuint);
|
this.ScaleTo(new Vector2(1, 3f), 500, Easing.OutQuint);
|
||||||
FadeOut(250);
|
this.FadeOut(250);
|
||||||
|
|
||||||
Expire();
|
Expire();
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = 10,
|
Width = 10,
|
||||||
ColourInfo = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
|
Colour = Framework.Graphics.Colour.ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.6f), Color4.Black.Opacity(0)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -16,12 +16,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class OsuLegacyDecoderTest
|
public class OsuLegacyDecoderTest
|
||||||
{
|
{
|
||||||
[OneTimeSetUpAttribute]
|
|
||||||
public void SetUp()
|
|
||||||
{
|
|
||||||
OsuLegacyDecoder.Register();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDecodeMetadata()
|
public void TestDecodeMetadata()
|
||||||
{
|
{
|
||||||
|
@ -10,8 +10,10 @@ using System.Threading.Tasks;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Desktop.Platform;
|
using osu.Framework.Desktop.Platform;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.IO
|
namespace osu.Game.Tests.Beatmaps.IO
|
||||||
{
|
{
|
||||||
@ -26,15 +28,15 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new HeadlessGameHost())
|
using (HeadlessGameHost host = new HeadlessGameHost())
|
||||||
{
|
{
|
||||||
loadOsu(host);
|
var osu = loadOsu(host);
|
||||||
|
|
||||||
var temp = prepareTempCopy(osz_path);
|
var temp = prepareTempCopy(osz_path);
|
||||||
|
|
||||||
Assert.IsTrue(File.Exists(temp));
|
Assert.IsTrue(File.Exists(temp));
|
||||||
|
|
||||||
host.Dependencies.Get<BeatmapDatabase>().Import(temp);
|
osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||||
|
|
||||||
ensureLoaded(host);
|
ensureLoaded(osu);
|
||||||
|
|
||||||
Assert.IsFalse(File.Exists(temp));
|
Assert.IsFalse(File.Exists(temp));
|
||||||
}
|
}
|
||||||
@ -49,7 +51,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
Assert.IsTrue(host.IsPrimaryInstance);
|
Assert.IsTrue(host.IsPrimaryInstance);
|
||||||
Assert.IsTrue(!client.IsPrimaryInstance);
|
Assert.IsTrue(!client.IsPrimaryInstance);
|
||||||
|
|
||||||
loadOsu(host);
|
var osu = loadOsu(host);
|
||||||
|
|
||||||
var temp = prepareTempCopy(osz_path);
|
var temp = prepareTempCopy(osz_path);
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
if (!importer.ImportAsync(temp).Wait(10000))
|
if (!importer.ImportAsync(temp).Wait(10000))
|
||||||
Assert.Fail(@"IPC took too long to send");
|
Assert.Fail(@"IPC took too long to send");
|
||||||
|
|
||||||
ensureLoaded(host);
|
ensureLoaded(osu);
|
||||||
|
|
||||||
Assert.IsFalse(File.Exists(temp));
|
Assert.IsFalse(File.Exists(temp));
|
||||||
}
|
}
|
||||||
@ -71,16 +73,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
//unfortunately for the time being we need to reference osu.Framework.Desktop for a game host here.
|
||||||
using (HeadlessGameHost host = new HeadlessGameHost())
|
using (HeadlessGameHost host = new HeadlessGameHost())
|
||||||
{
|
{
|
||||||
loadOsu(host);
|
var osu = loadOsu(host);
|
||||||
|
|
||||||
var temp = prepareTempCopy(osz_path);
|
var temp = prepareTempCopy(osz_path);
|
||||||
|
|
||||||
Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated");
|
Assert.IsTrue(File.Exists(temp), "Temporary file copy never substantiated");
|
||||||
|
|
||||||
using (File.OpenRead(temp))
|
using (File.OpenRead(temp))
|
||||||
host.Dependencies.Get<BeatmapDatabase>().Import(temp);
|
osu.Dependencies.Get<BeatmapManager>().Import(temp);
|
||||||
|
|
||||||
ensureLoaded(host);
|
ensureLoaded(osu);
|
||||||
|
|
||||||
File.Delete(temp);
|
File.Delete(temp);
|
||||||
|
|
||||||
@ -103,20 +105,21 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
|
|
||||||
//reset beatmap database (sqlite and storage backing)
|
//reset beatmap database (sqlite and storage backing)
|
||||||
host.Dependencies.Get<RulesetDatabase>().Reset();
|
osu.Dependencies.Get<RulesetStore>().Reset();
|
||||||
host.Dependencies.Get<BeatmapDatabase>().Reset();
|
osu.Dependencies.Get<BeatmapManager>().Reset();
|
||||||
|
|
||||||
return osu;
|
return osu;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureLoaded(GameHost host, int timeout = 60000)
|
private void ensureLoaded(OsuGameBase osu, int timeout = 60000)
|
||||||
{
|
{
|
||||||
IEnumerable<BeatmapSetInfo> resultSets = null;
|
IEnumerable<BeatmapSetInfo> resultSets = null;
|
||||||
|
|
||||||
|
var store = osu.Dependencies.Get<BeatmapManager>();
|
||||||
|
|
||||||
Action waitAction = () =>
|
Action waitAction = () =>
|
||||||
{
|
{
|
||||||
while (!(resultSets = host.Dependencies.Get<BeatmapDatabase>()
|
while (!(resultSets = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526)).Any())
|
||||||
.Query<BeatmapSetInfo>().Where(s => s.OnlineBeatmapSetID == 241526)).Any())
|
|
||||||
Thread.Sleep(50);
|
Thread.Sleep(50);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,15 +135,14 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
//if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
|
//if we don't re-check here, the set will be inserted but the beatmaps won't be present yet.
|
||||||
waitAction = () =>
|
waitAction = () =>
|
||||||
{
|
{
|
||||||
while ((resultBeatmaps = host.Dependencies.Get<BeatmapDatabase>()
|
while ((resultBeatmaps = store.QueryBeatmaps(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12)
|
||||||
.GetAllWithChildren<BeatmapInfo>(s => s.OnlineBeatmapSetID == 241526 && s.BaseDifficultyID > 0)).Count() != 12)
|
|
||||||
Thread.Sleep(50);
|
Thread.Sleep(50);
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout),
|
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(timeout),
|
||||||
@"Beatmaps did not import to the database in allocated time");
|
@"Beatmaps did not import to the database in allocated time");
|
||||||
|
|
||||||
var set = host.Dependencies.Get<BeatmapDatabase>().GetChildren(resultSets.First());
|
var set = store.QueryBeatmapSets(s => s.OnlineBeatmapSetID == 241526).First();
|
||||||
|
|
||||||
Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(),
|
Assert.IsTrue(set.Beatmaps.Count == resultBeatmaps.Count(),
|
||||||
$@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count}).");
|
$@"Incorrect database beatmap count post-import ({resultBeatmaps.Count()} but should be {set.Beatmaps.Count}).");
|
||||||
@ -150,16 +152,16 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
|
|
||||||
Assert.IsTrue(set.Beatmaps.Count > 0);
|
Assert.IsTrue(set.Beatmaps.Count > 0);
|
||||||
|
|
||||||
var beatmap = host.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
var beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 0))?.Beatmap;
|
||||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||||
|
|
||||||
beatmap = host.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
|
beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 1))?.Beatmap;
|
||||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||||
|
|
||||||
beatmap = host.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
|
beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 2))?.Beatmap;
|
||||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||||
|
|
||||||
beatmap = host.Dependencies.Get<BeatmapDatabase>().GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
beatmap = store.GetWorkingBeatmap(set.Beatmaps.First(b => b.RulesetID == 3))?.Beatmap;
|
||||||
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
Assert.IsTrue(beatmap?.HitObjects.Count > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,23 +2,18 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.IO;
|
using osu.Game.Beatmaps.IO;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.IO
|
namespace osu.Game.Tests.Beatmaps.IO
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class OszArchiveReaderTest
|
public class OszArchiveReaderTest
|
||||||
{
|
{
|
||||||
[OneTimeSetUpAttribute]
|
|
||||||
public void SetUp()
|
|
||||||
{
|
|
||||||
OszArchiveReader.Register();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestReadBeatmaps()
|
public void TestReadBeatmaps()
|
||||||
{
|
{
|
||||||
@ -40,7 +35,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
"Soleily - Renatus (MMzz) [Muzukashii].osu",
|
"Soleily - Renatus (MMzz) [Muzukashii].osu",
|
||||||
"Soleily - Renatus (MMzz) [Oni].osu"
|
"Soleily - Renatus (MMzz) [Oni].osu"
|
||||||
};
|
};
|
||||||
var maps = reader.BeatmapFilenames;
|
var maps = reader.Filenames.ToArray();
|
||||||
foreach (var map in expected)
|
foreach (var map in expected)
|
||||||
Assert.Contains(map, maps);
|
Assert.Contains(map, maps);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using SQLite.Net.Attributes;
|
using SQLite.Net.Attributes;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public class BeatmapDifficulty
|
public class BeatmapDifficulty
|
||||||
{
|
{
|
@ -1,14 +1,15 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using osu.Game.IO.Serialization;
|
|
||||||
using SQLite.Net.Attributes;
|
|
||||||
using SQLiteNetExtensions.Attributes;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using osu.Game.IO.Serialization;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using SQLite.Net.Attributes;
|
||||||
|
using SQLiteNetExtensions.Attributes;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable
|
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable
|
||||||
{
|
{
|
||||||
@ -60,7 +61,7 @@ namespace osu.Game.Database
|
|||||||
[ForeignKey(typeof(RulesetInfo))]
|
[ForeignKey(typeof(RulesetInfo))]
|
||||||
public int RulesetID { get; set; }
|
public int RulesetID { get; set; }
|
||||||
|
|
||||||
[OneToOne(CascadeOperations = CascadeOperation.All)]
|
[OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
|
||||||
public RulesetInfo Ruleset { get; set; }
|
public RulesetInfo Ruleset { get; set; }
|
||||||
|
|
||||||
public bool LetterboxInBreaks { get; set; }
|
public bool LetterboxInBreaks { get; set; }
|
||||||
@ -94,11 +95,11 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
public bool AudioEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||||
BeatmapSet.Path == other.BeatmapSet.Path &&
|
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||||
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
|
(Metadata ?? BeatmapSet.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSet.Metadata).AudioFile;
|
||||||
|
|
||||||
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||||
BeatmapSet.Path == other.BeatmapSet.Path &&
|
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||||
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
499
osu.Game/Beatmaps/BeatmapManager.cs
Normal file
499
osu.Game/Beatmaps/BeatmapManager.cs
Normal file
@ -0,0 +1,499 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using Ionic.Zip;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Logging;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.Beatmaps.Formats;
|
||||||
|
using osu.Game.Beatmaps.IO;
|
||||||
|
using osu.Game.IO;
|
||||||
|
using osu.Game.IPC;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using SQLite.Net;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the storage and retrieval of Beatmaps/WorkingBeatmaps.
|
||||||
|
/// </summary>
|
||||||
|
public class BeatmapManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a new <see cref="BeatmapSetInfo"/> becomes available in the database.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a <see cref="BeatmapSetInfo"/> is removed from the database.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||||
|
/// </summary>
|
||||||
|
public WorkingBeatmap DefaultBeatmap { private get; set; }
|
||||||
|
|
||||||
|
private readonly Storage storage;
|
||||||
|
|
||||||
|
private readonly FileStore files;
|
||||||
|
|
||||||
|
private readonly RulesetStore rulesets;
|
||||||
|
|
||||||
|
private readonly BeatmapStore beatmaps;
|
||||||
|
|
||||||
|
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||||
|
private BeatmapIPCChannel ipc;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set an endpoint for notifications to be posted to.
|
||||||
|
/// </summary>
|
||||||
|
public Action<Notification> PostNotification { private get; set; }
|
||||||
|
|
||||||
|
public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null)
|
||||||
|
{
|
||||||
|
beatmaps = new BeatmapStore(connection);
|
||||||
|
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
|
||||||
|
beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
|
||||||
|
|
||||||
|
this.storage = storage;
|
||||||
|
this.files = files;
|
||||||
|
this.rulesets = rulesets;
|
||||||
|
|
||||||
|
if (importHost != null)
|
||||||
|
ipc = new BeatmapIPCChannel(importHost, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Import one or more <see cref="BeatmapSetInfo"/> from filesystem <paramref name="paths"/>.
|
||||||
|
/// This will post a notification tracking import progress.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="paths">One or more beatmap locations on disk.</param>
|
||||||
|
public void Import(params string[] paths)
|
||||||
|
{
|
||||||
|
var notification = new ProgressNotification
|
||||||
|
{
|
||||||
|
Text = "Beatmap import is initialising...",
|
||||||
|
Progress = 0,
|
||||||
|
State = ProgressNotificationState.Active,
|
||||||
|
};
|
||||||
|
|
||||||
|
PostNotification?.Invoke(notification);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (string path in paths)
|
||||||
|
{
|
||||||
|
if (notification.State == ProgressNotificationState.Cancelled)
|
||||||
|
// user requested abort
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
notification.Text = $"Importing ({i} of {paths.Length})\n{Path.GetFileName(path)}";
|
||||||
|
using (ArchiveReader reader = getReaderFrom(path))
|
||||||
|
Import(reader);
|
||||||
|
|
||||||
|
notification.Progress = (float)++i / paths.Length;
|
||||||
|
|
||||||
|
// We may or may not want to delete the file depending on where it is stored.
|
||||||
|
// e.g. reconstructing/repairing database with beatmaps from default storage.
|
||||||
|
// Also, not always a single file, i.e. for LegacyFilesystemReader
|
||||||
|
// TODO: Add a check to prevent files from storage to be deleted.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(path))
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e = e.InnerException ?? e;
|
||||||
|
Logger.Error(e, @"Could not import beatmap set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.State = ProgressNotificationState.Completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly object importLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Import a beatmap from an <see cref="ArchiveReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="archiveReader">The beatmap to be imported.</param>
|
||||||
|
public BeatmapSetInfo Import(ArchiveReader archiveReader)
|
||||||
|
{
|
||||||
|
// let's only allow one concurrent import at a time for now.
|
||||||
|
lock (importLock)
|
||||||
|
{
|
||||||
|
BeatmapSetInfo set = importToStorage(archiveReader);
|
||||||
|
Import(set);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Import a beatmap from a <see cref="BeatmapSetInfo"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSetInfo">The beatmap to be imported.</param>
|
||||||
|
public void Import(BeatmapSetInfo beatmapSetInfo)
|
||||||
|
{
|
||||||
|
// If we have an ID then we already exist in the database.
|
||||||
|
if (beatmapSetInfo.ID != 0) return;
|
||||||
|
|
||||||
|
lock (beatmaps)
|
||||||
|
beatmaps.Add(beatmapSetInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete a beatmap from the manager.
|
||||||
|
/// Is a no-op for already deleted beatmaps.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||||
|
public void Delete(BeatmapSetInfo beatmapSet)
|
||||||
|
{
|
||||||
|
lock (beatmaps)
|
||||||
|
if (!beatmaps.Delete(beatmapSet)) return;
|
||||||
|
|
||||||
|
if (!beatmapSet.Protected)
|
||||||
|
files.Dereference(beatmapSet.Files.Select(f => f.FileInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
|
||||||
|
/// Is a no-op for already usable beatmaps.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSet">The beatmap to restore.</param>
|
||||||
|
public void Undelete(BeatmapSetInfo beatmapSet)
|
||||||
|
{
|
||||||
|
lock (beatmaps)
|
||||||
|
if (!beatmaps.Undelete(beatmapSet)) return;
|
||||||
|
|
||||||
|
if (!beatmapSet.Protected)
|
||||||
|
files.Reference(beatmapSet.Files.Select(f => f.FileInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve a <see cref="WorkingBeatmap"/> instance for the provided <see cref="BeatmapInfo"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapInfo">The beatmap to lookup.</param>
|
||||||
|
/// <param name="previous">The currently loaded <see cref="WorkingBeatmap"/>. Allows for optimisation where elements are shared with the new beatmap.</param>
|
||||||
|
/// <returns>A <see cref="WorkingBeatmap"/> instance correlating to the provided <see cref="BeatmapInfo"/>.</returns>
|
||||||
|
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null)
|
||||||
|
{
|
||||||
|
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
|
||||||
|
return DefaultBeatmap;
|
||||||
|
|
||||||
|
lock (beatmaps)
|
||||||
|
beatmaps.Populate(beatmapInfo);
|
||||||
|
|
||||||
|
if (beatmapInfo.BeatmapSet == null)
|
||||||
|
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");
|
||||||
|
|
||||||
|
if (beatmapInfo.Metadata == null)
|
||||||
|
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
|
||||||
|
|
||||||
|
WorkingBeatmap working = new BeatmapManagerWorkingBeatmap(files.Store, beatmapInfo);
|
||||||
|
|
||||||
|
previous?.TransferTo(working);
|
||||||
|
|
||||||
|
return working;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset the manager to an empty state.
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
lock (beatmaps)
|
||||||
|
beatmaps.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||||
|
public BeatmapSetInfo QueryBeatmapSet(Func<BeatmapSetInfo, bool> query)
|
||||||
|
{
|
||||||
|
lock (beatmaps)
|
||||||
|
{
|
||||||
|
BeatmapSetInfo set = beatmaps.Query<BeatmapSetInfo>().FirstOrDefault(query);
|
||||||
|
|
||||||
|
if (set != null)
|
||||||
|
beatmaps.Populate(set);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>Results from the provided query.</returns>
|
||||||
|
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
|
||||||
|
{
|
||||||
|
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||||
|
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
|
||||||
|
{
|
||||||
|
lock (beatmaps)
|
||||||
|
{
|
||||||
|
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
|
||||||
|
|
||||||
|
if (set != null)
|
||||||
|
beatmaps.Populate(set);
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The query.</param>
|
||||||
|
/// <returns>Results from the provided query.</returns>
|
||||||
|
public List<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query)
|
||||||
|
{
|
||||||
|
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an <see cref="ArchiveReader"/> from a valid storage path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">A file or folder path resolving the beatmap content.</param>
|
||||||
|
/// <returns>A reader giving access to the beatmap's content.</returns>
|
||||||
|
private ArchiveReader getReaderFrom(string path)
|
||||||
|
{
|
||||||
|
if (ZipFile.IsZipFile(path))
|
||||||
|
return new OszArchiveReader(storage.GetStream(path));
|
||||||
|
else
|
||||||
|
return new LegacyFilesystemReader(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Import a beamap into our local <see cref="FileStore"/> storage.
|
||||||
|
/// If the beatmap is already imported, the existing instance will be returned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The beatmap archive to be read.</param>
|
||||||
|
/// <returns>The imported beatmap, or an existing instance if it is already present.</returns>
|
||||||
|
private BeatmapSetInfo importToStorage(ArchiveReader reader)
|
||||||
|
{
|
||||||
|
// for now, concatenate all .osu files in the set to create a unique hash.
|
||||||
|
MemoryStream hashable = new MemoryStream();
|
||||||
|
foreach (string file in reader.Filenames.Where(f => f.EndsWith(".osu")))
|
||||||
|
using (Stream s = reader.GetStream(file))
|
||||||
|
s.CopyTo(hashable);
|
||||||
|
|
||||||
|
var hash = hashable.ComputeSHA2Hash();
|
||||||
|
|
||||||
|
// check if this beatmap has already been imported and exit early if so.
|
||||||
|
BeatmapSetInfo beatmapSet;
|
||||||
|
lock (beatmaps)
|
||||||
|
beatmapSet = beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => b.Hash == hash).FirstOrDefault();
|
||||||
|
|
||||||
|
if (beatmapSet != null)
|
||||||
|
{
|
||||||
|
Undelete(beatmapSet);
|
||||||
|
return beatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<BeatmapSetFileInfo> fileInfos = new List<BeatmapSetFileInfo>();
|
||||||
|
|
||||||
|
// import files to manager
|
||||||
|
foreach (string file in reader.Filenames)
|
||||||
|
using (Stream s = reader.GetStream(file))
|
||||||
|
fileInfos.Add(new BeatmapSetFileInfo
|
||||||
|
{
|
||||||
|
Filename = file,
|
||||||
|
FileInfo = files.Add(s)
|
||||||
|
});
|
||||||
|
|
||||||
|
BeatmapMetadata metadata;
|
||||||
|
|
||||||
|
using (var stream = new StreamReader(reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu")))))
|
||||||
|
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
||||||
|
|
||||||
|
beatmapSet = new BeatmapSetInfo
|
||||||
|
{
|
||||||
|
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
||||||
|
Beatmaps = new List<BeatmapInfo>(),
|
||||||
|
Hash = hash,
|
||||||
|
Files = fileInfos,
|
||||||
|
Metadata = metadata
|
||||||
|
};
|
||||||
|
|
||||||
|
var mapNames = reader.Filenames.Where(f => f.EndsWith(".osu"));
|
||||||
|
|
||||||
|
foreach (var name in mapNames)
|
||||||
|
{
|
||||||
|
using (var raw = reader.GetStream(name))
|
||||||
|
using (var ms = new MemoryStream()) //we need a memory stream so we can seek and shit
|
||||||
|
using (var sr = new StreamReader(ms))
|
||||||
|
{
|
||||||
|
raw.CopyTo(ms);
|
||||||
|
ms.Position = 0;
|
||||||
|
|
||||||
|
var decoder = BeatmapDecoder.GetDecoder(sr);
|
||||||
|
Beatmap beatmap = decoder.Decode(sr);
|
||||||
|
|
||||||
|
beatmap.BeatmapInfo.Path = name;
|
||||||
|
beatmap.BeatmapInfo.Hash = ms.ComputeSHA2Hash();
|
||||||
|
|
||||||
|
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
|
||||||
|
beatmap.BeatmapInfo.Metadata = null;
|
||||||
|
|
||||||
|
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
||||||
|
beatmap.BeatmapInfo.Ruleset = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID);
|
||||||
|
beatmap.BeatmapInfo.StarDifficulty = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap)
|
||||||
|
.Calculate() ?? 0;
|
||||||
|
|
||||||
|
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return beatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of all usable <see cref="BeatmapSetInfo"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="populate">Whether returned objects should be pre-populated with all data.</param>
|
||||||
|
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
|
||||||
|
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool populate = true)
|
||||||
|
{
|
||||||
|
lock (beatmaps)
|
||||||
|
{
|
||||||
|
if (populate)
|
||||||
|
return beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||||
|
else
|
||||||
|
return beatmaps.Query<BeatmapSetInfo>(b => !b.DeletePending).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap
|
||||||
|
{
|
||||||
|
private readonly IResourceStore<byte[]> store;
|
||||||
|
|
||||||
|
public BeatmapManagerWorkingBeatmap(IResourceStore<byte[]> store, BeatmapInfo beatmapInfo)
|
||||||
|
: base(beatmapInfo)
|
||||||
|
{
|
||||||
|
this.store = store;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Beatmap GetBeatmap()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Beatmap beatmap;
|
||||||
|
|
||||||
|
BeatmapDecoder decoder;
|
||||||
|
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
|
||||||
|
{
|
||||||
|
decoder = BeatmapDecoder.GetDecoder(stream);
|
||||||
|
beatmap = decoder.Decode(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beatmap == null || BeatmapSetInfo.StoryboardFile == null)
|
||||||
|
return beatmap;
|
||||||
|
|
||||||
|
using (var stream = new StreamReader(store.GetStream(getPathForFile(BeatmapSetInfo.StoryboardFile))))
|
||||||
|
decoder.Decode(stream, beatmap);
|
||||||
|
|
||||||
|
|
||||||
|
return beatmap;
|
||||||
|
}
|
||||||
|
catch { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getPathForFile(string filename) => BeatmapSetInfo.Files.First(f => f.Filename == filename).FileInfo.StoragePath;
|
||||||
|
|
||||||
|
protected override Texture GetBackground()
|
||||||
|
{
|
||||||
|
if (Metadata?.BackgroundFile == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new TextureStore(new RawTextureLoaderStore(store), false).Get(getPathForFile(Metadata.BackgroundFile));
|
||||||
|
}
|
||||||
|
catch { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Track GetTrack()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
|
||||||
|
return trackData == null ? null : new TrackBass(trackData);
|
||||||
|
}
|
||||||
|
catch { return new TrackVirtual(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ImportFromStable()
|
||||||
|
{
|
||||||
|
string stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!", "Songs");
|
||||||
|
if (!Directory.Exists(stableInstallPath))
|
||||||
|
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu", "Songs");
|
||||||
|
|
||||||
|
if (!Directory.Exists(stableInstallPath))
|
||||||
|
{
|
||||||
|
Logger.Log("Couldn't find an osu!stable installation!", LoggingTarget.Information, LogLevel.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Import(Directory.GetDirectories(stableInstallPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteAll()
|
||||||
|
{
|
||||||
|
var maps = GetAllUsableBeatmapSets().ToArray();
|
||||||
|
|
||||||
|
if (maps.Length == 0) return;
|
||||||
|
|
||||||
|
var notification = new ProgressNotification
|
||||||
|
{
|
||||||
|
Progress = 0,
|
||||||
|
State = ProgressNotificationState.Active,
|
||||||
|
};
|
||||||
|
|
||||||
|
PostNotification?.Invoke(notification);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
foreach (var b in maps)
|
||||||
|
{
|
||||||
|
if (notification.State == ProgressNotificationState.Cancelled)
|
||||||
|
// user requested abort
|
||||||
|
return;
|
||||||
|
|
||||||
|
notification.Text = $"Deleting ({i} of {maps.Length})";
|
||||||
|
notification.Progress = (float)++i / maps.Length;
|
||||||
|
Delete(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
notification.State = ProgressNotificationState.Completed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ using System.Linq;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using SQLite.Net.Attributes;
|
using SQLite.Net.Attributes;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public class BeatmapMetadata
|
public class BeatmapMetadata
|
||||||
{
|
{
|
@ -4,7 +4,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Beatmap metrics based on acculumated online data from community plays.
|
/// Beatmap metrics based on acculumated online data from community plays.
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Beatmap info retrieved for previewing locally without having the beatmap downloaded.
|
/// Beatmap info retrieved for previewing locally without having the beatmap downloaded.
|
27
osu.Game/Beatmaps/BeatmapSetFileInfo.cs
Normal file
27
osu.Game/Beatmaps/BeatmapSetFileInfo.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.IO;
|
||||||
|
using SQLite.Net.Attributes;
|
||||||
|
using SQLiteNetExtensions.Attributes;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
public class BeatmapSetFileInfo
|
||||||
|
{
|
||||||
|
[PrimaryKey, AutoIncrement]
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(typeof(BeatmapSetInfo)), NotNull]
|
||||||
|
public int BeatmapSetInfoID { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(typeof(FileInfo)), NotNull]
|
||||||
|
public int FileInfoID { get; set; }
|
||||||
|
|
||||||
|
[OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
|
||||||
|
public FileInfo FileInfo { get; set; }
|
||||||
|
|
||||||
|
[NotNull]
|
||||||
|
public string Filename { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ using System.Linq;
|
|||||||
using SQLite.Net.Attributes;
|
using SQLite.Net.Attributes;
|
||||||
using SQLiteNetExtensions.Attributes;
|
using SQLiteNetExtensions.Attributes;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public class BeatmapSetInfo
|
public class BeatmapSetInfo
|
||||||
{
|
{
|
||||||
@ -34,8 +34,11 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
public string Hash { get; set; }
|
public string Hash { get; set; }
|
||||||
|
|
||||||
public string Path { get; set; }
|
public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
|
||||||
|
|
||||||
public string StoryboardFile { get; set; }
|
[OneToMany(CascadeOperations = CascadeOperation.All)]
|
||||||
|
public List<BeatmapSetFileInfo> Files { get; set; }
|
||||||
|
|
||||||
|
public bool Protected { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Beatmap set info retrieved for previewing locally without having the set downloaded.
|
/// Beatmap set info retrieved for previewing locally without having the set downloaded.
|
152
osu.Game/Beatmaps/BeatmapStore.cs
Normal file
152
osu.Game/Beatmaps/BeatmapStore.cs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Logging;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using SQLite.Net;
|
||||||
|
using SQLiteNetExtensions.Extensions;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the storage and retrieval of Beatmaps/BeatmapSets to the database backing
|
||||||
|
/// </summary>
|
||||||
|
public class BeatmapStore : DatabaseBackedStore
|
||||||
|
{
|
||||||
|
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||||
|
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
|
||||||
|
/// The initial version is 1.
|
||||||
|
/// </summary>
|
||||||
|
protected override int StoreVersion => 2;
|
||||||
|
|
||||||
|
public BeatmapStore(SQLiteConnection connection)
|
||||||
|
: base(connection)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Type[] ValidTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(BeatmapSetInfo),
|
||||||
|
typeof(BeatmapInfo),
|
||||||
|
typeof(BeatmapMetadata),
|
||||||
|
typeof(BeatmapDifficulty),
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override void Prepare(bool reset = false)
|
||||||
|
{
|
||||||
|
if (reset)
|
||||||
|
{
|
||||||
|
Connection.DropTable<BeatmapMetadata>();
|
||||||
|
Connection.DropTable<BeatmapDifficulty>();
|
||||||
|
Connection.DropTable<BeatmapSetInfo>();
|
||||||
|
Connection.DropTable<BeatmapSetFileInfo>();
|
||||||
|
Connection.DropTable<BeatmapInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection.CreateTable<BeatmapMetadata>();
|
||||||
|
Connection.CreateTable<BeatmapDifficulty>();
|
||||||
|
Connection.CreateTable<BeatmapSetInfo>();
|
||||||
|
Connection.CreateTable<BeatmapSetFileInfo>();
|
||||||
|
Connection.CreateTable<BeatmapInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void StartupTasks()
|
||||||
|
{
|
||||||
|
base.StartupTasks();
|
||||||
|
cleanupPendingDeletions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform migrations between two store versions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
|
||||||
|
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
|
||||||
|
protected override void PerformMigration(int currentVersion, int targetVersion)
|
||||||
|
{
|
||||||
|
base.PerformMigration(currentVersion, targetVersion);
|
||||||
|
|
||||||
|
while (currentVersion++ < targetVersion)
|
||||||
|
{
|
||||||
|
switch (currentVersion)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
// cannot migrate; breaking underlying changes.
|
||||||
|
Reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a <see cref="BeatmapSetInfo"/> to the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSet">The beatmap to add.</param>
|
||||||
|
public void Add(BeatmapSetInfo beatmapSet)
|
||||||
|
{
|
||||||
|
Connection.RunInTransaction(() =>
|
||||||
|
{
|
||||||
|
Connection.InsertOrReplaceWithChildren(beatmapSet, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
BeatmapSetAdded?.Invoke(beatmapSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete a <see cref="BeatmapSetInfo"/> to the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||||
|
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
||||||
|
public bool Delete(BeatmapSetInfo beatmapSet)
|
||||||
|
{
|
||||||
|
if (beatmapSet.DeletePending) return false;
|
||||||
|
|
||||||
|
beatmapSet.DeletePending = true;
|
||||||
|
Connection.Update(beatmapSet);
|
||||||
|
|
||||||
|
BeatmapSetRemoved?.Invoke(beatmapSet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restore a previously deleted <see cref="BeatmapSetInfo"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmapSet">The beatmap to restore.</param>
|
||||||
|
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
||||||
|
public bool Undelete(BeatmapSetInfo beatmapSet)
|
||||||
|
{
|
||||||
|
if (!beatmapSet.DeletePending) return false;
|
||||||
|
|
||||||
|
beatmapSet.DeletePending = false;
|
||||||
|
Connection.Update(beatmapSet);
|
||||||
|
|
||||||
|
BeatmapSetAdded?.Invoke(beatmapSet);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanupPendingDeletions()
|
||||||
|
{
|
||||||
|
foreach (var b in QueryAndPopulate<BeatmapSetInfo>(b => b.DeletePending && !b.Protected))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// many-to-many join table entries are not automatically tidied.
|
||||||
|
Connection.Table<BeatmapSetFileInfo>().Delete(f => f.BeatmapSetInfoID == b.ID);
|
||||||
|
Connection.Delete(b, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, $@"Could not delete beatmap {b}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is required because sqlite migrations don't work, initially inserting nulls into this field.
|
||||||
|
//see https://github.com/praeclarum/sqlite-net/issues/326
|
||||||
|
Connection.Query<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
{
|
{
|
||||||
@ -59,10 +58,10 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapDatabase database)
|
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager)
|
||||||
{
|
{
|
||||||
BeatmapSet = beatmapSet;
|
BeatmapSet = beatmapSet;
|
||||||
WorkingBeatmap beatmap = database.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||||
|
|
||||||
Header = new BeatmapSetHeader(beatmap)
|
Header = new BeatmapSetHeader(beatmap)
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -34,7 +33,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
GainedSelection?.Invoke(this);
|
GainedSelection?.Invoke(this);
|
||||||
|
|
||||||
background.ColourInfo = ColourInfo.GradientVertical(
|
background.Colour = ColourInfo.GradientVertical(
|
||||||
new Color4(20, 43, 51, 255),
|
new Color4(20, 43, 51, 255),
|
||||||
new Color4(40, 86, 102, 255));
|
new Color4(40, 86, 102, 255));
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
new PanelBackground(beatmap)
|
new PanelBackground(beatmap)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
OnLoadComplete = d => d.FadeInFromZero(400, EasingTypes.Out),
|
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -119,21 +119,21 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColourInfo = ColourInfo.GradientHorizontal(
|
Colour = ColourInfo.GradientHorizontal(
|
||||||
Color4.Black, new Color4(0f, 0f, 0f, 0.9f)),
|
Color4.Black, new Color4(0f, 0f, 0f, 0.9f)),
|
||||||
Width = 0.05f,
|
Width = 0.05f,
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColourInfo = ColourInfo.GradientHorizontal(
|
Colour = ColourInfo.GradientHorizontal(
|
||||||
new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)),
|
new Color4(0f, 0f, 0f, 0.9f), new Color4(0f, 0f, 0f, 0.1f)),
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColourInfo = ColourInfo.GradientHorizontal(
|
Colour = ColourInfo.GradientHorizontal(
|
||||||
new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)),
|
new Color4(0f, 0f, 0f, 0.1f), new Color4(0, 0, 0, 0)),
|
||||||
Width = 0.05f,
|
Width = 0.05f,
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
@ -64,9 +64,9 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state == PanelSelectedState.Hidden)
|
if (state == PanelSelectedState.Hidden)
|
||||||
FadeOut(300, EasingTypes.OutQuint);
|
this.FadeOut(300, Easing.OutQuint);
|
||||||
else
|
else
|
||||||
FadeIn(250);
|
this.FadeIn(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PanelSelectedState state = PanelSelectedState.NotSelected;
|
private PanelSelectedState state = PanelSelectedState.NotSelected;
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
{
|
{
|
||||||
@ -13,6 +12,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
private static readonly Dictionary<string, Type> decoders = new Dictionary<string, Type>();
|
private static readonly Dictionary<string, Type> decoders = new Dictionary<string, Type>();
|
||||||
|
|
||||||
|
static BeatmapDecoder()
|
||||||
|
{
|
||||||
|
OsuLegacyDecoder.Register();
|
||||||
|
}
|
||||||
|
|
||||||
public static BeatmapDecoder GetDecoder(StreamReader stream)
|
public static BeatmapDecoder GetDecoder(StreamReader stream)
|
||||||
{
|
{
|
||||||
string line = stream.ReadLine()?.Trim();
|
string line = stream.ReadLine()?.Trim();
|
||||||
|
@ -5,45 +5,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Platform;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.IO
|
namespace osu.Game.Beatmaps.IO
|
||||||
{
|
{
|
||||||
public abstract class ArchiveReader : IDisposable, IResourceStore<byte[]>
|
public abstract class ArchiveReader : IDisposable, IResourceStore<byte[]>
|
||||||
{
|
{
|
||||||
private class Reader
|
|
||||||
{
|
|
||||||
public Func<Storage, string, bool> Test;
|
|
||||||
public Type Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly List<Reader> readers = new List<Reader>();
|
|
||||||
|
|
||||||
public static ArchiveReader GetReader(Storage storage, string path)
|
|
||||||
{
|
|
||||||
foreach (var reader in readers)
|
|
||||||
{
|
|
||||||
if (reader.Test(storage, path))
|
|
||||||
return (ArchiveReader)Activator.CreateInstance(reader.Type, storage.GetStream(path));
|
|
||||||
}
|
|
||||||
throw new IOException(@"Unknown file format");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static void AddReader<T>(Func<Storage, string, bool> test) where T : ArchiveReader
|
|
||||||
{
|
|
||||||
readers.Add(new Reader { Test = test, Type = typeof(T) });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of beatmap file names.
|
|
||||||
/// </summary>
|
|
||||||
public string[] BeatmapFilenames { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The storyboard filename. Null if no storyboard is present.
|
|
||||||
/// </summary>
|
|
||||||
public string StoryboardFilename { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens a stream for reading a specific file from this archive.
|
/// Opens a stream for reading a specific file from this archive.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -51,6 +17,8 @@ namespace osu.Game.Beatmaps.IO
|
|||||||
|
|
||||||
public abstract void Dispose();
|
public abstract void Dispose();
|
||||||
|
|
||||||
|
public abstract IEnumerable<string> Filenames { get; }
|
||||||
|
|
||||||
public virtual byte[] Get(string name)
|
public virtual byte[] Get(string name)
|
||||||
{
|
{
|
||||||
using (Stream input = GetStream(name))
|
using (Stream input = GetStream(name))
|
||||||
|
33
osu.Game/Beatmaps/IO/LegacyFilesystemReader.cs
Normal file
33
osu.Game/Beatmaps/IO/LegacyFilesystemReader.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.IO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an extracted legacy beatmap from disk.
|
||||||
|
/// </summary>
|
||||||
|
public class LegacyFilesystemReader : ArchiveReader
|
||||||
|
{
|
||||||
|
private readonly string path;
|
||||||
|
|
||||||
|
public LegacyFilesystemReader(string path)
|
||||||
|
{
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream GetStream(string name) => File.OpenRead(Path.Combine(path, name));
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> Filenames => Directory.GetFiles(path).Select(Path.GetFileName).ToArray();
|
||||||
|
|
||||||
|
public override Stream GetUnderlyingStream() => null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,15 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Ionic.Zip;
|
using Ionic.Zip;
|
||||||
using osu.Game.Beatmaps.Formats;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.IO
|
namespace osu.Game.Beatmaps.IO
|
||||||
{
|
{
|
||||||
public sealed class OszArchiveReader : ArchiveReader
|
public sealed class OszArchiveReader : ArchiveReader
|
||||||
{
|
{
|
||||||
public static void Register()
|
|
||||||
{
|
|
||||||
AddReader<OszArchiveReader>((storage, path) =>
|
|
||||||
{
|
|
||||||
using (var stream = storage.GetStream(path))
|
|
||||||
return stream != null && ZipFile.IsZipFile(stream, false);
|
|
||||||
});
|
|
||||||
OsuLegacyDecoder.Register();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Stream archiveStream;
|
private readonly Stream archiveStream;
|
||||||
private readonly ZipFile archive;
|
private readonly ZipFile archive;
|
||||||
|
|
||||||
@ -27,13 +17,6 @@ namespace osu.Game.Beatmaps.IO
|
|||||||
{
|
{
|
||||||
this.archiveStream = archiveStream;
|
this.archiveStream = archiveStream;
|
||||||
archive = ZipFile.Read(archiveStream);
|
archive = ZipFile.Read(archiveStream);
|
||||||
|
|
||||||
BeatmapFilenames = archive.Entries.Where(e => e.FileName.EndsWith(@".osu")).Select(e => e.FileName).ToArray();
|
|
||||||
|
|
||||||
if (BeatmapFilenames.Length == 0)
|
|
||||||
throw new FileNotFoundException(@"This directory contains no beatmaps");
|
|
||||||
|
|
||||||
StoryboardFilename = archive.Entries.Where(e => e.FileName.EndsWith(@".osb")).Select(e => e.FileName).FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Stream GetStream(string name)
|
public override Stream GetStream(string name)
|
||||||
@ -41,7 +24,16 @@ namespace osu.Game.Beatmaps.IO
|
|||||||
ZipEntry entry = archive.Entries.SingleOrDefault(e => e.FileName == name);
|
ZipEntry entry = archive.Entries.SingleOrDefault(e => e.FileName == name);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
return entry.OpenReader();
|
|
||||||
|
// allow seeking
|
||||||
|
MemoryStream copy = new MemoryStream();
|
||||||
|
|
||||||
|
using (Stream s = entry.OpenReader())
|
||||||
|
s.CopyTo(copy);
|
||||||
|
|
||||||
|
copy.Position = 0;
|
||||||
|
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
@ -50,6 +42,8 @@ namespace osu.Game.Beatmaps.IO
|
|||||||
archiveStream.Dispose();
|
archiveStream.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<string> Filenames => archive.Entries.Select(e => e.FileName).ToArray();
|
||||||
|
|
||||||
public override Stream GetUnderlyingStream() => archiveStream;
|
public override Stream GetUnderlyingStream() => archiveStream;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public enum RankStatus
|
public enum RankStatus
|
||||||
{
|
{
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -22,14 +21,11 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public readonly Bindable<IEnumerable<Mod>> Mods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
|
public readonly Bindable<IEnumerable<Mod>> Mods = new Bindable<IEnumerable<Mod>>(new Mod[] { });
|
||||||
|
|
||||||
public readonly bool WithStoryboard;
|
protected WorkingBeatmap(BeatmapInfo beatmapInfo)
|
||||||
|
|
||||||
protected WorkingBeatmap(BeatmapInfo beatmapInfo, bool withStoryboard = false)
|
|
||||||
{
|
{
|
||||||
BeatmapInfo = beatmapInfo;
|
BeatmapInfo = beatmapInfo;
|
||||||
BeatmapSetInfo = beatmapInfo.BeatmapSet;
|
BeatmapSetInfo = beatmapInfo.BeatmapSet;
|
||||||
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo.Metadata;
|
Metadata = beatmapInfo.Metadata ?? BeatmapSetInfo.Metadata;
|
||||||
WithStoryboard = withStoryboard;
|
|
||||||
|
|
||||||
Mods.ValueChanged += mods => applyRateAdjustments();
|
Mods.ValueChanged += mods => applyRateAdjustments();
|
||||||
}
|
}
|
||||||
|
@ -1,303 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Framework.Platform;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.Formats;
|
|
||||||
using osu.Game.Beatmaps.IO;
|
|
||||||
using osu.Game.IPC;
|
|
||||||
using osu.Game.Screens.Menu;
|
|
||||||
using SQLite.Net;
|
|
||||||
using SQLiteNetExtensions.Extensions;
|
|
||||||
|
|
||||||
namespace osu.Game.Database
|
|
||||||
{
|
|
||||||
public class BeatmapDatabase : Database
|
|
||||||
{
|
|
||||||
private readonly RulesetDatabase rulesets;
|
|
||||||
|
|
||||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
|
||||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
|
||||||
|
|
||||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
|
||||||
private BeatmapIPCChannel ipc;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
|
||||||
/// </summary>
|
|
||||||
public WorkingBeatmap DefaultBeatmap { private get; set; }
|
|
||||||
|
|
||||||
public BeatmapDatabase(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection)
|
|
||||||
{
|
|
||||||
this.rulesets = rulesets;
|
|
||||||
if (importHost != null)
|
|
||||||
ipc = new BeatmapIPCChannel(importHost, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deletePending()
|
|
||||||
{
|
|
||||||
foreach (var b in GetAllWithChildren<BeatmapSetInfo>(b => b.DeletePending))
|
|
||||||
{
|
|
||||||
if (b.Hash == Intro.MENU_MUSIC_BEATMAP_HASH)
|
|
||||||
// this is a bit hacky, but will do for now.
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Storage.Delete(b.Path);
|
|
||||||
|
|
||||||
foreach (var i in b.Beatmaps)
|
|
||||||
{
|
|
||||||
if (i.Metadata != null) Connection.Delete(i.Metadata);
|
|
||||||
if (i.Difficulty != null) Connection.Delete(i.Difficulty);
|
|
||||||
|
|
||||||
Connection.Delete(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b.Metadata != null) Connection.Delete(b.Metadata);
|
|
||||||
Connection.Delete(b);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error(e, $@"Could not delete beatmap {b}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//this is required because sqlite migrations don't work, initially inserting nulls into this field.
|
|
||||||
//see https://github.com/praeclarum/sqlite-net/issues/326
|
|
||||||
Connection.Query<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Prepare(bool reset = false)
|
|
||||||
{
|
|
||||||
Connection.CreateTable<BeatmapMetadata>();
|
|
||||||
Connection.CreateTable<BeatmapDifficulty>();
|
|
||||||
Connection.CreateTable<BeatmapSetInfo>();
|
|
||||||
Connection.CreateTable<BeatmapInfo>();
|
|
||||||
|
|
||||||
if (reset)
|
|
||||||
{
|
|
||||||
Storage.DeleteDatabase(@"beatmaps");
|
|
||||||
|
|
||||||
foreach (var setInfo in Query<BeatmapSetInfo>())
|
|
||||||
{
|
|
||||||
if (Storage.Exists(setInfo.Path))
|
|
||||||
Storage.Delete(setInfo.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection.DeleteAll<BeatmapMetadata>();
|
|
||||||
Connection.DeleteAll<BeatmapDifficulty>();
|
|
||||||
Connection.DeleteAll<BeatmapSetInfo>();
|
|
||||||
Connection.DeleteAll<BeatmapInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
deletePending();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Type[] ValidTypes => new[] {
|
|
||||||
typeof(BeatmapSetInfo),
|
|
||||||
typeof(BeatmapInfo),
|
|
||||||
typeof(BeatmapMetadata),
|
|
||||||
typeof(BeatmapDifficulty),
|
|
||||||
};
|
|
||||||
|
|
||||||
public void Import(string path)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Import(ArchiveReader.GetReader(Storage, path));
|
|
||||||
|
|
||||||
// We may or may not want to delete the file depending on where it is stored.
|
|
||||||
// e.g. reconstructing/repairing database with beatmaps from default storage.
|
|
||||||
// Also, not always a single file, i.e. for LegacyFilesystemReader
|
|
||||||
// TODO: Add a check to prevent files from storage to be deleted.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(path);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error(e, $@"Could not delete file at {path}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e = e.InnerException ?? e;
|
|
||||||
Logger.Error(e, @"Could not import beatmap set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Import(ArchiveReader archiveReader)
|
|
||||||
{
|
|
||||||
BeatmapSetInfo set = getBeatmapSet(archiveReader);
|
|
||||||
|
|
||||||
//If we have an ID then we already exist in the database.
|
|
||||||
if (set.ID == 0)
|
|
||||||
Import(new[] { set });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Import multiple <see cref="BeatmapSetInfo"/> from <paramref name="paths"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="paths">Multiple locations on disk</param>
|
|
||||||
public void Import(params string[] paths)
|
|
||||||
{
|
|
||||||
foreach (string p in paths)
|
|
||||||
{
|
|
||||||
//In case the file was imported twice and deleted after the first time
|
|
||||||
if (File.Exists(p))
|
|
||||||
Import(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Duplicates content from <paramref name="path"/> to storage and returns a representing <see cref="BeatmapSetInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">Content location</param>
|
|
||||||
/// <returns><see cref="BeatmapSetInfo"/></returns>
|
|
||||||
private BeatmapSetInfo getBeatmapSet(string path) => getBeatmapSet(ArchiveReader.GetReader(Storage, path));
|
|
||||||
|
|
||||||
private BeatmapSetInfo getBeatmapSet(ArchiveReader archiveReader)
|
|
||||||
{
|
|
||||||
BeatmapMetadata metadata;
|
|
||||||
|
|
||||||
using (var stream = new StreamReader(archiveReader.GetStream(archiveReader.BeatmapFilenames[0])))
|
|
||||||
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
|
||||||
|
|
||||||
string hash;
|
|
||||||
string path;
|
|
||||||
|
|
||||||
using (var input = archiveReader.GetUnderlyingStream())
|
|
||||||
{
|
|
||||||
hash = input.GetMd5Hash();
|
|
||||||
input.Seek(0, SeekOrigin.Begin);
|
|
||||||
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
|
|
||||||
if (!Storage.Exists(path))
|
|
||||||
using (var output = Storage.GetStream(path, FileAccess.Write))
|
|
||||||
input.CopyTo(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
var existing = Connection.Table<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
|
||||||
|
|
||||||
if (existing != null)
|
|
||||||
{
|
|
||||||
GetChildren(existing);
|
|
||||||
|
|
||||||
if (existing.DeletePending)
|
|
||||||
{
|
|
||||||
existing.DeletePending = false;
|
|
||||||
Update(existing, false);
|
|
||||||
BeatmapSetAdded?.Invoke(existing);
|
|
||||||
}
|
|
||||||
|
|
||||||
return existing;
|
|
||||||
}
|
|
||||||
|
|
||||||
var beatmapSet = new BeatmapSetInfo
|
|
||||||
{
|
|
||||||
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
|
||||||
Beatmaps = new List<BeatmapInfo>(),
|
|
||||||
Path = path,
|
|
||||||
Hash = hash,
|
|
||||||
Metadata = metadata
|
|
||||||
};
|
|
||||||
|
|
||||||
using (var archive = ArchiveReader.GetReader(Storage, path))
|
|
||||||
{
|
|
||||||
string[] mapNames = archive.BeatmapFilenames;
|
|
||||||
foreach (var name in mapNames)
|
|
||||||
using (var raw = archive.GetStream(name))
|
|
||||||
using (var ms = new MemoryStream()) //we need a memory stream so we can seek and shit
|
|
||||||
using (var sr = new StreamReader(ms))
|
|
||||||
{
|
|
||||||
raw.CopyTo(ms);
|
|
||||||
ms.Position = 0;
|
|
||||||
|
|
||||||
var decoder = BeatmapDecoder.GetDecoder(sr);
|
|
||||||
Beatmap beatmap = decoder.Decode(sr);
|
|
||||||
|
|
||||||
beatmap.BeatmapInfo.Path = name;
|
|
||||||
beatmap.BeatmapInfo.Hash = ms.GetMd5Hash();
|
|
||||||
|
|
||||||
// TODO: Diff beatmap metadata with set metadata and leave it here if necessary
|
|
||||||
beatmap.BeatmapInfo.Metadata = null;
|
|
||||||
|
|
||||||
// TODO: this should be done in a better place once we actually need to dynamically update it.
|
|
||||||
beatmap.BeatmapInfo.Ruleset = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID);
|
|
||||||
beatmap.BeatmapInfo.StarDifficulty = rulesets.Query<RulesetInfo>().FirstOrDefault(r => r.ID == beatmap.BeatmapInfo.RulesetID)?.CreateInstance()?.CreateDifficultyCalculator(beatmap).Calculate() ?? 0;
|
|
||||||
|
|
||||||
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
|
|
||||||
}
|
|
||||||
beatmapSet.StoryboardFile = archive.StoryboardFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
return beatmapSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Import(IEnumerable<BeatmapSetInfo> beatmapSets)
|
|
||||||
{
|
|
||||||
lock (Connection)
|
|
||||||
{
|
|
||||||
Connection.BeginTransaction();
|
|
||||||
|
|
||||||
foreach (var s in beatmapSets)
|
|
||||||
{
|
|
||||||
Connection.InsertOrReplaceWithChildren(s, true);
|
|
||||||
BeatmapSetAdded?.Invoke(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
Connection.Commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete(BeatmapSetInfo beatmapSet)
|
|
||||||
{
|
|
||||||
beatmapSet.DeletePending = true;
|
|
||||||
Update(beatmapSet, false);
|
|
||||||
|
|
||||||
BeatmapSetRemoved?.Invoke(beatmapSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArchiveReader GetReader(BeatmapSetInfo beatmapSet)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(beatmapSet.Path))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return ArchiveReader.GetReader(Storage, beatmapSet.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeatmapSetInfo GetBeatmapSet(int id)
|
|
||||||
{
|
|
||||||
return Query<BeatmapSetInfo>().FirstOrDefault(s => s.OnlineBeatmapSetID == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false)
|
|
||||||
{
|
|
||||||
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
|
|
||||||
return DefaultBeatmap;
|
|
||||||
|
|
||||||
if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null)
|
|
||||||
beatmapInfo = GetChildren(beatmapInfo, true);
|
|
||||||
|
|
||||||
if (beatmapInfo.BeatmapSet == null)
|
|
||||||
throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database.");
|
|
||||||
|
|
||||||
if (beatmapInfo.Metadata == null)
|
|
||||||
beatmapInfo.Metadata = beatmapInfo.BeatmapSet.Metadata;
|
|
||||||
|
|
||||||
WorkingBeatmap working = new DatabaseWorkingBeatmap(this, beatmapInfo, withStoryboard);
|
|
||||||
|
|
||||||
previous?.TransferTo(working);
|
|
||||||
|
|
||||||
return working;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Exists(BeatmapSetInfo beatmapSet) => Storage.Exists(beatmapSet.Path);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Framework.Platform;
|
|
||||||
using SQLite.Net;
|
|
||||||
using SQLiteNetExtensions.Extensions;
|
|
||||||
|
|
||||||
namespace osu.Game.Database
|
|
||||||
{
|
|
||||||
public abstract class Database
|
|
||||||
{
|
|
||||||
protected SQLiteConnection Connection { get; }
|
|
||||||
protected Storage Storage { get; }
|
|
||||||
|
|
||||||
protected Database(Storage storage, SQLiteConnection connection)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
Connection = connection;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Prepare();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
|
|
||||||
Prepare(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepare this database for use.
|
|
||||||
/// </summary>
|
|
||||||
protected abstract void Prepare(bool reset = false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reset this database to a default state. Undo all changes to database and storage backings.
|
|
||||||
/// </summary>
|
|
||||||
public void Reset() => Prepare(true);
|
|
||||||
|
|
||||||
public TableQuery<T> Query<T>() where T : class
|
|
||||||
{
|
|
||||||
return Connection.Table<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This is expensive. Use with caution.
|
|
||||||
/// </summary>
|
|
||||||
public List<T> GetAllWithChildren<T>(Expression<Func<T, bool>> filter = null, bool recursive = true)
|
|
||||||
where T : class
|
|
||||||
{
|
|
||||||
return Connection.GetAllWithChildren(filter, recursive);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetChildren<T>(T item, bool recursive = false)
|
|
||||||
{
|
|
||||||
if (item == null) return default(T);
|
|
||||||
|
|
||||||
Connection.GetChildren(item, recursive);
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract Type[] ValidTypes { get; }
|
|
||||||
|
|
||||||
public void Update<T>(T record, bool cascade = true) where T : class
|
|
||||||
{
|
|
||||||
if (ValidTypes.All(t => t != typeof(T)))
|
|
||||||
throw new ArgumentException("Must be a type managed by BeatmapDatabase", nameof(T));
|
|
||||||
if (cascade)
|
|
||||||
Connection.UpdateWithChildren(record);
|
|
||||||
else
|
|
||||||
Connection.Update(record);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
131
osu.Game/Database/DatabaseBackedStore.cs
Normal file
131
osu.Game/Database/DatabaseBackedStore.cs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using osu.Framework.Logging;
|
||||||
|
using osu.Framework.Platform;
|
||||||
|
using SQLite.Net;
|
||||||
|
using SQLiteNetExtensions.Extensions;
|
||||||
|
|
||||||
|
namespace osu.Game.Database
|
||||||
|
{
|
||||||
|
public abstract class DatabaseBackedStore
|
||||||
|
{
|
||||||
|
protected readonly Storage Storage;
|
||||||
|
protected readonly SQLiteConnection Connection;
|
||||||
|
|
||||||
|
protected virtual int StoreVersion => 1;
|
||||||
|
|
||||||
|
protected DatabaseBackedStore(SQLiteConnection connection, Storage storage = null)
|
||||||
|
{
|
||||||
|
Storage = storage;
|
||||||
|
Connection = connection;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Prepare();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
|
||||||
|
Prepare(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkMigrations();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkMigrations()
|
||||||
|
{
|
||||||
|
var storeName = GetType().Name;
|
||||||
|
|
||||||
|
var reportedVersion = Connection.Table<StoreVersion>().FirstOrDefault(s => s.StoreName == storeName) ?? new StoreVersion
|
||||||
|
{
|
||||||
|
StoreName = storeName,
|
||||||
|
Version = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (reportedVersion.Version != StoreVersion)
|
||||||
|
PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion);
|
||||||
|
|
||||||
|
Connection.InsertOrReplace(reportedVersion);
|
||||||
|
|
||||||
|
StartupTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the database version of this store doesn't match the local version.
|
||||||
|
/// Any manual migration operations should be performed in this.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
|
||||||
|
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
|
||||||
|
protected virtual void PerformMigration(int currentVersion, int targetVersion)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform any common startup tasks. Runs after <see cref="Prepare(bool)"/> and <see cref="PerformMigration(int, int)"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void StartupTasks()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prepare this database for use. Tables should be created here.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract void Prepare(bool reset = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset this database to a default state. Undo all changes to database and storage backings.
|
||||||
|
/// </summary>
|
||||||
|
public void Reset() => Prepare(true);
|
||||||
|
|
||||||
|
|
||||||
|
public TableQuery<T> Query<T>(Expression<Func<T, bool>> filter = null) where T : class
|
||||||
|
{
|
||||||
|
checkType(typeof(T));
|
||||||
|
|
||||||
|
var query = Connection.Table<T>();
|
||||||
|
|
||||||
|
if (filter != null)
|
||||||
|
query = query.Where(filter);
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Query and populate results.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">An filter to refine results.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<T> QueryAndPopulate<T>(Expression<Func<T, bool>> filter)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
checkType(typeof(T));
|
||||||
|
|
||||||
|
return Connection.GetAllWithChildren(filter, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Populate a database-backed item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <param name="recursive">Whether population should recurse beyond a single level.</param>
|
||||||
|
public void Populate<T>(T item, bool recursive = true)
|
||||||
|
{
|
||||||
|
checkType(item.GetType());
|
||||||
|
Connection.GetChildren(item, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkType(Type type)
|
||||||
|
{
|
||||||
|
if (!ValidTypes.Contains(type))
|
||||||
|
throw new InvalidOperationException($"The requested operation specified a type of {type}, which is invalid for this {nameof(DatabaseBackedStore)}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Type[] ValidTypes { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,75 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.Formats;
|
|
||||||
using osu.Game.Beatmaps.IO;
|
|
||||||
|
|
||||||
namespace osu.Game.Database
|
|
||||||
{
|
|
||||||
internal class DatabaseWorkingBeatmap : WorkingBeatmap
|
|
||||||
{
|
|
||||||
private readonly BeatmapDatabase database;
|
|
||||||
|
|
||||||
public DatabaseWorkingBeatmap(BeatmapDatabase database, BeatmapInfo beatmapInfo, bool withStoryboard = false)
|
|
||||||
: base(beatmapInfo, withStoryboard)
|
|
||||||
{
|
|
||||||
this.database = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArchiveReader getReader() => database?.GetReader(BeatmapSetInfo);
|
|
||||||
|
|
||||||
protected override Beatmap GetBeatmap()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Beatmap beatmap;
|
|
||||||
|
|
||||||
using (var reader = getReader())
|
|
||||||
{
|
|
||||||
BeatmapDecoder decoder;
|
|
||||||
using (var stream = new StreamReader(reader.GetStream(BeatmapInfo.Path)))
|
|
||||||
{
|
|
||||||
decoder = BeatmapDecoder.GetDecoder(stream);
|
|
||||||
beatmap = decoder.Decode(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beatmap == null || !WithStoryboard || BeatmapSetInfo.StoryboardFile == null)
|
|
||||||
return beatmap;
|
|
||||||
|
|
||||||
using (var stream = new StreamReader(reader.GetStream(BeatmapSetInfo.StoryboardFile)))
|
|
||||||
decoder.Decode(stream, beatmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
return beatmap;
|
|
||||||
}
|
|
||||||
catch { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Texture GetBackground()
|
|
||||||
{
|
|
||||||
if (Metadata?.BackgroundFile == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var reader = getReader())
|
|
||||||
return new TextureStore(new RawTextureLoaderStore(reader), false).Get(Metadata.BackgroundFile);
|
|
||||||
}
|
|
||||||
catch { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Track GetTrack()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var trackData = getReader()?.GetStream(Metadata.AudioFile);
|
|
||||||
return trackData == null ? null : new TrackBass(trackData);
|
|
||||||
}
|
|
||||||
catch { return new TrackVirtual(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
15
osu.Game/Database/StoreVersion.cs
Normal file
15
osu.Game/Database/StoreVersion.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using SQLite.Net.Attributes;
|
||||||
|
|
||||||
|
namespace osu.Game.Database
|
||||||
|
{
|
||||||
|
public class StoreVersion
|
||||||
|
{
|
||||||
|
[PrimaryKey]
|
||||||
|
public string StoreName { get; set; }
|
||||||
|
|
||||||
|
public int Version { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
if (!parallaxEnabled)
|
if (!parallaxEnabled)
|
||||||
{
|
{
|
||||||
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
|
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint);
|
||||||
content.Scale = new Vector2(1 + ParallaxAmount);
|
content.Scale = new Vector2(1 + ParallaxAmount);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
if (parallaxEnabled)
|
if (parallaxEnabled)
|
||||||
{
|
{
|
||||||
Vector2 offset = input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2;
|
Vector2 offset = input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2;
|
||||||
content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, EasingTypes.OutQuint);
|
content.MoveTo(offset * ParallaxAmount, firstUpdate ? 0 : 1000, Easing.OutQuint);
|
||||||
content.Scale = new Vector2(1 + ParallaxAmount);
|
content.Scale = new Vector2(1 + ParallaxAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Cursor
|
namespace osu.Game.Graphics.Cursor
|
||||||
{
|
{
|
||||||
@ -29,14 +28,14 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
{
|
{
|
||||||
ActiveCursor.Scale = new Vector2(1);
|
ActiveCursor.Scale = new Vector2(1);
|
||||||
ActiveCursor.ScaleTo(1.2f, 100, EasingTypes.OutQuad);
|
ActiveCursor.ScaleTo(1.2f, 100, Easing.OutQuad);
|
||||||
return base.OnMouseDown(state, args);
|
return base.OnMouseDown(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||||
{
|
{
|
||||||
if (!state.Mouse.HasMainButtonPressed)
|
if (!state.Mouse.HasMainButtonPressed)
|
||||||
ActiveCursor.ScaleTo(1, 200, EasingTypes.OutQuad);
|
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
|
||||||
return base.OnMouseUp(state, args);
|
return base.OnMouseUp(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
if (diff > 180) diff -= 360;
|
if (diff > 180) diff -= 360;
|
||||||
degrees = ActiveCursor.Rotation + diff;
|
degrees = ActiveCursor.Rotation + diff;
|
||||||
|
|
||||||
ActiveCursor.RotateTo(degrees, 600, EasingTypes.OutQuint);
|
ActiveCursor.RotateTo(degrees, 600, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseMove(state);
|
return base.OnMouseMove(state);
|
||||||
@ -49,10 +49,10 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
{
|
{
|
||||||
ActiveCursor.Scale = new Vector2(1);
|
ActiveCursor.Scale = new Vector2(1);
|
||||||
ActiveCursor.ScaleTo(0.90f, 800, EasingTypes.OutQuint);
|
ActiveCursor.ScaleTo(0.90f, 800, Easing.OutQuint);
|
||||||
|
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
|
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, EasingTypes.OutQuint);
|
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
|
||||||
return base.OnMouseDown(state, args);
|
return base.OnMouseDown(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,9 +62,9 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
{
|
{
|
||||||
dragging = false;
|
dragging = false;
|
||||||
|
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, EasingTypes.OutQuint);
|
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
|
||||||
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), EasingTypes.OutElasticHalf);
|
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
|
||||||
ActiveCursor.ScaleTo(1, 500, EasingTypes.OutElastic);
|
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseUp(state, args);
|
return base.OnMouseUp(state, args);
|
||||||
@ -72,21 +72,21 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
|
|
||||||
protected override bool OnClick(InputState state)
|
protected override bool OnClick(InputState state)
|
||||||
{
|
{
|
||||||
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, EasingTypes.OutQuint);
|
((Cursor)ActiveCursor).AdditiveLayer.FadeOutFromOne(500, Easing.OutQuint);
|
||||||
|
|
||||||
return base.OnClick(state);
|
return base.OnClick(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
ActiveCursor.FadeTo(1, 250, EasingTypes.OutQuint);
|
ActiveCursor.FadeTo(1, 250, Easing.OutQuint);
|
||||||
ActiveCursor.ScaleTo(1, 400, EasingTypes.OutQuint);
|
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut()
|
||||||
{
|
{
|
||||||
ActiveCursor.FadeTo(0, 900, EasingTypes.OutQuint);
|
ActiveCursor.FadeTo(0, 900, Easing.OutQuint);
|
||||||
ActiveCursor.ScaleTo(0, 500, EasingTypes.In);
|
ActiveCursor.ScaleTo(0, 500, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Cursor : Container
|
public class Cursor : Container
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
if (IsPresent)
|
if (IsPresent)
|
||||||
{
|
{
|
||||||
AutoSizeDuration = 250;
|
AutoSizeDuration = 250;
|
||||||
background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
|
background.FlashColour(OsuColour.Gray(0.4f), 1000, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
AutoSizeDuration = 0;
|
AutoSizeDuration = 0;
|
||||||
@ -48,7 +48,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
|
|
||||||
public OsuTooltip()
|
public OsuTooltip()
|
||||||
{
|
{
|
||||||
AutoSizeEasing = EasingTypes.OutQuint;
|
AutoSizeEasing = Easing.OutQuint;
|
||||||
|
|
||||||
CornerRadius = 5;
|
CornerRadius = 5;
|
||||||
Masking = true;
|
Masking = true;
|
||||||
@ -83,16 +83,10 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
protected override void PopIn()
|
protected override void PopIn()
|
||||||
{
|
{
|
||||||
instantMovement |= !IsPresent;
|
instantMovement |= !IsPresent;
|
||||||
|
this.FadeIn(500, Easing.OutQuint);
|
||||||
ClearTransforms();
|
|
||||||
FadeIn(500, EasingTypes.OutQuint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PopOut()
|
protected override void PopOut() => this.Delay(150).FadeOut(500, Easing.OutQuint);
|
||||||
{
|
|
||||||
using (BeginDelayedSequence(150))
|
|
||||||
FadeOut(500, EasingTypes.OutQuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Move(Vector2 pos)
|
public override void Move(Vector2 pos)
|
||||||
{
|
{
|
||||||
@ -103,7 +97,7 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MoveTo(pos, 200, EasingTypes.OutQuint);
|
this.MoveTo(pos, 200, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Game.Graphics.Transforms;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics
|
namespace osu.Game.Graphics
|
||||||
{
|
{
|
||||||
@ -27,10 +26,8 @@ namespace osu.Game.Graphics
|
|||||||
/// <param name="newColour">The new accent colour.</param>
|
/// <param name="newColour">The new accent colour.</param>
|
||||||
/// <param name="duration">The tween duration.</param>
|
/// <param name="duration">The tween duration.</param>
|
||||||
/// <param name="easing">The tween easing.</param>
|
/// <param name="easing">The tween easing.</param>
|
||||||
public static void FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, EasingTypes easing = EasingTypes.None)
|
public static TransformSequence<T> FadeAccent<T>(this T accentedDrawable, Color4 newColour, double duration = 0, Easing easing = Easing.None)
|
||||||
where T : Transformable<Drawable>, IHasAccentColour
|
where T : IHasAccentColour
|
||||||
{
|
=> accentedDrawable.TransformTo(nameof(accentedDrawable.AccentColour), newColour, duration, easing);
|
||||||
accentedDrawable.TransformTo(newColour, duration, easing, new TransformAccent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
public static Color4 FromHex(string hex)
|
public static Color4 FromHex(string hex)
|
||||||
{
|
{
|
||||||
|
if (hex[0] == '#')
|
||||||
|
hex = hex.Substring(1);
|
||||||
|
|
||||||
switch (hex.Length)
|
switch (hex.Length)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Transforms;
|
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Transforms
|
|
||||||
{
|
|
||||||
public class TransformAccent : Transform<Color4, Drawable>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Current value of the transformed colour in linear colour space.
|
|
||||||
/// </summary>
|
|
||||||
public virtual Color4 CurrentValue
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double time = Time?.Current ?? 0;
|
|
||||||
if (time < StartTime) return StartValue;
|
|
||||||
if (time >= EndTime) return EndValue;
|
|
||||||
|
|
||||||
return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Apply(Drawable d) => ((IHasAccentColour)d).AccentColour = CurrentValue;
|
|
||||||
public override void ReadIntoStartValue(Drawable d) => StartValue = ((IHasAccentColour)d).AccentColour;
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user