1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-15 18:52:55 +08:00

Merge branch 'master' into editor-clock-transform

This commit is contained in:
smoogipoo 2020-05-25 19:01:04 +09:00
commit ebe2e97372
10 changed files with 104 additions and 42 deletions

View File

@ -8,7 +8,7 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
using osu.Game.IO; using osu.Game.IO;
using osu.Game.IO.Archives; using osu.Game.IO.Archives;
using osu.Game.Resources; using osu.Game.Tests.Resources;
namespace osu.Game.Benchmarks namespace osu.Game.Benchmarks
{ {
@ -18,8 +18,8 @@ namespace osu.Game.Benchmarks
public override void SetUp() public override void SetUp()
{ {
using (var resources = new DllResourceStore(OsuResources.ResourceAssembly)) using (var resources = new DllResourceStore(typeof(TestResources).Assembly))
using (var archive = resources.GetStream("Beatmaps/241526 Soleily - Renatus.osz")) using (var archive = resources.GetStream("Resources/Archives/241526 Soleily - Renatus.osz"))
using (var reader = new ZipArchiveReader(archive)) using (var reader = new ZipArchiveReader(archive))
reader.GetStream("Soleily - Renatus (Gamu) [Insane].osu").CopyTo(beatmapStream); reader.GetStream("Soleily - Renatus (Gamu) [Insane].osu").CopyTo(beatmapStream);
} }

View File

@ -13,6 +13,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
<ProjectReference Include="..\osu.Game\osu.Game.csproj" /> <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
</ItemGroup> </ItemGroup>

View File

@ -40,10 +40,10 @@ namespace osu.Game.Rulesets.Osu.Edit
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
LayerBelowRuleset.Add(distanceSnapGridContainer = new Container { RelativeSizeAxes = Axes.Both });
EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid(); EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid();
EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid(); EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid();
LayerBelowRuleset.Add(distanceSnapGridContainer = new Container { RelativeSizeAxes = Axes.Both });
} }
protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(HitObjects); protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(HitObjects);
@ -86,10 +86,24 @@ namespace osu.Game.Rulesets.Osu.Edit
distanceSnapGridContainer.Clear(); distanceSnapGridContainer.Clear();
distanceSnapGridCache.Invalidate(); distanceSnapGridCache.Invalidate();
if (BlueprintContainer.CurrentTool is SelectTool && !EditorBeatmap.SelectedHitObjects.Any()) switch (BlueprintContainer.CurrentTool)
return; {
case SelectTool _:
if (!EditorBeatmap.SelectedHitObjects.Any())
return;
if ((distanceSnapGrid = createDistanceSnapGrid(EditorBeatmap.SelectedHitObjects)) != null) distanceSnapGrid = createDistanceSnapGrid(EditorBeatmap.SelectedHitObjects);
break;
default:
if (!CursorInPlacementArea)
return;
distanceSnapGrid = createDistanceSnapGrid(Enumerable.Empty<HitObject>());
break;
}
if (distanceSnapGrid != null)
{ {
distanceSnapGridContainer.Add(distanceSnapGrid); distanceSnapGridContainer.Add(distanceSnapGrid);
distanceSnapGridCache.Validate(); distanceSnapGridCache.Validate();

View File

@ -27,7 +27,6 @@ using osu.Game.Online.API.Requests;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using Decoder = osu.Game.Beatmaps.Formats.Decoder; using Decoder = osu.Game.Beatmaps.Formats.Decoder;
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
@ -66,7 +65,6 @@ namespace osu.Game.Beatmaps
private readonly AudioManager audioManager; private readonly AudioManager audioManager;
private readonly GameHost host; private readonly GameHost host;
private readonly BeatmapOnlineLookupQueue onlineLookupQueue; private readonly BeatmapOnlineLookupQueue onlineLookupQueue;
private readonly Storage exportStorage;
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, AudioManager audioManager, GameHost host = null, public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, AudioManager audioManager, GameHost host = null,
WorkingBeatmap defaultBeatmap = null) WorkingBeatmap defaultBeatmap = null)
@ -83,7 +81,6 @@ namespace osu.Game.Beatmaps
beatmaps.BeatmapRestored += b => beatmapRestored.Value = new WeakReference<BeatmapInfo>(b); beatmaps.BeatmapRestored += b => beatmapRestored.Value = new WeakReference<BeatmapInfo>(b);
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage); onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
exportStorage = storage.GetStorageForDirectory("exports");
} }
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) => protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
@ -214,26 +211,6 @@ namespace osu.Game.Beatmaps
workingCache.Remove(working); workingCache.Remove(working);
} }
/// <summary>
/// Exports a <see cref="BeatmapSetInfo"/> to an .osz package.
/// </summary>
/// <param name="set">The <see cref="BeatmapSetInfo"/> to export.</param>
public void Export(BeatmapSetInfo set)
{
var localSet = QueryBeatmapSet(s => s.ID == set.ID);
using (var archive = ZipArchive.Create())
{
foreach (var file in localSet.Files)
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
using (var outputStream = exportStorage.GetStream($"{set}.osz", FileAccess.Write, FileMode.Create))
archive.SaveTo(outputStream);
exportStorage.OpenInNativeExplorer();
}
}
private readonly WeakList<WorkingBeatmap> workingCache = new WeakList<WorkingBeatmap>(); private readonly WeakList<WorkingBeatmap> workingCache = new WeakList<WorkingBeatmap>();
/// <summary> /// <summary>

