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:
commit
ebe2e97372
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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" />
|
||||||
|
@ -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" />
|
||||||
|
Loading…
Reference in New Issue
Block a user