mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 19:53:23 +08:00
Merge branch 'master' into input-handler-configuration
This commit is contained in:
commit
249ab8ab3d
@ -27,8 +27,8 @@
|
|||||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
||||||
<PackageReference Include="System.IO.Packaging" Version="5.0.0" />
|
<PackageReference Include="System.IO.Packaging" Version="5.0.0" />
|
||||||
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.5" />
|
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
<PackageReference Include="DiscordRichPresence" Version="1.0.175" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
|
@ -37,9 +37,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
AddInternal(scaleContainer = new Container
|
AddInternal(scaleContainer = new Container
|
||||||
{
|
{
|
||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Y = SPINNER_Y_CENTRE,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
glow = new Sprite
|
glow = new Sprite
|
||||||
|
@ -33,30 +33,23 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
spinnerBlink = source.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.SpinnerNoBlink)?.Value != true;
|
spinnerBlink = source.GetConfig<OsuSkinConfiguration, bool>(OsuSkinConfiguration.SpinnerNoBlink)?.Value != true;
|
||||||
|
|
||||||
AddInternal(new Container
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
|
||||||
// the old-style spinner relied heavily on absolute screen-space coordinate values.
|
|
||||||
// wrap everything in a container simulating absolute coords to preserve alignment
|
|
||||||
// as there are skins that depend on it.
|
|
||||||
Width = 640,
|
|
||||||
Height = 480,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Sprite
|
new Sprite
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Texture = source.GetTexture("spinner-background"),
|
Texture = source.GetTexture("spinner-background"),
|
||||||
Scale = new Vector2(SPRITE_SCALE)
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
|
Y = SPINNER_Y_CENTRE,
|
||||||
},
|
},
|
||||||
disc = new Sprite
|
disc = new Sprite
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Texture = source.GetTexture("spinner-circle"),
|
Texture = source.GetTexture("spinner-circle"),
|
||||||
Scale = new Vector2(SPRITE_SCALE)
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
|
Y = SPINNER_Y_CENTRE,
|
||||||
},
|
},
|
||||||
metre = new Container
|
metre = new Container
|
||||||
{
|
{
|
||||||
@ -64,8 +57,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
// this anchor makes no sense, but that's what stable uses.
|
// this anchor makes no sense, but that's what stable uses.
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
// adjustment for stable (metre has additional offset)
|
Margin = new MarginPadding { Top = SPINNER_TOP_OFFSET },
|
||||||
Margin = new MarginPadding { Top = 20 },
|
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Child = metreSprite = new Sprite
|
Child = metreSprite = new Sprite
|
||||||
{
|
{
|
||||||
@ -75,7 +67,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
Scale = new Vector2(SPRITE_SCALE)
|
Scale = new Vector2(SPRITE_SCALE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
public abstract class LegacySpinner : CompositeDrawable
|
public abstract class LegacySpinner : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// All constants are in osu!stable's gamefield space, which is shifted 16px downwards.
|
||||||
|
/// This offset is negated in both osu!stable and osu!lazer to bring all constants into window-space.
|
||||||
|
/// Note: SPINNER_Y_CENTRE + SPINNER_TOP_OFFSET - Position.Y = 240 (=480/2, or half the window-space in osu!stable)
|
||||||
|
/// </remarks>
|
||||||
|
protected const float SPINNER_TOP_OFFSET = 45f - 16f;
|
||||||
|
|
||||||
|
protected const float SPINNER_Y_CENTRE = SPINNER_TOP_OFFSET + 219f;
|
||||||
|
|
||||||
protected const float SPRITE_SCALE = 0.625f;
|
protected const float SPRITE_SCALE = 0.625f;
|
||||||
|
|
||||||
protected DrawableSpinner DrawableSpinner { get; private set; }
|
protected DrawableSpinner DrawableSpinner { get; private set; }
|
||||||
@ -26,7 +35,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(DrawableHitObject drawableHitObject, ISkinSource source)
|
private void load(DrawableHitObject drawableHitObject, ISkinSource source)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
// osu!stable positions spinner components in window-space (as opposed to gamefield-space). This is a 640x480 area taking up the entire screen.
|
||||||
|
// In lazer, the gamefield-space positional transformation is applied in OsuPlayfieldAdjustmentContainer, which is inverted here to make this area take up the entire window space.
|
||||||
|
Size = new Vector2(640, 480);
|
||||||
|
Position = new Vector2(0, -8f);
|
||||||
|
|
||||||
DrawableSpinner = (DrawableSpinner)drawableHitObject;
|
DrawableSpinner = (DrawableSpinner)drawableHitObject;
|
||||||
|
|
||||||
@ -34,22 +49,22 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
spin = new Sprite
|
spin = new Sprite
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Depth = float.MinValue,
|
Depth = float.MinValue,
|
||||||
Texture = source.GetTexture("spinner-spin"),
|
Texture = source.GetTexture("spinner-spin"),
|
||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Y = 120 - 45 // offset temporarily to avoid overlapping default spin counter
|
Y = SPINNER_TOP_OFFSET + 335,
|
||||||
},
|
},
|
||||||
clear = new Sprite
|
clear = new Sprite
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Alpha = 0,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Depth = float.MinValue,
|
Depth = float.MinValue,
|
||||||
Alpha = 0,
|
|
||||||
Texture = source.GetTexture("spinner-clear"),
|
Texture = source.GetTexture("spinner-clear"),
|
||||||
Scale = new Vector2(SPRITE_SCALE),
|
Scale = new Vector2(SPRITE_SCALE),
|
||||||
Y = -60
|
Y = SPINNER_TOP_OFFSET + 115,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
|
@ -56,6 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new BeatmapInfo
|
||||||
{
|
{
|
||||||
Ruleset = rulesets.GetRuleset(i % 4),
|
Ruleset = rulesets.GetRuleset(i % 4),
|
||||||
|
RulesetID = i % 4, // workaround for efcore 5 compatibility.
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineBeatmapID = beatmapId,
|
||||||
Length = length,
|
Length = length,
|
||||||
BPM = bpm,
|
BPM = bpm,
|
||||||
|
@ -229,6 +229,35 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddUntilStep("settings displayed", () => Game.Settings.State.Value == Visibility.Visible);
|
AddUntilStep("settings displayed", () => Game.Settings.State.Value == Visibility.Visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestToolbarHiddenByUser()
|
||||||
|
{
|
||||||
|
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
|
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
|
||||||
|
|
||||||
|
AddStep("Hide toolbar", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
|
InputManager.Key(Key.T);
|
||||||
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
|
});
|
||||||
|
|
||||||
|
pushEscape();
|
||||||
|
|
||||||
|
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
|
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
|
||||||
|
|
||||||
|
AddStep("Enter song select", () =>
|
||||||
|
{
|
||||||
|
InputManager.Key(Key.Enter);
|
||||||
|
InputManager.Key(Key.Enter);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
private void pushEscape() =>
|
private void pushEscape() =>
|
||||||
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
|
@ -186,6 +186,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Metadata = metadata,
|
Metadata = metadata,
|
||||||
BaseDifficulty = new BeatmapDifficulty(),
|
BaseDifficulty = new BeatmapDifficulty(),
|
||||||
Ruleset = ruleset,
|
Ruleset = ruleset,
|
||||||
|
RulesetID = ruleset.ID.GetValueOrDefault(), // workaround for efcore 5 compatibility.
|
||||||
StarDifficulty = difficultyIndex + 1,
|
StarDifficulty = difficultyIndex + 1,
|
||||||
Version = $"SR{difficultyIndex + 1}"
|
Version = $"SR{difficultyIndex + 1}"
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
@ -911,9 +911,11 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
int length = RNG.Next(30000, 200000);
|
int length = RNG.Next(30000, 200000);
|
||||||
double bpm = RNG.NextSingle(80, 200);
|
double bpm = RNG.NextSingle(80, 200);
|
||||||
|
|
||||||
|
var ruleset = getRuleset();
|
||||||
beatmaps.Add(new BeatmapInfo
|
beatmaps.Add(new BeatmapInfo
|
||||||
{
|
{
|
||||||
Ruleset = getRuleset(),
|
Ruleset = ruleset,
|
||||||
|
RulesetID = ruleset.ID.GetValueOrDefault(), // workaround for efcore 5 compatibility.
|
||||||
OnlineBeatmapID = beatmapId,
|
OnlineBeatmapID = beatmapId,
|
||||||
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
Version = $"{beatmapId} (length {TimeSpan.FromMilliseconds(length):m\\:ss}, bpm {bpm:0.#})",
|
||||||
Length = length,
|
Length = length,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Project">
|
<PropertyGroup Label="Project">
|
||||||
|
@ -17,12 +17,12 @@ namespace osu.Game.Beatmaps
|
|||||||
public abstract class BeatmapConverter<T> : IBeatmapConverter
|
public abstract class BeatmapConverter<T> : IBeatmapConverter
|
||||||
where T : HitObject
|
where T : HitObject
|
||||||
{
|
{
|
||||||
private event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
|
private event Action<HitObject, IEnumerable<HitObject>> objectConverted;
|
||||||
|
|
||||||
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
|
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
|
||||||
{
|
{
|
||||||
add => ObjectConverted += value;
|
add => objectConverted += value;
|
||||||
remove => ObjectConverted -= value;
|
remove => objectConverted -= value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBeatmap Beatmap { get; }
|
public IBeatmap Beatmap { get; }
|
||||||
@ -92,10 +92,10 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
|
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
|
||||||
|
|
||||||
if (ObjectConverted != null)
|
if (objectConverted != null)
|
||||||
{
|
{
|
||||||
converted = converted.ToList();
|
converted = converted.ToList();
|
||||||
ObjectConverted.Invoke(obj, converted);
|
objectConverted.Invoke(obj, converted);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var c in converted)
|
foreach (var c in converted)
|
||||||
|
@ -174,6 +174,8 @@ namespace osu.Game.Beatmaps
|
|||||||
if (beatmapSet.Beatmaps.Any(b => b.BaseDifficulty == null))
|
if (beatmapSet.Beatmaps.Any(b => b.BaseDifficulty == null))
|
||||||
throw new InvalidOperationException($"Cannot import {nameof(BeatmapInfo)} with null {nameof(BeatmapInfo.BaseDifficulty)}.");
|
throw new InvalidOperationException($"Cannot import {nameof(BeatmapInfo)} with null {nameof(BeatmapInfo.BaseDifficulty)}.");
|
||||||
|
|
||||||
|
beatmapSet.Requery(ContextFactory);
|
||||||
|
|
||||||
// check if a set already exists with the same online id, delete if it does.
|
// check if a set already exists with the same online id, delete if it does.
|
||||||
if (beatmapSet.OnlineBeatmapSetID != null)
|
if (beatmapSet.OnlineBeatmapSetID != null)
|
||||||
{
|
{
|
||||||
|
@ -471,9 +471,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
private string toLegacyCustomSampleBank(HitSampleInfo hitSampleInfo)
|
private string toLegacyCustomSampleBank(HitSampleInfo hitSampleInfo)
|
||||||
{
|
{
|
||||||
if (hitSampleInfo == null)
|
|
||||||
return "0";
|
|
||||||
|
|
||||||
if (hitSampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy)
|
if (hitSampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy)
|
||||||
return legacy.CustomSampleBank.ToString(CultureInfo.InvariantCulture);
|
return legacy.CustomSampleBank.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
@ -462,6 +462,8 @@ namespace osu.Game.Database
|
|||||||
// Dereference the existing file info, since the file model will be removed.
|
// Dereference the existing file info, since the file model will be removed.
|
||||||
if (file.FileInfo != null)
|
if (file.FileInfo != null)
|
||||||
{
|
{
|
||||||
|
file.Requery(usage.Context);
|
||||||
|
|
||||||
Files.Dereference(file.FileInfo);
|
Files.Dereference(file.FileInfo);
|
||||||
|
|
||||||
// This shouldn't be required, but here for safety in case the provided TModel is not being change tracked
|
// This shouldn't be required, but here for safety in case the provided TModel is not being change tracked
|
||||||
@ -635,10 +637,12 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
using (Stream s = reader.GetStream(file))
|
using (Stream s = reader.GetStream(file))
|
||||||
{
|
{
|
||||||
|
var fileInfo = files.Add(s);
|
||||||
fileInfos.Add(new TFileModel
|
fileInfos.Add(new TFileModel
|
||||||
{
|
{
|
||||||
Filename = file.Substring(prefix.Length).ToStandardisedPath(),
|
Filename = file.Substring(prefix.Length).ToStandardisedPath(),
|
||||||
FileInfo = files.Add(s)
|
FileInfo = fileInfo,
|
||||||
|
FileInfoID = fileInfo.ID // workaround for efcore 5 compatibility.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
71
osu.Game/Database/DatabaseWorkaroundExtensions.cs
Normal file
71
osu.Game/Database/DatabaseWorkaroundExtensions.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods which contain workarounds to make EFcore 5.x work with our existing (incorrect) thread safety.
|
||||||
|
/// The intention is to avoid blocking package updates while we consider the future of the database backend, with a potential backend switch imminent.
|
||||||
|
/// </summary>
|
||||||
|
public static class DatabaseWorkaroundExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Re-query the provided model to ensure it is in a sane state. This method requires explicit implementation per model type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model"></param>
|
||||||
|
/// <param name="contextFactory"></param>
|
||||||
|
public static void Requery(this IHasPrimaryKey model, IDatabaseContextFactory contextFactory)
|
||||||
|
{
|
||||||
|
switch (model)
|
||||||
|
{
|
||||||
|
case SkinInfo skinInfo:
|
||||||
|
requeryFiles(skinInfo.Files, contextFactory);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScoreInfo scoreInfo:
|
||||||
|
requeryFiles(scoreInfo.Beatmap.BeatmapSet.Files, contextFactory);
|
||||||
|
requeryFiles(scoreInfo.Files, contextFactory);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BeatmapSetInfo beatmapSetInfo:
|
||||||
|
var context = contextFactory.Get();
|
||||||
|
|
||||||
|
foreach (var beatmap in beatmapSetInfo.Beatmaps)
|
||||||
|
{
|
||||||
|
// Workaround System.InvalidOperationException
|
||||||
|
// The instance of entity type 'RulesetInfo' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked.
|
||||||
|
beatmap.Ruleset = context.RulesetInfo.Find(beatmap.RulesetID);
|
||||||
|
}
|
||||||
|
|
||||||
|
requeryFiles(beatmapSetInfo.Files, contextFactory);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"{nameof(Requery)} does not have support for the provided model type", nameof(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
void requeryFiles<T>(List<T> files, IDatabaseContextFactory databaseContextFactory) where T : class, INamedFileInfo
|
||||||
|
{
|
||||||
|
var dbContext = databaseContextFactory.Get();
|
||||||
|
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
Requery(file, dbContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Requery(this INamedFileInfo file, OsuDbContext dbContext)
|
||||||
|
{
|
||||||
|
// Workaround System.InvalidOperationException
|
||||||
|
// The instance of entity type 'FileInfo' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked.
|
||||||
|
file.FileInfo = dbContext.FileInfo.Find(file.FileInfoID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
@ -111,10 +110,10 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
base.OnConfiguring(optionsBuilder);
|
base.OnConfiguring(optionsBuilder);
|
||||||
optionsBuilder
|
optionsBuilder
|
||||||
// this is required for the time being due to the way we are querying in places like BeatmapStore.
|
.UseSqlite(connectionString,
|
||||||
// if we ever move to having consumers file their own .Includes, or get eager loading support, this could be re-enabled.
|
sqliteOptions => sqliteOptions
|
||||||
.ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.IncludeIgnoredWarning))
|
.CommandTimeout(10)
|
||||||
.UseSqlite(connectionString, sqliteOptions => sqliteOptions.CommandTimeout(10))
|
.UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery))
|
||||||
.UseLoggerFactory(logger.Value);
|
.UseLoggerFactory(logger.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,12 +884,9 @@ namespace osu.Game
|
|||||||
frameworkConfig.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode).SetDefault();
|
frameworkConfig.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode).SetDefault();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case GlobalAction.ToggleToolbar:
|
|
||||||
Toolbar.ToggleVisibility();
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GlobalAction.ToggleGameplayMouseButtons:
|
case GlobalAction.ToggleGameplayMouseButtons:
|
||||||
LocalConfig.Set(OsuSetting.MouseDisableButtons, !LocalConfig.Get<bool>(OsuSetting.MouseDisableButtons));
|
var mouseDisableButtons = LocalConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
||||||
|
mouseDisableButtons.Value = !mouseDisableButtons.Value;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case GlobalAction.RandomSkin:
|
case GlobalAction.RandomSkin:
|
||||||
|
@ -21,6 +21,8 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
public class ChangelogOverlay : OnlineOverlay<ChangelogHeader>
|
public class ChangelogOverlay : OnlineOverlay<ChangelogHeader>
|
||||||
{
|
{
|
||||||
|
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
||||||
|
|
||||||
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
|
||||||
|
|
||||||
private Sample sampleBack;
|
private Sample sampleBack;
|
||||||
@ -126,8 +128,11 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private Task initialFetchTask;
|
private Task initialFetchTask;
|
||||||
|
|
||||||
private void performAfterFetch(Action action) => fetchListing()?.ContinueWith(_ =>
|
private void performAfterFetch(Action action) => Schedule(() =>
|
||||||
|
{
|
||||||
|
fetchListing()?.ContinueWith(_ =>
|
||||||
Schedule(action), TaskContinuationOptions.OnlyOnRanToCompletion);
|
Schedule(action), TaskContinuationOptions.OnlyOnRanToCompletion);
|
||||||
|
});
|
||||||
|
|
||||||
private Task fetchListing()
|
private Task fetchListing()
|
||||||
{
|
{
|
||||||
@ -163,7 +168,7 @@ namespace osu.Game.Overlays
|
|||||||
await API.PerformAsync(req).ConfigureAwait(false);
|
await API.PerformAsync(req).ConfigureAwait(false);
|
||||||
|
|
||||||
return tcs.Task;
|
return tcs.Task;
|
||||||
});
|
}).Unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CancellationTokenSource loadContentCancellation;
|
private CancellationTokenSource loadContentCancellation;
|
||||||
|
@ -138,7 +138,6 @@ namespace osu.Game.Overlays.Profile.Header
|
|||||||
if (!string.IsNullOrEmpty(user.Twitter))
|
if (!string.IsNullOrEmpty(user.Twitter))
|
||||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
||||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
||||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
|
||||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
|
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
|
||||||
|
|
||||||
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
|
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
|
||||||
|
@ -13,14 +13,22 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Toolbar
|
namespace osu.Game.Overlays.Toolbar
|
||||||
{
|
{
|
||||||
public class Toolbar : VisibilityContainer
|
public class Toolbar : VisibilityContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public const float HEIGHT = 40;
|
public const float HEIGHT = 40;
|
||||||
public const float TOOLTIP_HEIGHT = 30;
|
public const float TOOLTIP_HEIGHT = 30;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the user hid this <see cref="Toolbar"/> with <see cref="GlobalAction.ToggleToolbar"/>.
|
||||||
|
/// In this state, automatic toggles should not occur, respecting the user's preference to have no toolbar.
|
||||||
|
/// </summary>
|
||||||
|
private bool hiddenByUser;
|
||||||
|
|
||||||
public Action OnHome;
|
public Action OnHome;
|
||||||
|
|
||||||
private ToolbarUserButton userButton;
|
private ToolbarUserButton userButton;
|
||||||
@ -30,7 +38,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
protected readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
|
protected readonly IBindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
|
||||||
|
|
||||||
// Toolbar components like RulesetSelector should receive keyboard input events even when the toolbar is hidden.
|
// Toolbar and its components need keyboard input even when hidden.
|
||||||
public override bool PropagateNonPositionalInputSubTree => true;
|
public override bool PropagateNonPositionalInputSubTree => true;
|
||||||
|
|
||||||
public Toolbar()
|
public Toolbar()
|
||||||
@ -142,7 +150,9 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
protected override void UpdateState(ValueChangedEvent<Visibility> state)
|
||||||
{
|
{
|
||||||
if (state.NewValue == Visibility.Visible && OverlayActivationMode.Value == OverlayActivation.Disabled)
|
bool blockShow = hiddenByUser || OverlayActivationMode.Value == OverlayActivation.Disabled;
|
||||||
|
|
||||||
|
if (state.NewValue == Visibility.Visible && blockShow)
|
||||||
{
|
{
|
||||||
State.Value = Visibility.Hidden;
|
State.Value = Visibility.Hidden;
|
||||||
return;
|
return;
|
||||||
@ -164,5 +174,25 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
this.MoveToY(-DrawSize.Y, transition_time, Easing.OutQuint);
|
this.MoveToY(-DrawSize.Y, transition_time, Easing.OutQuint);
|
||||||
this.FadeOut(transition_time, Easing.InQuint);
|
this.FadeOut(transition_time, Easing.InQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (OverlayActivationMode.Value == OverlayActivation.Disabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.ToggleToolbar:
|
||||||
|
hiddenByUser = State.Value == Visibility.Visible; // set before toggling to allow the operation to always succeed.
|
||||||
|
ToggleVisibility();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(GlobalAction action)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Scoring
|
|||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
modsJson = null;
|
modsJson = JsonConvert.SerializeObject(value.Select(m => new DeserializedMod { Acronym = m.Acronym }));
|
||||||
mods = value;
|
mods = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,16 +86,7 @@ namespace osu.Game.Scoring
|
|||||||
[Column("Mods")]
|
[Column("Mods")]
|
||||||
public string ModsJson
|
public string ModsJson
|
||||||
{
|
{
|
||||||
get
|
get => modsJson;
|
||||||
{
|
|
||||||
if (modsJson != null)
|
|
||||||
return modsJson;
|
|
||||||
|
|
||||||
if (mods == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return modsJson = JsonConvert.SerializeObject(mods.Select(m => new DeserializedMod { Acronym = m.Acronym }));
|
|
||||||
}
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
modsJson = value;
|
modsJson = value;
|
||||||
|
@ -52,6 +52,11 @@ namespace osu.Game.Scoring
|
|||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void PreImport(ScoreInfo model)
|
||||||
|
{
|
||||||
|
model.Requery(ContextFactory);
|
||||||
|
}
|
||||||
|
|
||||||
protected override ScoreInfo CreateModel(ArchiveReader archive)
|
protected override ScoreInfo CreateModel(ArchiveReader archive)
|
||||||
{
|
{
|
||||||
if (archive == null)
|
if (archive == null)
|
||||||
|
@ -74,7 +74,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private string lastSavedHash;
|
private string lastSavedHash;
|
||||||
|
|
||||||
private Box bottomBackground;
|
|
||||||
private Container<EditorScreen> screenContainer;
|
private Container<EditorScreen> screenContainer;
|
||||||
|
|
||||||
private EditorScreen currentScreen;
|
private EditorScreen currentScreen;
|
||||||
@ -106,26 +105,29 @@ namespace osu.Game.Screens.Edit
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, GameHost host, OsuConfigManager config)
|
private void load(OsuColour colours, GameHost host, OsuConfigManager config)
|
||||||
{
|
{
|
||||||
if (Beatmap.Value is DummyWorkingBeatmap)
|
var loadableBeatmap = Beatmap.Value;
|
||||||
|
|
||||||
|
if (loadableBeatmap is DummyWorkingBeatmap)
|
||||||
{
|
{
|
||||||
isNewBeatmap = true;
|
isNewBeatmap = true;
|
||||||
|
|
||||||
var newBeatmap = beatmapManager.CreateNew(Ruleset.Value, api.LocalUser.Value);
|
loadableBeatmap = beatmapManager.CreateNew(Ruleset.Value, api.LocalUser.Value);
|
||||||
|
|
||||||
|
// required so we can get the track length in EditorClock.
|
||||||
|
// this is safe as nothing has yet got a reference to this new beatmap.
|
||||||
|
loadableBeatmap.LoadTrack();
|
||||||
|
|
||||||
// this is a bit haphazard, but guards against setting the lease Beatmap bindable if
|
// this is a bit haphazard, but guards against setting the lease Beatmap bindable if
|
||||||
// the editor has already been exited.
|
// the editor has already been exited.
|
||||||
if (!ValidForPush)
|
if (!ValidForPush)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// this probably shouldn't be set in the asynchronous load method, but everything following relies on it.
|
|
||||||
Beatmap.Value = newBeatmap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beatDivisor.Value = Beatmap.Value.BeatmapInfo.BeatDivisor;
|
beatDivisor.Value = loadableBeatmap.BeatmapInfo.BeatDivisor;
|
||||||
beatDivisor.BindValueChanged(divisor => Beatmap.Value.BeatmapInfo.BeatDivisor = divisor.NewValue);
|
beatDivisor.BindValueChanged(divisor => loadableBeatmap.BeatmapInfo.BeatDivisor = divisor.NewValue);
|
||||||
|
|
||||||
// Todo: should probably be done at a DrawableRuleset level to share logic with Player.
|
// Todo: should probably be done at a DrawableRuleset level to share logic with Player.
|
||||||
clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
|
clock = new EditorClock(loadableBeatmap, beatDivisor) { IsCoupled = false };
|
||||||
|
|
||||||
UpdateClockSource();
|
UpdateClockSource();
|
||||||
|
|
||||||
@ -139,7 +141,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
playableBeatmap = loadableBeatmap.GetPlayableBeatmap(loadableBeatmap.BeatmapInfo.Ruleset);
|
||||||
|
|
||||||
// clone these locally for now to avoid incurring overhead on GetPlayableBeatmap usages.
|
// clone these locally for now to avoid incurring overhead on GetPlayableBeatmap usages.
|
||||||
// eventually we will want to improve how/where this is done as there are issues with *not* cloning it in all cases.
|
// eventually we will want to improve how/where this is done as there are issues with *not* cloning it in all cases.
|
||||||
@ -153,13 +155,21 @@ namespace osu.Game.Screens.Edit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, Beatmap.Value.Skin));
|
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.Skin));
|
||||||
dependencies.CacheAs(editorBeatmap);
|
dependencies.CacheAs(editorBeatmap);
|
||||||
changeHandler = new EditorChangeHandler(editorBeatmap);
|
changeHandler = new EditorChangeHandler(editorBeatmap);
|
||||||
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
|
dependencies.CacheAs<IEditorChangeHandler>(changeHandler);
|
||||||
|
|
||||||
updateLastSavedHash();
|
updateLastSavedHash();
|
||||||
|
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
// we need to avoid changing the beatmap from an asynchronous load thread. it can potentially cause weirdness including crashes.
|
||||||
|
// this assumes that nothing during the rest of this load() method is accessing Beatmap.Value (loadableBeatmap should be preferred).
|
||||||
|
// generally this is quite safe, as the actual load of editor content comes after menuBar.Mode.ValueChanged is fired in its own LoadComplete.
|
||||||
|
Beatmap.Value = loadableBeatmap;
|
||||||
|
});
|
||||||
|
|
||||||
OsuMenuItem undoMenuItem;
|
OsuMenuItem undoMenuItem;
|
||||||
OsuMenuItem redoMenuItem;
|
OsuMenuItem redoMenuItem;
|
||||||
|
|
||||||
@ -167,17 +177,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
EditorMenuItem copyMenuItem;
|
EditorMenuItem copyMenuItem;
|
||||||
EditorMenuItem pasteMenuItem;
|
EditorMenuItem pasteMenuItem;
|
||||||
|
|
||||||
var fileMenuItems = new List<MenuItem>
|
|
||||||
{
|
|
||||||
new EditorMenuItem("Save", MenuItemType.Standard, Save)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (RuntimeInfo.IsDesktop)
|
|
||||||
fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap));
|
|
||||||
|
|
||||||
fileMenuItems.Add(new EditorMenuItemSpacer());
|
|
||||||
fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit));
|
|
||||||
|
|
||||||
AddInternal(new OsuContextMenuContainer
|
AddInternal(new OsuContextMenuContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -209,7 +208,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
new MenuItem("File")
|
new MenuItem("File")
|
||||||
{
|
{
|
||||||
Items = fileMenuItems
|
Items = createFileMenuItems()
|
||||||
},
|
},
|
||||||
new MenuItem("Edit")
|
new MenuItem("Edit")
|
||||||
{
|
{
|
||||||
@ -242,7 +241,11 @@ namespace osu.Game.Screens.Edit
|
|||||||
Height = 60,
|
Height = 60,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
bottomBackground = new Box { RelativeSizeAxes = Axes.Both },
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colours.Gray2
|
||||||
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
@ -299,8 +302,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
clipboard.BindValueChanged(content => pasteMenuItem.Action.Disabled = string.IsNullOrEmpty(content.NewValue));
|
clipboard.BindValueChanged(content => pasteMenuItem.Action.Disabled = string.IsNullOrEmpty(content.NewValue));
|
||||||
|
|
||||||
menuBar.Mode.ValueChanged += onModeChanged;
|
menuBar.Mode.ValueChanged += onModeChanged;
|
||||||
|
|
||||||
bottomBackground.Colour = colours.Gray2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -681,6 +682,21 @@ namespace osu.Game.Screens.Edit
|
|||||||
lastSavedHash = changeHandler.CurrentStateHash;
|
lastSavedHash = changeHandler.CurrentStateHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<MenuItem> createFileMenuItems()
|
||||||
|
{
|
||||||
|
var fileMenuItems = new List<MenuItem>
|
||||||
|
{
|
||||||
|
new EditorMenuItem("Save", MenuItemType.Standard, Save)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (RuntimeInfo.IsDesktop)
|
||||||
|
fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap));
|
||||||
|
|
||||||
|
fileMenuItems.Add(new EditorMenuItemSpacer());
|
||||||
|
fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit));
|
||||||
|
return fileMenuItems;
|
||||||
|
}
|
||||||
|
|
||||||
public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime);
|
public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime);
|
||||||
|
|
||||||
public double GetBeatLengthAtTime(double referenceTime) => editorBeatmap.GetBeatLengthAtTime(referenceTime);
|
public double GetBeatLengthAtTime(double referenceTime) => editorBeatmap.GetBeatLengthAtTime(referenceTime);
|
||||||
|
@ -142,6 +142,11 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void PreImport(SkinInfo model)
|
||||||
|
{
|
||||||
|
model.Requery(ContextFactory);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve a <see cref="Skin"/> instance for the provided <see cref="SkinInfo"/>
|
/// Retrieve a <see cref="Skin"/> instance for the provided <see cref="SkinInfo"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -111,9 +111,6 @@ namespace osu.Game.Users
|
|||||||
[JsonProperty(@"twitter")]
|
[JsonProperty(@"twitter")]
|
||||||
public string Twitter;
|
public string Twitter;
|
||||||
|
|
||||||
[JsonProperty(@"skype")]
|
|
||||||
public string Skype;
|
|
||||||
|
|
||||||
[JsonProperty(@"discord")]
|
[JsonProperty(@"discord")]
|
||||||
public string Discord;
|
public string Discord;
|
||||||
|
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="5.0.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="5.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
|
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.309.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.309.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
|
||||||
|
@ -90,8 +90,6 @@
|
|||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<PackageReference Include="DiffPlex" Version="1.6.3" />
|
<PackageReference Include="DiffPlex" Version="1.6.3" />
|
||||||
<PackageReference Include="Humanizer" Version="2.8.26" />
|
<PackageReference Include="Humanizer" Version="2.8.26" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.309.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.309.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.1" />
|
<PackageReference Include="SharpCompress" Version="0.28.1" />
|
||||||
|
Loading…
Reference in New Issue
Block a user