View File

@ -22,6 +22,7 @@ using osu.Game.IO.Archives;
using osu.Game.IPC; using osu.Game.IPC;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Utils; using osu.Game.Utils;
using SharpCompress.Archives.Zip;
using SharpCompress.Common; using SharpCompress.Common;
using FileInfo = osu.Game.IO.FileInfo; using FileInfo = osu.Game.IO.FileInfo;
@ -82,6 +83,8 @@ namespace osu.Game.Database
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private ArchiveImportIPCChannel ipc; private ArchiveImportIPCChannel ipc;
private readonly Storage exportStorage;
protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore, IIpcHost importHost = null) protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore, IIpcHost importHost = null)
{ {
ContextFactory = contextFactory; ContextFactory = contextFactory;
@ -90,6 +93,8 @@ namespace osu.Game.Database
ModelStore.ItemAdded += item => handleEvent(() => itemAdded.Value = new WeakReference<TModel>(item)); ModelStore.ItemAdded += item => handleEvent(() => itemAdded.Value = new WeakReference<TModel>(item));
ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference<TModel>(item)); ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference<TModel>(item));
exportStorage = storage.GetStorageForDirectory("exports");
Files = new FileStore(contextFactory, storage); Files = new FileStore(contextFactory, storage);
if (importHost != null) if (importHost != null)
@ -369,6 +374,29 @@ namespace osu.Game.Database
return item; return item;
}, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap(); }, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap();
/// <summary>
/// Exports an item to a legacy (.zip based) package.
/// </summary>
/// <param name="item">The item to export.</param>
public void Export(TModel item)
{
var retrievedItem = ModelStore.ConsumableItems.FirstOrDefault(s => s.ID == item.ID);
if (retrievedItem == null)
throw new ArgumentException("Specified model could not be found", nameof(item));
using (var archive = ZipArchive.Create())
{
foreach (var file in retrievedItem.Files)
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
using (var outputStream = exportStorage.GetStream($"{getValidFilename(item.ToString())}{HandledExtensions.First()}", FileAccess.Write, FileMode.Create))
archive.SaveTo(outputStream);
exportStorage.OpenInNativeExplorer();
}
}
public void UpdateFile(TModel model, TFileModel file, Stream contents) public void UpdateFile(TModel model, TFileModel file, Stream contents)
{ {
using (var usage = ContextFactory.GetForWrite()) using (var usage = ContextFactory.GetForWrite())
@ -710,5 +738,12 @@ namespace osu.Game.Database
} }
#endregion #endregion
private string getValidFilename(string filename)
{
foreach (char c in Path.GetInvalidFileNameChars())
filename = filename.Replace(c, '_');
return filename;
}
} }
} }

View File

@ -7,6 +7,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Logging;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Skinning; using osu.Game.Skinning;
@ -38,9 +39,11 @@ namespace osu.Game.Overlays.Settings.Sections
private void load(OsuConfigManager config) private void load(OsuConfigManager config)
{ {
FlowContent.Spacing = new Vector2(0, 5); FlowContent.Spacing = new Vector2(0, 5);
Children = new Drawable[] Children = new Drawable[]
{ {
skinDropdown = new SkinSettingsDropdown(), skinDropdown = new SkinSettingsDropdown(),
new ExportSkinButton(),
new SettingsSlider<float, SizeSlider> new SettingsSlider<float, SizeSlider>
{ {
LabelText = "Menu cursor size", LabelText = "Menu cursor size",
@ -117,5 +120,35 @@ namespace osu.Game.Overlays.Settings.Sections
protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 200); protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 200);
} }
} }
private class ExportSkinButton : SettingsButton
{
[Resolved]
private SkinManager skins { get; set; }
private Bindable<Skin> currentSkin;
[BackgroundDependencyLoader]
private void load()
{
Text = "Export selected skin";
Action = export;
currentSkin = skins.CurrentSkin.GetBoundCopy();
currentSkin.BindValueChanged(skin => Enabled.Value = skin.NewValue.SkinInfo.ID > 0, true);
}
private void export()
{
try
{
skins.Export(currentSkin.Value.SkinInfo);
}
catch (Exception e)
{
Logger.Log($"Could not export current skin: {e.Message}", level: LogLevel.Error);
}
}
}
} }
} }

View File

@ -30,11 +30,13 @@ namespace osu.Game.Rulesets.Edit
/// </summary> /// </summary>
protected readonly HitObject HitObject; protected readonly HitObject HitObject;
[Resolved] [Resolved(canBeNull: true)]
protected EditorClock EditorClock { get; private set; } protected EditorClock EditorClock { get; private set; }
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>(); private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
private Bindable<double> startTimeBindable;
[Resolved] [Resolved]
private IPlacementHandler placementHandler { get; set; } private IPlacementHandler placementHandler { get; set; }
@ -54,7 +56,8 @@ namespace osu.Game.Rulesets.Edit
{ {
this.beatmap.BindTo(beatmap); this.beatmap.BindTo(beatmap);
ApplyDefaultsToHitObject(); startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy();
startTimeBindable.BindValueChanged(_ => ApplyDefaultsToHitObject(), true);
} }
/// <summary> /// <summary>
@ -80,9 +83,6 @@ namespace osu.Game.Rulesets.Edit
PlacementActive = false; PlacementActive = false;
} }
[Resolved(canBeNull: true)]
private EditorClock editorClock { get; set; }
/// <summary> /// <summary>
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position. /// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
/// </summary> /// </summary>
@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Edit
public virtual void UpdatePosition(SnapResult snapResult) public virtual void UpdatePosition(SnapResult snapResult)
{ {
if (!PlacementActive) if (!PlacementActive)
HitObject.StartTime = snapResult.Time ?? editorClock?.CurrentTime ?? Time.Current; HitObject.StartTime = snapResult.Time ?? EditorClock?.CurrentTime ?? Time.Current;
} }
/// <summary> /// <summary>

View File

@ -24,8 +24,6 @@ namespace osu.Game.Skinning
public bool DeletePending { get; set; } public bool DeletePending { get; set; }
public string FullName => $"\"{Name}\" by {Creator}";
public static SkinInfo Default { get; } = new SkinInfo public static SkinInfo Default { get; } = new SkinInfo
{ {
Name = "osu!lazer", Name = "osu!lazer",
@ -34,6 +32,10 @@ namespace osu.Game.Skinning
public bool Equals(SkinInfo other) => other != null && ID == other.ID; public bool Equals(SkinInfo other) => other != null && ID == other.ID;
public override string ToString() => FullName; public override string ToString()
{
string author = Creator == null ? string.Empty : $"({Creator})";
return $"{Name} {author}".Trim();
}
} }
} }

View File

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="Dapper" Version="2.0.35" /> <PackageReference Include="Dapper" Version="2.0.35" />
<PackageReference Include="DiffPlex" Version="1.6.1" /> <PackageReference Include="DiffPlex" Version="1.6.2" />
<PackageReference Include="Humanizer" Version="2.8.11" /> <PackageReference Include="Humanizer" Version="2.8.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />

View File

@ -75,7 +75,7 @@
</ItemGroup> </ItemGroup>
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. --> <!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
<PackageReference Include="DiffPlex" Version="1.6.1" /> <PackageReference Include="DiffPlex" Version="1.6.2" />
<PackageReference Include="Humanizer" Version="2.8.11" /> <PackageReference Include="Humanizer" Version="2.8.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />