mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 23:12:56 +08:00
Merge branch 'master' into pp-balancing
This commit is contained in:
commit
61a3758cd9
@ -4,8 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
@ -50,9 +48,6 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
new KeyBinding(InputKey.X, PippidonAction.Button2),
|
new KeyBinding(InputKey.X, PippidonAction.Button2),
|
||||||
};
|
};
|
||||||
|
|
||||||
public override Drawable CreateIcon() => new Sprite
|
public override Drawable CreateIcon() => new PippidonRulesetIcon(this);
|
||||||
{
|
|
||||||
Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/coin"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Pippidon
|
||||||
|
{
|
||||||
|
public class PippidonRulesetIcon : Sprite
|
||||||
|
{
|
||||||
|
private readonly Ruleset ruleset;
|
||||||
|
|
||||||
|
public PippidonRulesetIcon(Ruleset ruleset)
|
||||||
|
{
|
||||||
|
this.ruleset = ruleset;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IRenderer renderer)
|
||||||
|
{
|
||||||
|
Texture = new TextureStore(renderer, new TextureLoaderStore(ruleset.CreateResourceStore()), false).Get("Textures/coin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,8 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
@ -47,10 +45,6 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
new KeyBinding(InputKey.S, PippidonAction.MoveDown),
|
new KeyBinding(InputKey.S, PippidonAction.MoveDown),
|
||||||
};
|
};
|
||||||
|
|
||||||
public override Drawable CreateIcon() => new Sprite
|
public override Drawable CreateIcon() => new PippidonRulesetIcon(this);
|
||||||
{
|
|
||||||
Margin = new MarginPadding { Top = 3 },
|
|
||||||
Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/coin"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Pippidon
|
||||||
|
{
|
||||||
|
public class PippidonRulesetIcon : Sprite
|
||||||
|
{
|
||||||
|
private readonly Ruleset ruleset;
|
||||||
|
|
||||||
|
public PippidonRulesetIcon(Ruleset ruleset)
|
||||||
|
{
|
||||||
|
this.ruleset = ruleset;
|
||||||
|
|
||||||
|
Margin = new MarginPadding { Top = 3 };
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IRenderer renderer)
|
||||||
|
{
|
||||||
|
Texture = new TextureStore(renderer, new TextureLoaderStore(ruleset.CreateResourceStore()), false).Get("Textures/coin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -51,8 +51,8 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.722.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.810.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.730.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.810.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
52
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs
Normal file
52
osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
||||||
|
{
|
||||||
|
public class TestSceneBarLine : ManiaSkinnableTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestMinor()
|
||||||
|
{
|
||||||
|
AddStep("Create barlines", () => recreate());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recreate(Func<IEnumerable<BarLine>>? createBarLines = null)
|
||||||
|
{
|
||||||
|
var stageDefinitions = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = 4 },
|
||||||
|
};
|
||||||
|
|
||||||
|
SetContents(_ => new ManiaPlayfield(stageDefinitions).With(s =>
|
||||||
|
{
|
||||||
|
if (createBarLines != null)
|
||||||
|
{
|
||||||
|
var barLines = createBarLines();
|
||||||
|
|
||||||
|
foreach (var b in barLines)
|
||||||
|
s.Add(b);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
s.Add(new BarLine
|
||||||
|
{
|
||||||
|
StartTime = Time.Current + i * 500,
|
||||||
|
Major = i % 4 == 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,9 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -16,21 +13,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableBarLine : DrawableManiaHitObject<BarLine>
|
public class DrawableBarLine : DrawableManiaHitObject<BarLine>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Height of major bar line triangles.
|
|
||||||
/// </summary>
|
|
||||||
private const float triangle_height = 12;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offset of the major bar line triangles from the sides of the bar line.
|
|
||||||
/// </summary>
|
|
||||||
private const float triangle_offset = 9;
|
|
||||||
|
|
||||||
public DrawableBarLine(BarLine barLine)
|
public DrawableBarLine(BarLine barLine)
|
||||||
: base(barLine)
|
: base(barLine)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = 2f;
|
Height = barLine.Major ? 1.7f : 1.2f;
|
||||||
|
|
||||||
AddInternal(new Box
|
AddInternal(new Box
|
||||||
{
|
{
|
||||||
@ -38,34 +25,33 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = new Color4(255, 204, 33, 255),
|
Alpha = barLine.Major ? 0.5f : 0.2f
|
||||||
});
|
});
|
||||||
|
|
||||||
if (barLine.Major)
|
if (barLine.Major)
|
||||||
{
|
{
|
||||||
AddInternal(new EquilateralTriangle
|
Vector2 size = new Vector2(22, 6);
|
||||||
|
const float line_offset = 4;
|
||||||
|
|
||||||
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Name = "Left triangle",
|
Name = "Left line",
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.CentreRight,
|
||||||
Size = new Vector2(triangle_height),
|
|
||||||
X = -triangle_offset,
|
Size = size,
|
||||||
Rotation = 90
|
X = -line_offset,
|
||||||
});
|
});
|
||||||
|
|
||||||
AddInternal(new EquilateralTriangle
|
AddInternal(new Circle
|
||||||
{
|
{
|
||||||
Name = "Right triangle",
|
Name = "Right line",
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.CentreLeft,
|
||||||
Size = new Vector2(triangle_height),
|
Size = size,
|
||||||
X = triangle_offset,
|
X = line_offset,
|
||||||
Rotation = -90
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!barLine.Major)
|
|
||||||
Alpha = 0.2f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
|
@ -9,7 +9,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.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
@ -6,7 +6,8 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -19,6 +20,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
[HeadlessTest]
|
[HeadlessTest]
|
||||||
public class LegacyMainCirclePieceTest : OsuTestScene
|
public class LegacyMainCirclePieceTest : OsuTestScene
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IRenderer renderer { get; set; } = null!;
|
||||||
|
|
||||||
private static readonly object?[][] texture_priority_cases =
|
private static readonly object?[][] texture_priority_cases =
|
||||||
{
|
{
|
||||||
// default priority lookup
|
// default priority lookup
|
||||||
@ -76,7 +80,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
skin.Setup(s => s.GetTexture(It.IsAny<string>())).CallBase();
|
skin.Setup(s => s.GetTexture(It.IsAny<string>())).CallBase();
|
||||||
|
|
||||||
skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny<WrapMode>(), It.IsAny<WrapMode>()))
|
skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny<WrapMode>(), It.IsAny<WrapMode>()))
|
||||||
.Returns((string componentName, WrapMode _, WrapMode _) => new Texture(1, 1) { AssetName = componentName });
|
.Returns((string componentName, WrapMode _, WrapMode _) =>
|
||||||
|
{
|
||||||
|
var tex = renderer.CreateTexture(1, 1);
|
||||||
|
tex.AssetName = componentName;
|
||||||
|
return tex;
|
||||||
|
});
|
||||||
|
|
||||||
Child = new DependencyProvidingContainer
|
Child = new DependencyProvidingContainer
|
||||||
{
|
{
|
||||||
@ -84,7 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
Child = piece = new TestLegacyMainCirclePiece(priorityLookup),
|
Child = piece = new TestLegacyMainCirclePiece(priorityLookup),
|
||||||
};
|
};
|
||||||
|
|
||||||
var sprites = this.ChildrenOfType<Sprite>().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray();
|
var sprites = this.ChildrenOfType<Sprite>().Where(s => !string.IsNullOrEmpty(s.Texture.AssetName)).DistinctBy(s => s.Texture.AssetName).ToArray();
|
||||||
Debug.Assert(sprites.Length <= 2);
|
Debug.Assert(sprites.Length <= 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing.Input;
|
using osu.Framework.Testing.Input;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -25,6 +25,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
public class TestSceneCursorTrail : OsuTestScene
|
public class TestSceneCursorTrail : OsuTestScene
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IRenderer renderer { get; set; }
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSmoothCursorTrail()
|
public void TestSmoothCursorTrail()
|
||||||
{
|
{
|
||||||
@ -44,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
createTest(() =>
|
createTest(() =>
|
||||||
{
|
{
|
||||||
var skinContainer = new LegacySkinContainer(false);
|
var skinContainer = new LegacySkinContainer(renderer, false);
|
||||||
var legacyCursorTrail = new LegacyCursorTrail(skinContainer);
|
var legacyCursorTrail = new LegacyCursorTrail(skinContainer);
|
||||||
|
|
||||||
skinContainer.Child = legacyCursorTrail;
|
skinContainer.Child = legacyCursorTrail;
|
||||||
@ -58,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
createTest(() =>
|
createTest(() =>
|
||||||
{
|
{
|
||||||
var skinContainer = new LegacySkinContainer(true);
|
var skinContainer = new LegacySkinContainer(renderer, true);
|
||||||
var legacyCursorTrail = new LegacyCursorTrail(skinContainer);
|
var legacyCursorTrail = new LegacyCursorTrail(skinContainer);
|
||||||
|
|
||||||
skinContainer.Child = legacyCursorTrail;
|
skinContainer.Child = legacyCursorTrail;
|
||||||
@ -82,10 +85,12 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
[Cached(typeof(ISkinSource))]
|
[Cached(typeof(ISkinSource))]
|
||||||
private class LegacySkinContainer : Container, ISkinSource
|
private class LegacySkinContainer : Container, ISkinSource
|
||||||
{
|
{
|
||||||
|
private readonly IRenderer renderer;
|
||||||
private readonly bool disjoint;
|
private readonly bool disjoint;
|
||||||
|
|
||||||
public LegacySkinContainer(bool disjoint)
|
public LegacySkinContainer(IRenderer renderer, bool disjoint)
|
||||||
{
|
{
|
||||||
|
this.renderer = renderer;
|
||||||
this.disjoint = disjoint;
|
this.disjoint = disjoint;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -98,14 +103,14 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
switch (componentName)
|
switch (componentName)
|
||||||
{
|
{
|
||||||
case "cursortrail":
|
case "cursortrail":
|
||||||
var tex = new Texture(Texture.WhitePixel.TextureGL);
|
var tex = new Texture(renderer.WhitePixel);
|
||||||
|
|
||||||
if (disjoint)
|
if (disjoint)
|
||||||
tex.ScaleAdjust = 1 / 25f;
|
tex.ScaleAdjust = 1 / 25f;
|
||||||
return tex;
|
return tex;
|
||||||
|
|
||||||
case "cursormiddle":
|
case "cursormiddle":
|
||||||
return disjoint ? null : Texture.WhitePixel;
|
return disjoint ? null : renderer.WhitePixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
@ -12,7 +12,6 @@ using osu.Framework.Audio;
|
|||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
|||||||
velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2);
|
velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (osuLastObj.TravelTime != 0)
|
if (osuLastObj.BaseObject is Slider)
|
||||||
{
|
{
|
||||||
// Reward sliders based on velocity.
|
// Reward sliders based on velocity.
|
||||||
sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime;
|
||||||
|
@ -15,11 +15,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
|||||||
private const double max_opacity_bonus = 0.4;
|
private const double max_opacity_bonus = 0.4;
|
||||||
private const double hidden_bonus = 0.2;
|
private const double hidden_bonus = 0.2;
|
||||||
|
|
||||||
|
private const double min_velocity = 0.5;
|
||||||
|
private const double slider_multiplier = 1.3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Evaluates the difficulty of memorising and hitting an object, based on:
|
/// Evaluates the difficulty of memorising and hitting an object, based on:
|
||||||
/// <list type="bullet">
|
/// <list type="bullet">
|
||||||
/// <item><description>distance between the previous and current object,</description></item>
|
/// <item><description>distance between a number of previous objects and the current object,</description></item>
|
||||||
/// <item><description>the visual opacity of the current object,</description></item>
|
/// <item><description>the visual opacity of the current object,</description></item>
|
||||||
|
/// <item><description>length and speed of the current object (for sliders),</description></item>
|
||||||
/// <item><description>and whether the hidden mod is enabled.</description></item>
|
/// <item><description>and whether the hidden mod is enabled.</description></item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -73,6 +77,26 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators
|
|||||||
if (hidden)
|
if (hidden)
|
||||||
result *= 1.0 + hidden_bonus;
|
result *= 1.0 + hidden_bonus;
|
||||||
|
|
||||||
|
double sliderBonus = 0.0;
|
||||||
|
|
||||||
|
if (osuCurrent.BaseObject is Slider osuSlider)
|
||||||
|
{
|
||||||
|
// Invert the scaling factor to determine the true travel distance independent of circle size.
|
||||||
|
double pixelTravelDistance = osuSlider.LazyTravelDistance / scalingFactor;
|
||||||
|
|
||||||
|
// Reward sliders based on velocity.
|
||||||
|
sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5);
|
||||||
|
|
||||||
|
// Longer sliders require more memorisation.
|
||||||
|
sliderBonus *= pixelTravelDistance;
|
||||||
|
|
||||||
|
// Nerf sliders with repeats, as less memorisation is required.
|
||||||
|
if (osuSlider.RepeatCount > 0)
|
||||||
|
sliderBonus /= (osuSlider.RepeatCount + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
result += sliderBonus * slider_multiplier;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
{
|
{
|
||||||
public class OsuDifficultyHitObject : DifficultyHitObject
|
public class OsuDifficultyHitObject : DifficultyHitObject
|
||||||
{
|
{
|
||||||
private const int normalised_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
/// <summary>
|
||||||
|
/// A distance by which all distances should be scaled in order to assume a uniform circle size.
|
||||||
|
/// </summary>
|
||||||
|
public const int NORMALISED_RADIUS = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths.
|
||||||
|
|
||||||
private const int min_delta_time = 25;
|
private const int min_delta_time = 25;
|
||||||
private const float maximum_slider_radius = normalised_radius * 2.4f;
|
private const float maximum_slider_radius = NORMALISED_RADIUS * 2.4f;
|
||||||
private const float assumed_slider_radius = normalised_radius * 1.8f;
|
private const float assumed_slider_radius = NORMALISED_RADIUS * 1.8f;
|
||||||
|
|
||||||
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject;
|
||||||
|
|
||||||
@ -64,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
public double TravelDistance { get; private set; }
|
public double TravelDistance { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time taken to travel through <see cref="TravelDistance"/>, with a minimum value of 25ms for a non-zero distance.
|
/// The time taken to travel through <see cref="TravelDistance"/>, with a minimum value of 25ms for <see cref="Slider"/> objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double TravelTime { get; private set; }
|
public double TravelTime { get; private set; }
|
||||||
|
|
||||||
@ -123,7 +127,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
if (BaseObject is Slider currentSlider)
|
if (BaseObject is Slider currentSlider)
|
||||||
{
|
{
|
||||||
computeSliderCursorPosition(currentSlider);
|
computeSliderCursorPosition(currentSlider);
|
||||||
TravelDistance = currentSlider.LazyTravelDistance;
|
// Bonus for repeat sliders until a better per nested object strain system can be achieved.
|
||||||
|
TravelDistance = currentSlider.LazyTravelDistance * (float)Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5);
|
||||||
TravelTime = Math.Max(currentSlider.LazyTravelTime / clockRate, min_delta_time);
|
TravelTime = Math.Max(currentSlider.LazyTravelTime / clockRate, min_delta_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
// We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps.
|
||||||
float scalingFactor = normalised_radius / (float)BaseObject.Radius;
|
float scalingFactor = NORMALISED_RADIUS / (float)BaseObject.Radius;
|
||||||
|
|
||||||
if (BaseObject.Radius < 30)
|
if (BaseObject.Radius < 30)
|
||||||
{
|
{
|
||||||
@ -206,7 +211,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
|
|
||||||
slider.LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived.
|
slider.LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived.
|
||||||
var currCursorPosition = slider.StackedPosition;
|
var currCursorPosition = slider.StackedPosition;
|
||||||
double scalingFactor = normalised_radius / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used.
|
double scalingFactor = NORMALISED_RADIUS / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used.
|
||||||
|
|
||||||
for (int i = 1; i < slider.NestedHitObjects.Count; i++)
|
for (int i = 1; i < slider.NestedHitObjects.Count; i++)
|
||||||
{
|
{
|
||||||
@ -234,7 +239,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
else if (currMovementObj is SliderRepeat)
|
else if (currMovementObj is SliderRepeat)
|
||||||
{
|
{
|
||||||
// For a slider repeat, assume a tighter movement threshold to better assess repeat sliders.
|
// For a slider repeat, assume a tighter movement threshold to better assess repeat sliders.
|
||||||
requiredMovement = normalised_radius;
|
requiredMovement = NORMALISED_RADIUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currMovementLength > requiredMovement)
|
if (currMovementLength > requiredMovement)
|
||||||
@ -248,8 +253,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
|
|||||||
if (i == slider.NestedHitObjects.Count - 1)
|
if (i == slider.NestedHitObjects.Count - 1)
|
||||||
slider.LazyEndPosition = currCursorPosition;
|
slider.LazyEndPosition = currCursorPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
slider.LazyTravelDistance *= (float)Math.Pow(1 + slider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 getEndCursorPosition(OsuHitObject hitObject)
|
private Vector2 getEndCursorPosition(OsuHitObject hitObject)
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
|||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
connectionPool = new DrawablePool<FollowPointConnection>(1, 200),
|
connectionPool = new DrawablePool<FollowPointConnection>(10, 200),
|
||||||
pointPool = new DrawablePool<FollowPoint>(50, 1000)
|
pointPool = new DrawablePool<FollowPoint>(50, 1000)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ using System.Runtime.InteropServices;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Batches;
|
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Graphics.Rendering.Vertices;
|
||||||
using osu.Framework.Graphics.Shaders;
|
using osu.Framework.Graphics.Shaders;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
@ -68,8 +68,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ShaderManager shaders)
|
private void load(IRenderer renderer, ShaderManager shaders)
|
||||||
{
|
{
|
||||||
|
texture ??= renderer.WhitePixel;
|
||||||
shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE);
|
shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
resetTime();
|
resetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Texture texture = Texture.WhitePixel;
|
private Texture texture;
|
||||||
|
|
||||||
public Texture Texture
|
public Texture Texture
|
||||||
{
|
{
|
||||||
@ -222,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
private Vector2 originPosition;
|
private Vector2 originPosition;
|
||||||
|
|
||||||
private readonly QuadBatch<TexturedTrailVertex> vertexBatch = new QuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
private IVertexBatch<TexturedTrailVertex> vertexBatch;
|
||||||
|
|
||||||
public TrailDrawNode(CursorTrail source)
|
public TrailDrawNode(CursorTrail source)
|
||||||
: base(source)
|
: base(source)
|
||||||
@ -254,15 +255,17 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
Source.parts.CopyTo(parts, 0);
|
Source.parts.CopyTo(parts, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(IRenderer renderer)
|
||||||
{
|
{
|
||||||
base.Draw(vertexAction);
|
base.Draw(renderer);
|
||||||
|
|
||||||
|
vertexBatch ??= renderer.CreateQuadBatch<TexturedTrailVertex>(max_sprites, 1);
|
||||||
|
|
||||||
shader.Bind();
|
shader.Bind();
|
||||||
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
shader.GetUniform<float>("g_FadeClock").UpdateValue(ref time);
|
||||||
shader.GetUniform<float>("g_FadeExponent").UpdateValue(ref fadeExponent);
|
shader.GetUniform<float>("g_FadeExponent").UpdateValue(ref fadeExponent);
|
||||||
|
|
||||||
texture.TextureGL.Bind();
|
texture.Bind();
|
||||||
|
|
||||||
RectangleF textureRect = texture.GetTextureRect();
|
RectangleF textureRect = texture.GetTextureRect();
|
||||||
|
|
||||||
@ -319,7 +322,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
vertexBatch.Dispose();
|
vertexBatch?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,9 +11,11 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Configuration;
|
using osu.Game.Rulesets.Osu.Configuration;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
@ -112,21 +114,36 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuRulesetConfigManager config)
|
private void load(OsuRulesetConfigManager config, IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle);
|
config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle);
|
||||||
|
|
||||||
RegisterPool<HitCircle, DrawableHitCircle>(10, 100);
|
var osuBeatmap = (OsuBeatmap)beatmap;
|
||||||
|
|
||||||
RegisterPool<Slider, DrawableSlider>(10, 100);
|
RegisterPool<HitCircle, DrawableHitCircle>(20, 100);
|
||||||
RegisterPool<SliderHeadCircle, DrawableSliderHead>(10, 100);
|
|
||||||
RegisterPool<SliderTailCircle, DrawableSliderTail>(10, 100);
|
// handle edge cases where a beatmap has a slider with many repeats.
|
||||||
RegisterPool<SliderTick, DrawableSliderTick>(10, 100);
|
int maxRepeatsOnOneSlider = 0;
|
||||||
RegisterPool<SliderRepeat, DrawableSliderRepeat>(5, 50);
|
int maxTicksOnOneSlider = 0;
|
||||||
|
|
||||||
|
if (osuBeatmap != null)
|
||||||
|
{
|
||||||
|
foreach (var slider in osuBeatmap.HitObjects.OfType<Slider>())
|
||||||
|
{
|
||||||
|
maxRepeatsOnOneSlider = Math.Max(maxRepeatsOnOneSlider, slider.RepeatCount);
|
||||||
|
maxTicksOnOneSlider = Math.Max(maxTicksOnOneSlider, slider.NestedHitObjects.OfType<SliderTick>().Count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterPool<Slider, DrawableSlider>(20, 100);
|
||||||
|
RegisterPool<SliderHeadCircle, DrawableSliderHead>(20, 100);
|
||||||
|
RegisterPool<SliderTailCircle, DrawableSliderTail>(20, 100);
|
||||||
|
RegisterPool<SliderTick, DrawableSliderTick>(Math.Max(maxTicksOnOneSlider, 20), Math.Max(maxTicksOnOneSlider, 200));
|
||||||
|
RegisterPool<SliderRepeat, DrawableSliderRepeat>(Math.Max(maxRepeatsOnOneSlider, 20), Math.Max(maxRepeatsOnOneSlider, 200));
|
||||||
|
|
||||||
RegisterPool<Spinner, DrawableSpinner>(2, 20);
|
RegisterPool<Spinner, DrawableSpinner>(2, 20);
|
||||||
RegisterPool<SpinnerTick, DrawableSpinnerTick>(10, 100);
|
RegisterPool<SpinnerTick, DrawableSpinnerTick>(10, 200);
|
||||||
RegisterPool<SpinnerBonusTick, DrawableSpinnerBonusTick>(10, 100);
|
RegisterPool<SpinnerBonusTick, DrawableSpinnerBonusTick>(10, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new OsuHitObjectLifetimeEntry(hitObject);
|
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new OsuHitObjectLifetimeEntry(hitObject);
|
||||||
@ -173,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
private readonly Action<DrawableOsuJudgement> onLoaded;
|
private readonly Action<DrawableOsuJudgement> onLoaded;
|
||||||
|
|
||||||
public DrawableJudgementPool(HitResult result, Action<DrawableOsuJudgement> onLoaded)
|
public DrawableJudgementPool(HitResult result, Action<DrawableOsuJudgement> onLoaded)
|
||||||
: base(10)
|
: base(20)
|
||||||
{
|
{
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.onLoaded = onLoaded;
|
this.onLoaded = onLoaded;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
@ -9,6 +9,7 @@ using System.Linq;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.Rendering.Dummy;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -55,7 +56,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestAcceptable()
|
public void TestAcceptable()
|
||||||
{
|
{
|
||||||
var context = getContext(new Texture(1920, 1080));
|
var context = getContext(new DummyRenderer().CreateTexture(1920, 1080));
|
||||||
|
|
||||||
Assert.That(check.Run(context), Is.Empty);
|
Assert.That(check.Run(context), Is.Empty);
|
||||||
}
|
}
|
||||||
@ -63,7 +64,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooHighResolution()
|
public void TestTooHighResolution()
|
||||||
{
|
{
|
||||||
var context = getContext(new Texture(3840, 2160));
|
var context = getContext(new DummyRenderer().CreateTexture(3840, 2160));
|
||||||
|
|
||||||
var issues = check.Run(context).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLowResolution()
|
public void TestLowResolution()
|
||||||
{
|
{
|
||||||
var context = getContext(new Texture(640, 480));
|
var context = getContext(new DummyRenderer().CreateTexture(640, 480));
|
||||||
|
|
||||||
var issues = check.Run(context).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooLowResolution()
|
public void TestTooLowResolution()
|
||||||
{
|
{
|
||||||
var context = getContext(new Texture(100, 100));
|
var context = getContext(new DummyRenderer().CreateTexture(100, 100));
|
||||||
|
|
||||||
var issues = check.Run(context).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestTooUncompressed()
|
public void TestTooUncompressed()
|
||||||
{
|
{
|
||||||
var context = getContext(new Texture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3]));
|
var context = getContext(new DummyRenderer().CreateTexture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3]));
|
||||||
|
|
||||||
var issues = check.Run(context).ToList();
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestStreamClosed()
|
public void TestStreamClosed()
|
||||||
{
|
{
|
||||||
var background = new Texture(1920, 1080);
|
var background = new DummyRenderer().CreateTexture(1920, 1080);
|
||||||
var stream = new Mock<MemoryStream>(new byte[1024 * 1024]);
|
var stream = new Mock<MemoryStream>(new byte[1024 * 1024]);
|
||||||
|
|
||||||
var context = getContext(background, stream.Object);
|
var context = getContext(background, stream.Object);
|
||||||
|
@ -206,7 +206,7 @@ namespace osu.Game.Tests.Editing
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assertSnapDistance(float expectedDistance, HitObject hitObject = null)
|
private void assertSnapDistance(float expectedDistance, HitObject hitObject = null)
|
||||||
=> AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()) == expectedDistance);
|
=> AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()), () => Is.EqualTo(expectedDistance));
|
||||||
|
|
||||||
private void assertDurationToDistance(double duration, float expectedDistance)
|
private void assertDurationToDistance(double duration, float expectedDistance)
|
||||||
=> AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(new HitObject(), duration) == expectedDistance);
|
=> AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(new HitObject(), duration) == expectedDistance);
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -11,8 +11,10 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -36,6 +38,9 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private GameHost host { get; set; }
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRetrieveTopLevelSample()
|
public void TestRetrieveTopLevelSample()
|
||||||
{
|
{
|
||||||
@ -202,6 +207,7 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
|
|
||||||
#region IResourceStorageProvider
|
#region IResourceStorageProvider
|
||||||
|
|
||||||
|
public IRenderer Renderer => host.Renderer;
|
||||||
public AudioManager AudioManager => Audio;
|
public AudioManager AudioManager => Audio;
|
||||||
public IResourceStore<byte[]> Files => null;
|
public IResourceStore<byte[]> Files => null;
|
||||||
public new IResourceStore<byte[]> Resources => base.Resources;
|
public new IResourceStore<byte[]> Resources => base.Resources;
|
||||||
|
@ -36,6 +36,23 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single()));
|
Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAudioEqualityCaseSensitivity()
|
||||||
|
{
|
||||||
|
var beatmapSetA = TestResources.CreateTestBeatmapSetInfo(1);
|
||||||
|
var beatmapSetB = TestResources.CreateTestBeatmapSetInfo(1);
|
||||||
|
|
||||||
|
// empty by default so let's set it..
|
||||||
|
beatmapSetA.Beatmaps.First().Metadata.AudioFile = "audio.mp3";
|
||||||
|
beatmapSetB.Beatmaps.First().Metadata.AudioFile = "audio.mp3";
|
||||||
|
|
||||||
|
addAudioFile(beatmapSetA, "abc", "AuDiO.mP3");
|
||||||
|
addAudioFile(beatmapSetB, "abc", "audio.mp3");
|
||||||
|
|
||||||
|
Assert.AreNotEqual(beatmapSetA, beatmapSetB);
|
||||||
|
Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single()));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAudioEqualitySameHash()
|
public void TestAudioEqualitySameHash()
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -27,6 +27,9 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
|||||||
private const string animation_name = "animation";
|
private const string animation_name = "animation";
|
||||||
private const int frame_count = 6;
|
private const int frame_count = 6;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IRenderer renderer { get; set; }
|
||||||
|
|
||||||
[Cached(typeof(IAnimationTimeReference))]
|
[Cached(typeof(IAnimationTimeReference))]
|
||||||
private TestAnimationTimeReference animationTimeReference = new TestAnimationTimeReference();
|
private TestAnimationTimeReference animationTimeReference = new TestAnimationTimeReference();
|
||||||
|
|
||||||
@ -35,9 +38,12 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestAnimationTimeReferenceChange()
|
public void TestAnimationTimeReferenceChange()
|
||||||
{
|
{
|
||||||
ISkin skin = new TestSkin();
|
AddStep("get animation", () =>
|
||||||
|
{
|
||||||
|
ISkin skin = new TestSkin(renderer);
|
||||||
|
Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false));
|
||||||
|
});
|
||||||
|
|
||||||
AddStep("get animation", () => Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false)));
|
|
||||||
AddAssert("frame count correct", () => animation.FrameCount == frame_count);
|
AddAssert("frame count correct", () => animation.FrameCount == frame_count);
|
||||||
assertPlaybackPosition(0);
|
assertPlaybackPosition(0);
|
||||||
|
|
||||||
@ -55,9 +61,16 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
|||||||
{
|
{
|
||||||
private static readonly string[] lookup_names = Enumerable.Range(0, frame_count).Select(frame => $"{animation_name}-{frame}").ToArray();
|
private static readonly string[] lookup_names = Enumerable.Range(0, frame_count).Select(frame => $"{animation_name}-{frame}").ToArray();
|
||||||
|
|
||||||
|
private readonly IRenderer renderer;
|
||||||
|
|
||||||
|
public TestSkin(IRenderer renderer)
|
||||||
|
{
|
||||||
|
this.renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||||
{
|
{
|
||||||
return lookup_names.Contains(componentName) ? Texture.WhitePixel : null;
|
return lookup_names.Contains(componentName) ? renderer.WhitePixel : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
||||||
|
@ -11,6 +11,8 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Graphics.Rendering.Dummy;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
@ -141,6 +143,7 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
|||||||
this.textureStore = textureStore;
|
this.textureStore = textureStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IRenderer Renderer => new DummyRenderer();
|
||||||
public AudioManager AudioManager => null;
|
public AudioManager AudioManager => null;
|
||||||
public IResourceStore<byte[]> Files => null;
|
public IResourceStore<byte[]> Files => null;
|
||||||
public IResourceStore<byte[]> Resources => null;
|
public IResourceStore<byte[]> Resources => null;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -148,6 +149,16 @@ namespace osu.Game.Tests.Online
|
|||||||
Assert.That(apiMod.Settings["speed_change"], Is.EqualTo(1.01d));
|
Assert.That(apiMod.Settings["speed_change"], Is.EqualTo(1.01d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSerialisedModSettingPresence()
|
||||||
|
{
|
||||||
|
var mod = new TestMod();
|
||||||
|
|
||||||
|
mod.TestSetting.Value = mod.TestSetting.Default;
|
||||||
|
JObject serialised = JObject.Parse(JsonConvert.SerializeObject(new APIMod(mod)));
|
||||||
|
Assert.False(serialised.ContainsKey("settings"));
|
||||||
|
}
|
||||||
|
|
||||||
private class TestRuleset : Ruleset
|
private class TestRuleset : Ruleset
|
||||||
{
|
{
|
||||||
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[]
|
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[]
|
||||||
|
@ -15,11 +15,12 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Shaders;
|
using osu.Framework.Graphics.Shaders;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -77,9 +78,9 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
{
|
{
|
||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
dependencies.CacheAs<TextureStore>(ParentTextureStore = new TestTextureStore());
|
dependencies.CacheAs<TextureStore>(ParentTextureStore = new TestTextureStore(parent.Get<GameHost>().Renderer));
|
||||||
dependencies.CacheAs<ISampleStore>(ParentSampleStore = new TestSampleStore());
|
dependencies.CacheAs<ISampleStore>(ParentSampleStore = new TestSampleStore());
|
||||||
dependencies.CacheAs<ShaderManager>(ParentShaderManager = new TestShaderManager());
|
dependencies.CacheAs<ShaderManager>(ParentShaderManager = new TestShaderManager(parent.Get<GameHost>().Renderer));
|
||||||
|
|
||||||
return new DrawableRulesetDependencies(new OsuRuleset(), dependencies);
|
return new DrawableRulesetDependencies(new OsuRuleset(), dependencies);
|
||||||
}
|
}
|
||||||
@ -95,6 +96,11 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
|
|
||||||
private class TestTextureStore : TextureStore
|
private class TestTextureStore : TextureStore
|
||||||
{
|
{
|
||||||
|
public TestTextureStore(IRenderer renderer)
|
||||||
|
: base(renderer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) => null;
|
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) => null;
|
||||||
|
|
||||||
public bool IsDisposed { get; private set; }
|
public bool IsDisposed { get; private set; }
|
||||||
@ -148,8 +154,8 @@ namespace osu.Game.Tests.Rulesets
|
|||||||
|
|
||||||
private class TestShaderManager : ShaderManager
|
private class TestShaderManager : ShaderManager
|
||||||
{
|
{
|
||||||
public TestShaderManager()
|
public TestShaderManager(IRenderer renderer)
|
||||||
: base(new ResourceStore<byte[]>())
|
: base(renderer, new ResourceStore<byte[]>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -6,10 +6,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -21,6 +22,9 @@ namespace osu.Game.Tests.Skins
|
|||||||
[HeadlessTest]
|
[HeadlessTest]
|
||||||
public class TestSceneSkinProvidingContainer : OsuTestScene
|
public class TestSceneSkinProvidingContainer : OsuTestScene
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private IRenderer renderer { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures that the first inserted skin after resetting (via source change)
|
/// Ensures that the first inserted skin after resetting (via source change)
|
||||||
/// is always prioritised over others when providing the same resource.
|
/// is always prioritised over others when providing the same resource.
|
||||||
@ -35,7 +39,7 @@ namespace osu.Game.Tests.Skins
|
|||||||
{
|
{
|
||||||
var sources = new List<TestSkin>();
|
var sources = new List<TestSkin>();
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
sources.Add(new TestSkin());
|
sources.Add(new TestSkin(renderer));
|
||||||
|
|
||||||
mostPrioritisedSource = sources.First();
|
mostPrioritisedSource = sources.First();
|
||||||
|
|
||||||
@ -76,12 +80,19 @@ namespace osu.Game.Tests.Skins
|
|||||||
{
|
{
|
||||||
public const string TEXTURE_NAME = "virtual-texture";
|
public const string TEXTURE_NAME = "virtual-texture";
|
||||||
|
|
||||||
|
private readonly IRenderer renderer;
|
||||||
|
|
||||||
|
public TestSkin(IRenderer renderer)
|
||||||
|
{
|
||||||
|
this.renderer = renderer;
|
||||||
|
}
|
||||||
|
|
||||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new System.NotImplementedException();
|
public Drawable GetDrawableComponent(ISkinComponent component) => throw new System.NotImplementedException();
|
||||||
|
|
||||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||||
{
|
{
|
||||||
if (componentName == TEXTURE_NAME)
|
if (componentName == TEXTURE_NAME)
|
||||||
return Texture.WhitePixel;
|
return renderer.WhitePixel;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Rendering.Dummy;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -55,6 +55,7 @@ namespace osu.Game.Tests.Skins
|
|||||||
lookedUpFileNames = new List<string>();
|
lookedUpFileNames = new List<string>();
|
||||||
mockResourceProvider = new Mock<IStorageResourceProvider>();
|
mockResourceProvider = new Mock<IStorageResourceProvider>();
|
||||||
mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio);
|
mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio);
|
||||||
|
mockResourceProvider.Setup(m => m.Renderer).Returns(new DummyRenderer());
|
||||||
mockResourceStore = new Mock<IResourceStore<byte[]>>();
|
mockResourceStore = new Mock<IResourceStore<byte[]>>();
|
||||||
mockResourceStore.Setup(r => r.Get(It.IsAny<string>()))
|
mockResourceStore.Setup(r => r.Get(It.IsAny<string>()))
|
||||||
.Callback<string>(n => lookedUpFileNames.Add(n))
|
.Callback<string>(n => lookedUpFileNames.Add(n))
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -43,6 +44,9 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IRenderer renderer { get; set; }
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
@ -245,7 +249,7 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
Id = API.LocalUser.Value.Id + 1,
|
Id = API.LocalUser.Value.Id + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(Audio);
|
private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(renderer, Audio);
|
||||||
private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio);
|
private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio);
|
||||||
|
|
||||||
private class TestBackgroundScreenDefault : BackgroundScreenDefault
|
private class TestBackgroundScreenDefault : BackgroundScreenDefault
|
||||||
@ -274,12 +278,15 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
|
|
||||||
private class UniqueBackgroundTestWorkingBeatmap : TestWorkingBeatmap
|
private class UniqueBackgroundTestWorkingBeatmap : TestWorkingBeatmap
|
||||||
{
|
{
|
||||||
public UniqueBackgroundTestWorkingBeatmap(AudioManager audioManager)
|
private readonly IRenderer renderer;
|
||||||
|
|
||||||
|
public UniqueBackgroundTestWorkingBeatmap(IRenderer renderer, AudioManager audioManager)
|
||||||
: base(new Beatmap(), null, audioManager)
|
: base(new Beatmap(), null, audioManager)
|
||||||
{
|
{
|
||||||
|
this.renderer = renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Texture GetBackground() => new Texture(1, 1);
|
protected override Texture GetBackground() => renderer.CreateTexture(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap
|
private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap
|
||||||
|
@ -10,7 +10,7 @@ using NUnit.Framework;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
@ -28,11 +28,9 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private SessionStatics statics { get; set; }
|
private SessionStatics statics { get; set; }
|
||||||
|
|
||||||
[Cached(typeof(LargeTextureStore))]
|
|
||||||
private LookupLoggingTextureStore textureStore = new LookupLoggingTextureStore();
|
|
||||||
|
|
||||||
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
|
||||||
|
|
||||||
|
private LookupLoggingTextureStore textureStore;
|
||||||
private SeasonalBackgroundLoader backgroundLoader;
|
private SeasonalBackgroundLoader backgroundLoader;
|
||||||
private Container backgroundContainer;
|
private Container backgroundContainer;
|
||||||
|
|
||||||
@ -45,15 +43,32 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
"Backgrounds/bg3"
|
"Backgrounds/bg3"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
{
|
||||||
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
|
textureStore = new LookupLoggingTextureStore(dependencies.Get<IRenderer>());
|
||||||
|
dependencies.CacheAs(typeof(LargeTextureStore), textureStore);
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(LargeTextureStore wrappedStore)
|
private void load(LargeTextureStore wrappedStore)
|
||||||
{
|
{
|
||||||
textureStore.AddStore(wrappedStore);
|
textureStore.AddStore(wrappedStore);
|
||||||
|
|
||||||
Add(backgroundContainer = new Container
|
Child = new DependencyProvidingContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
CachedDependencies = new (Type, object)[]
|
||||||
});
|
{
|
||||||
|
(typeof(LargeTextureStore), textureStore)
|
||||||
|
},
|
||||||
|
Child = backgroundContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
@ -193,6 +208,11 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
{
|
{
|
||||||
public List<string> PerformedLookups { get; } = new List<string>();
|
public List<string> PerformedLookups { get; } = new List<string>();
|
||||||
|
|
||||||
|
public LookupLoggingTextureStore(IRenderer renderer)
|
||||||
|
: base(renderer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT)
|
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT)
|
||||||
{
|
{
|
||||||
PerformedLookups.Add(name);
|
PerformedLookups.Add(name);
|
||||||
|
@ -200,10 +200,12 @@ namespace osu.Game.Tests.Visual.Collections
|
|||||||
AddStep("click confirmation", () =>
|
AddStep("click confirmation", () =>
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType<PopupDialogButton>().First());
|
InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType<PopupDialogButton>().First());
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.PressButton(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
assertCollectionCount(0);
|
assertCollectionCount(0);
|
||||||
|
|
||||||
|
AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -190,7 +190,7 @@ namespace osu.Game.Tests.Visual.Components
|
|||||||
AddAssert("track stopped", () => !track.IsRunning);
|
AddAssert("track stopped", () => !track.IsRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null);
|
private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(CreateAPIBeatmapSet());
|
||||||
|
|
||||||
private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack()
|
private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack()
|
||||||
{
|
{
|
||||||
|
@ -56,8 +56,10 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCreateNewBeatmap()
|
public void TestCreateNewBeatmap()
|
||||||
{
|
{
|
||||||
|
AddAssert("status is none", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
|
||||||
AddStep("save beatmap", () => Editor.Save());
|
AddStep("save beatmap", () => Editor.Save());
|
||||||
AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == currentBeatmapSetID)?.Value.DeletePending == false);
|
AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == currentBeatmapSetID)?.Value.DeletePending == false);
|
||||||
|
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -208,6 +210,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
});
|
});
|
||||||
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
|
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
|
||||||
|
|
||||||
|
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
|
||||||
|
|
||||||
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = secondDifficultyName);
|
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = secondDifficultyName);
|
||||||
AddStep("save beatmap", () => Editor.Save());
|
AddStep("save beatmap", () => Editor.Save());
|
||||||
AddAssert("new beatmap persisted", () =>
|
AddAssert("new beatmap persisted", () =>
|
||||||
@ -218,7 +222,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
return beatmap != null
|
return beatmap != null
|
||||||
&& beatmap.DifficultyName == secondDifficultyName
|
&& beatmap.DifficultyName == secondDifficultyName
|
||||||
&& set != null
|
&& set != null
|
||||||
&& set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName));
|
&& set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName) && s.Beatmaps.All(b => s.Status == BeatmapOnlineStatus.LocallyModified));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +298,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
|
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
|
||||||
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
|
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
|
||||||
|
|
||||||
AddAssert("status not copied", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None);
|
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
|
||||||
AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1);
|
AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1);
|
||||||
|
|
||||||
AddStep("save beatmap", () => Editor.Save());
|
AddStep("save beatmap", () => Editor.Save());
|
||||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
AddStep("reset clock", () => Clock.Seek(0));
|
AddStep("reset clock", () => Clock.Seek(0));
|
||||||
|
|
||||||
AddStep("start clock", Clock.Start);
|
AddStep("start clock", () => Clock.Start());
|
||||||
AddAssert("clock running", () => Clock.IsRunning);
|
AddAssert("clock running", () => Clock.IsRunning);
|
||||||
|
|
||||||
AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250));
|
AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250));
|
||||||
@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
||||||
|
|
||||||
AddStep("start clock again", Clock.Start);
|
AddStep("start clock again", () => Clock.Start());
|
||||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,20 +76,20 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
AddStep("reset clock", () => Clock.Seek(0));
|
AddStep("reset clock", () => Clock.Seek(0));
|
||||||
|
|
||||||
AddStep("stop clock", Clock.Stop);
|
AddStep("stop clock", () => Clock.Stop());
|
||||||
AddAssert("clock stopped", () => !Clock.IsRunning);
|
AddAssert("clock stopped", () => !Clock.IsRunning);
|
||||||
|
|
||||||
AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength));
|
AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength));
|
||||||
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
||||||
|
|
||||||
AddStep("start clock again", Clock.Start);
|
AddStep("start clock again", () => Clock.Start());
|
||||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestClampWhenSeekOutsideBeatmapBounds()
|
public void TestClampWhenSeekOutsideBeatmapBounds()
|
||||||
{
|
{
|
||||||
AddStep("stop clock", Clock.Stop);
|
AddStep("stop clock", () => Clock.Stop());
|
||||||
|
|
||||||
AddStep("seek before start time", () => Clock.Seek(-1000));
|
AddStep("seek before start time", () => Clock.Seek(-1000));
|
||||||
AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0);
|
AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0);
|
||||||
|
@ -60,17 +60,17 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
// Forwards
|
// Forwards
|
||||||
AddStep("Seek(0)", () => Clock.Seek(0));
|
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
AddStep("Seek(33)", () => Clock.Seek(33));
|
AddStep("Seek(33)", () => Clock.Seek(33));
|
||||||
AddAssert("Time = 33", () => Clock.CurrentTime == 33);
|
checkTime(33);
|
||||||
AddStep("Seek(89)", () => Clock.Seek(89));
|
AddStep("Seek(89)", () => Clock.Seek(89));
|
||||||
AddAssert("Time = 89", () => Clock.CurrentTime == 89);
|
checkTime(89);
|
||||||
|
|
||||||
// Backwards
|
// Backwards
|
||||||
AddStep("Seek(25)", () => Clock.Seek(25));
|
AddStep("Seek(25)", () => Clock.Seek(25));
|
||||||
AddAssert("Time = 25", () => Clock.CurrentTime == 25);
|
checkTime(25);
|
||||||
AddStep("Seek(0)", () => Clock.Seek(0));
|
AddStep("Seek(0)", () => Clock.Seek(0));
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -83,19 +83,19 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(0), Snap", () => Clock.SeekSnapped(0));
|
AddStep("Seek(0), Snap", () => Clock.SeekSnapped(0));
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
AddStep("Seek(50), Snap", () => Clock.SeekSnapped(50));
|
AddStep("Seek(50), Snap", () => Clock.SeekSnapped(50));
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("Seek(100), Snap", () => Clock.SeekSnapped(100));
|
AddStep("Seek(100), Snap", () => Clock.SeekSnapped(100));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("Seek(175), Snap", () => Clock.SeekSnapped(175));
|
AddStep("Seek(175), Snap", () => Clock.SeekSnapped(175));
|
||||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
checkTime(175);
|
||||||
AddStep("Seek(350), Snap", () => Clock.SeekSnapped(350));
|
AddStep("Seek(350), Snap", () => Clock.SeekSnapped(350));
|
||||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
checkTime(350);
|
||||||
AddStep("Seek(400), Snap", () => Clock.SeekSnapped(400));
|
AddStep("Seek(400), Snap", () => Clock.SeekSnapped(400));
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("Seek(450), Snap", () => Clock.SeekSnapped(450));
|
AddStep("Seek(450), Snap", () => Clock.SeekSnapped(450));
|
||||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
checkTime(450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -108,17 +108,17 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("Seek(24), Snap", () => Clock.SeekSnapped(24));
|
AddStep("Seek(24), Snap", () => Clock.SeekSnapped(24));
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
AddStep("Seek(26), Snap", () => Clock.SeekSnapped(26));
|
AddStep("Seek(26), Snap", () => Clock.SeekSnapped(26));
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("Seek(150), Snap", () => Clock.SeekSnapped(150));
|
AddStep("Seek(150), Snap", () => Clock.SeekSnapped(150));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("Seek(170), Snap", () => Clock.SeekSnapped(170));
|
AddStep("Seek(170), Snap", () => Clock.SeekSnapped(170));
|
||||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
checkTime(175);
|
||||||
AddStep("Seek(274), Snap", () => Clock.SeekSnapped(274));
|
AddStep("Seek(274), Snap", () => Clock.SeekSnapped(274));
|
||||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
checkTime(175);
|
||||||
AddStep("Seek(276), Snap", () => Clock.SeekSnapped(276));
|
AddStep("Seek(276), Snap", () => Clock.SeekSnapped(276));
|
||||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
checkTime(350);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -130,15 +130,15 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("SeekForward", () => Clock.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("SeekForward", () => Clock.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("SeekForward", () => Clock.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 200", () => Clock.CurrentTime == 200);
|
checkTime(200);
|
||||||
AddStep("SeekForward", () => Clock.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("SeekForward", () => Clock.SeekForward());
|
AddStep("SeekForward", () => Clock.SeekForward());
|
||||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
checkTime(450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -150,17 +150,17 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
checkTime(175);
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
checkTime(350);
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
checkTime(450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -174,28 +174,28 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("Seek(49)", () => Clock.Seek(49));
|
AddStep("Seek(49)", () => Clock.Seek(49));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("Seek(49.999)", () => Clock.Seek(49.999));
|
AddStep("Seek(49.999)", () => Clock.Seek(49.999));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("Seek(99)", () => Clock.Seek(99));
|
AddStep("Seek(99)", () => Clock.Seek(99));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("Seek(99.999)", () => Clock.Seek(99.999));
|
AddStep("Seek(99.999)", () => Clock.Seek(99.999));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 150);
|
checkTime(150);
|
||||||
AddStep("Seek(174)", () => Clock.Seek(174));
|
AddStep("Seek(174)", () => Clock.Seek(174));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
checkTime(175);
|
||||||
AddStep("Seek(349)", () => Clock.Seek(349));
|
AddStep("Seek(349)", () => Clock.Seek(349));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
checkTime(350);
|
||||||
AddStep("Seek(399)", () => Clock.Seek(399));
|
AddStep("Seek(399)", () => Clock.Seek(399));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("Seek(449)", () => Clock.Seek(449));
|
AddStep("Seek(449)", () => Clock.Seek(449));
|
||||||
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
AddStep("SeekForward, Snap", () => Clock.SeekForward(true));
|
||||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
checkTime(450);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -208,15 +208,15 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("Seek(450)", () => Clock.Seek(450));
|
AddStep("Seek(450)", () => Clock.Seek(450));
|
||||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
checkTime(350);
|
||||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 150", () => Clock.CurrentTime == 150);
|
checkTime(150);
|
||||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("SeekBackward", () => Clock.SeekBackward());
|
AddStep("SeekBackward", () => Clock.SeekBackward());
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -229,17 +229,17 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("Seek(450)", () => Clock.Seek(450));
|
AddStep("Seek(450)", () => Clock.Seek(450));
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 350", () => Clock.CurrentTime == 350);
|
checkTime(350);
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 175", () => Clock.CurrentTime == 175);
|
checkTime(175);
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 100", () => Clock.CurrentTime == 100);
|
checkTime(100);
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 50", () => Clock.CurrentTime == 50);
|
checkTime(50);
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -253,16 +253,16 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("Seek(451)", () => Clock.Seek(451));
|
AddStep("Seek(451)", () => Clock.Seek(451));
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
checkTime(450);
|
||||||
AddStep("Seek(450.999)", () => Clock.Seek(450.999));
|
AddStep("Seek(450.999)", () => Clock.Seek(450.999));
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 450", () => Clock.CurrentTime == 450);
|
checkTime(450);
|
||||||
AddStep("Seek(401)", () => Clock.Seek(401));
|
AddStep("Seek(401)", () => Clock.Seek(401));
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
AddStep("Seek(401.999)", () => Clock.Seek(401.999));
|
AddStep("Seek(401.999)", () => Clock.Seek(401.999));
|
||||||
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true));
|
||||||
AddAssert("Time = 400", () => Clock.CurrentTime == 400);
|
checkTime(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -297,9 +297,11 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddAssert("Time < lastTime", () => Clock.CurrentTime < lastTime);
|
AddAssert("Time < lastTime", () => Clock.CurrentTime < lastTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddAssert("Time = 0", () => Clock.CurrentTime == 0);
|
checkTime(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkTime(double expectedTime) => AddAssert($"Current time is {expectedTime}", () => Clock.CurrentTime, () => Is.EqualTo(expectedTime));
|
||||||
|
|
||||||
private void reset()
|
private void reset()
|
||||||
{
|
{
|
||||||
AddStep("Reset", () => Clock.Seek(0));
|
AddStep("Reset", () => Clock.Seek(0));
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
private void pressAndCheckTime(Key key, double expectedTime)
|
private void pressAndCheckTime(Key key, double expectedTime)
|
||||||
{
|
{
|
||||||
AddStep($"press {key}", () => InputManager.Key(key));
|
AddStep($"press {key}", () => InputManager.Key(key));
|
||||||
AddUntilStep($"time is {expectedTime}", () => Precision.AlmostEquals(expectedTime, EditorClock.CurrentTime, 1));
|
AddUntilStep($"time is {expectedTime}", () => EditorClock.CurrentTime, () => Is.EqualTo(expectedTime).Within(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Audio;
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
87
osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs
Normal file
87
osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Overlays.Toolbar;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Menus
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneToolbarUserButton : OsuManualInputManagerTestScene
|
||||||
|
{
|
||||||
|
public TestSceneToolbarUserButton()
|
||||||
|
{
|
||||||
|
Container mainContainer;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
mainContainer = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = Toolbar.HEIGHT,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.Black,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.DarkRed,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 2,
|
||||||
|
},
|
||||||
|
new ToolbarUserButton(),
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = Color4.DarkRed,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
AddSliderStep("scale", 0.5, 4, 1, scale => mainContainer.Scale = new Vector2((float)scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLoginLogout()
|
||||||
|
{
|
||||||
|
AddStep("Log out", () => ((DummyAPIAccess)API).Logout());
|
||||||
|
AddStep("Log in", () => ((DummyAPIAccess)API).Login("wang", "jang"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestStates()
|
||||||
|
{
|
||||||
|
AddStep("Log in", () => ((DummyAPIAccess)API).Login("wang", "jang"));
|
||||||
|
|
||||||
|
foreach (var state in Enum.GetValues<APIState>())
|
||||||
|
{
|
||||||
|
AddStep($"Change state to {state}", () => ((DummyAPIAccess)API).SetState(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -432,8 +432,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
var user = playingUsers.Single(u => u.UserID == userId);
|
var user = playingUsers.Single(u => u.UserID == userId);
|
||||||
|
|
||||||
OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull());
|
|
||||||
SpectatorClient.SendEndPlay(userId);
|
SpectatorClient.SendEndPlay(userId);
|
||||||
|
OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull());
|
||||||
|
|
||||||
playingUsers.Remove(user);
|
playingUsers.Remove(user);
|
||||||
});
|
});
|
||||||
|
@ -83,6 +83,20 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Beatmap = dummyBeatmap,
|
Beatmap = dummyBeatmap,
|
||||||
},
|
},
|
||||||
new APIRecentActivity
|
new APIRecentActivity
|
||||||
|
{
|
||||||
|
User = dummyUser,
|
||||||
|
Type = RecentActivityType.BeatmapsetApprove,
|
||||||
|
Approval = BeatmapApproval.Approved,
|
||||||
|
Beatmapset = dummyBeatmap,
|
||||||
|
},
|
||||||
|
new APIRecentActivity
|
||||||
|
{
|
||||||
|
User = dummyUser,
|
||||||
|
Type = RecentActivityType.BeatmapsetApprove,
|
||||||
|
Approval = BeatmapApproval.Loved,
|
||||||
|
Beatmapset = dummyBeatmap,
|
||||||
|
},
|
||||||
|
new APIRecentActivity
|
||||||
{
|
{
|
||||||
User = dummyUser,
|
User = dummyUser,
|
||||||
Type = RecentActivityType.BeatmapsetApprove,
|
Type = RecentActivityType.BeatmapsetApprove,
|
||||||
@ -90,6 +104,13 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Beatmapset = dummyBeatmap,
|
Beatmapset = dummyBeatmap,
|
||||||
},
|
},
|
||||||
new APIRecentActivity
|
new APIRecentActivity
|
||||||
|
{
|
||||||
|
User = dummyUser,
|
||||||
|
Type = RecentActivityType.BeatmapsetApprove,
|
||||||
|
Approval = BeatmapApproval.Ranked,
|
||||||
|
Beatmapset = dummyBeatmap,
|
||||||
|
},
|
||||||
|
new APIRecentActivity
|
||||||
{
|
{
|
||||||
User = dummyUser,
|
User = dummyUser,
|
||||||
Type = RecentActivityType.BeatmapsetDelete,
|
Type = RecentActivityType.BeatmapsetDelete,
|
||||||
|
@ -11,9 +11,11 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mania.Mods;
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
@ -35,16 +37,27 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Cached]
|
[Cached]
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
|
|
||||||
|
[Cached(typeof(IDialogOverlay))]
|
||||||
|
private readonly DialogOverlay dialogOverlay = new DialogOverlay();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
|
||||||
Dependencies.Cache(Realm);
|
Dependencies.Cache(Realm);
|
||||||
|
|
||||||
base.Content.Add(content = new PopoverContainer
|
base.Content.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
new OsuContextMenuContainer
|
||||||
Padding = new MarginPadding(30),
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Child = content = new PopoverContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(30),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dialogOverlay
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +134,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
public void TestSoftDeleteSupport()
|
public void TestSoftDeleteSupport()
|
||||||
{
|
{
|
||||||
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0));
|
||||||
|
AddStep("clear mods", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||||
AddStep("create content", () => Child = new ModPresetColumn
|
AddStep("create content", () => Child = new ModPresetColumn
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -140,9 +154,11 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
foreach (var preset in r.All<ModPreset>())
|
foreach (var preset in r.All<ModPreset>())
|
||||||
preset.DeletePending = true;
|
preset.DeletePending = true;
|
||||||
}));
|
}));
|
||||||
AddUntilStep("no panels visible", () => this.ChildrenOfType<ModPresetPanel>().Count() == 0);
|
AddUntilStep("no panels visible", () => !this.ChildrenOfType<ModPresetPanel>().Any());
|
||||||
|
|
||||||
AddStep("undelete preset", () => Realm.Write(r =>
|
AddStep("select mods from first preset", () => SelectedMods.Value = new Mod[] { new OsuModDoubleTime(), new OsuModHardRock() });
|
||||||
|
|
||||||
|
AddStep("undelete presets", () => Realm.Write(r =>
|
||||||
{
|
{
|
||||||
foreach (var preset in r.All<ModPreset>())
|
foreach (var preset in r.All<ModPreset>())
|
||||||
preset.DeletePending = false;
|
preset.DeletePending = false;
|
||||||
@ -205,6 +221,46 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddUntilStep("popover closed", () => !this.ChildrenOfType<OsuPopover>().Any());
|
AddUntilStep("popover closed", () => !this.ChildrenOfType<OsuPopover>().Any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDeleteFlow()
|
||||||
|
{
|
||||||
|
ModPresetColumn modPresetColumn = null!;
|
||||||
|
|
||||||
|
AddStep("create content", () => Child = modPresetColumn = new ModPresetColumn
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("items loaded", () => modPresetColumn.IsLoaded && modPresetColumn.ItemsLoaded);
|
||||||
|
AddStep("right click first panel", () =>
|
||||||
|
{
|
||||||
|
var panel = this.ChildrenOfType<ModPresetPanel>().First();
|
||||||
|
InputManager.MoveMouseTo(panel);
|
||||||
|
InputManager.Click(MouseButton.Right);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for context menu", () => this.ChildrenOfType<OsuContextMenu>().Any());
|
||||||
|
AddStep("click delete", () =>
|
||||||
|
{
|
||||||
|
var deleteItem = this.ChildrenOfType<DrawableOsuMenuItem>().Single();
|
||||||
|
InputManager.MoveMouseTo(deleteItem);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for dialog", () => dialogOverlay.CurrentDialog is DeleteModPresetDialog);
|
||||||
|
AddStep("hold confirm", () =>
|
||||||
|
{
|
||||||
|
var confirmButton = this.ChildrenOfType<PopupDialogDangerousButton>().Single();
|
||||||
|
InputManager.MoveMouseTo(confirmButton);
|
||||||
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
});
|
||||||
|
AddUntilStep("wait for dialog to close", () => dialogOverlay.CurrentDialog == null);
|
||||||
|
AddStep("release mouse", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
|
AddUntilStep("preset deletion occurred", () => this.ChildrenOfType<ModPresetPanel>().Count() == 2);
|
||||||
|
AddAssert("preset soft-deleted", () => Realm.Run(r => r.All<ModPreset>().Count(preset => preset.DeletePending) == 1));
|
||||||
|
}
|
||||||
|
|
||||||
private ICollection<ModPreset> createTestPresets() => new[]
|
private ICollection<ModPreset> createTestPresets() => new[]
|
||||||
{
|
{
|
||||||
new ModPreset
|
new ModPreset
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
@ -23,6 +26,12 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
[Cached]
|
[Cached]
|
||||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("reset selected mods", () => SelectedMods.SetDefault());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVariousModPresets()
|
public void TestVariousModPresets()
|
||||||
{
|
{
|
||||||
@ -37,6 +46,78 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPresetSelectionStateAfterExternalModChanges()
|
||||||
|
{
|
||||||
|
ModPresetPanel? panel = null;
|
||||||
|
|
||||||
|
AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Width = 0.5f
|
||||||
|
});
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR", () => SelectedMods.Value = new[] { new OsuModHardRock() });
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to DT", () => SelectedMods.Value = new[] { new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is active", () => panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR+customised DT", () => SelectedMods.Value = new Mod[]
|
||||||
|
{
|
||||||
|
new OsuModHardRock(),
|
||||||
|
new OsuModDoubleTime
|
||||||
|
{
|
||||||
|
SpeedChange = { Value = 1.25 }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is active", () => panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("customise mod in place", () => SelectedMods.Value.OfType<OsuModDoubleTime>().Single().SpeedChange.Value = 1.33);
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
|
||||||
|
AddStep("set mods to HD+HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHidden(), new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestActivatingPresetTogglesIncludedMods()
|
||||||
|
{
|
||||||
|
ModPresetPanel? panel = null;
|
||||||
|
|
||||||
|
AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Width = 0.5f
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
|
||||||
|
AddStep("deactivate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(Array.Empty<Mod>());
|
||||||
|
|
||||||
|
AddStep("set different mod", () => SelectedMods.Value = new[] { new OsuModHidden() });
|
||||||
|
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() });
|
||||||
|
|
||||||
|
AddStep("set customised mod", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } });
|
||||||
|
AddStep("activate panel", () => panel.AsNonNull().TriggerClick());
|
||||||
|
assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSelectedModsEquivalentTo(IEnumerable<Mod> mods)
|
||||||
|
=> AddAssert("selected mods changed correctly", () => new HashSet<Mod>(SelectedMods.Value).SetEquals(mods));
|
||||||
|
|
||||||
private static IEnumerable<ModPreset> createTestPresets() => new[]
|
private static IEnumerable<ModPreset> createTestPresets() => new[]
|
||||||
{
|
{
|
||||||
new ModPreset
|
new ModPreset
|
||||||
|
@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddUntilStep("any column dimmed", () => this.ChildrenOfType<ModColumn>().Any(column => !column.Active.Value));
|
AddUntilStep("any column dimmed", () => this.ChildrenOfType<ModColumn>().Any(column => !column.Active.Value));
|
||||||
|
|
||||||
ModColumn lastColumn = null;
|
ModSelectColumn lastColumn = null;
|
||||||
|
|
||||||
AddAssert("last column dimmed", () => !this.ChildrenOfType<ModColumn>().Last().Active.Value);
|
AddAssert("last column dimmed", () => !this.ChildrenOfType<ModColumn>().Last().Active.Value);
|
||||||
AddStep("request scroll to last column", () =>
|
AddStep("request scroll to last column", () =>
|
||||||
|
@ -105,5 +105,11 @@ namespace osu.Game.Audio
|
|||||||
/// Retrieves the audio track.
|
/// Retrieves the audio track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract Track? GetTrack();
|
protected abstract Track? GetTrack();
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
Track?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,8 @@ namespace osu.Game.Beatmaps
|
|||||||
OnlineID = -1;
|
OnlineID = -1;
|
||||||
LastOnlineUpdate = null;
|
LastOnlineUpdate = null;
|
||||||
OnlineMD5Hash = string.Empty;
|
OnlineMD5Hash = string.Empty;
|
||||||
Status = BeatmapOnlineStatus.None;
|
if (Status != BeatmapOnlineStatus.LocallyModified)
|
||||||
|
Status = BeatmapOnlineStatus.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Properties we may not want persisted (but also maybe no harm?)
|
#region Properties we may not want persisted (but also maybe no harm?)
|
||||||
@ -198,8 +199,8 @@ namespace osu.Game.Beatmaps
|
|||||||
Debug.Assert(x.BeatmapSet != null);
|
Debug.Assert(x.BeatmapSet != null);
|
||||||
Debug.Assert(y.BeatmapSet != null);
|
Debug.Assert(y.BeatmapSet != null);
|
||||||
|
|
||||||
string? fileHashX = x.BeatmapSet.Files.FirstOrDefault(f => f.Filename == getFilename(x.Metadata))?.File.Hash;
|
string? fileHashX = x.BeatmapSet.GetFile(getFilename(x.Metadata))?.File.Hash;
|
||||||
string? fileHashY = y.BeatmapSet.Files.FirstOrDefault(f => f.Filename == getFilename(y.Metadata))?.File.Hash;
|
string? fileHashY = y.BeatmapSet.GetFile(getFilename(y.Metadata))?.File.Hash;
|
||||||
|
|
||||||
return fileHashX == fileHashY;
|
return fileHashX == fileHashY;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ namespace osu.Game.Beatmaps
|
|||||||
stream.Seek(0, SeekOrigin.Begin);
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
// AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity.
|
// AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity.
|
||||||
var existingFileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase));
|
var existingFileInfo = beatmapInfo.Path != null ? setInfo.GetFile(beatmapInfo.Path) : null;
|
||||||
string targetFilename = createBeatmapFilenameFromMetadata(beatmapInfo);
|
string targetFilename = createBeatmapFilenameFromMetadata(beatmapInfo);
|
||||||
|
|
||||||
// ensure that two difficulties from the set don't point at the same beatmap file.
|
// ensure that two difficulties from the set don't point at the same beatmap file.
|
||||||
@ -313,9 +313,12 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
beatmapInfo.MD5Hash = stream.ComputeMD5Hash();
|
||||||
beatmapInfo.Hash = stream.ComputeSHA2Hash();
|
beatmapInfo.Hash = stream.ComputeSHA2Hash();
|
||||||
|
|
||||||
|
beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified;
|
||||||
|
|
||||||
AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo));
|
AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo));
|
||||||
|
|
||||||
setInfo.Hash = beatmapImporter.ComputeHash(setInfo);
|
setInfo.Hash = beatmapImporter.ComputeHash(setInfo);
|
||||||
|
setInfo.Status = BeatmapOnlineStatus.LocallyModified;
|
||||||
|
|
||||||
Realm.Write(r =>
|
Realm.Write(r =>
|
||||||
{
|
{
|
||||||
|
@ -3,13 +3,23 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
public enum BeatmapOnlineStatus
|
public enum BeatmapOnlineStatus
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is a special status given when local changes are made via the editor.
|
||||||
|
/// Once in this state, online status changes should be ignored unless the beatmap is reverted or submitted.
|
||||||
|
/// </summary>
|
||||||
|
[Description("Local")]
|
||||||
|
[LocalisableDescription(typeof(SongSelectStrings), nameof(SongSelectStrings.LocallyModified))]
|
||||||
|
LocallyModified = -4,
|
||||||
|
|
||||||
None = -3,
|
None = -3,
|
||||||
|
|
||||||
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusGraveyard))]
|
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusGraveyard))]
|
||||||
|
@ -84,13 +84,6 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
|
||||||
/// The path returned is relative to the user file storage.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">The name of the file to get the storage path of.</param>
|
|
||||||
public string? GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.File.GetStoragePath();
|
|
||||||
|
|
||||||
public bool Equals(BeatmapSetInfo? other)
|
public bool Equals(BeatmapSetInfo? other)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(this, other)) return true;
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
33
osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs
Normal file
33
osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Extensions;
|
||||||
|
using osu.Game.Models;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps
|
||||||
|
{
|
||||||
|
public static class BeatmapSetInfoExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
||||||
|
/// The path returned is relative to the user file storage.
|
||||||
|
/// The lookup is case insensitive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The model to operate on.</param>
|
||||||
|
/// <param name="filename">The name of the file to get the storage path of.</param>
|
||||||
|
public static string? GetPathForFile(this IHasRealmFiles model, string filename) => model.GetFile(filename)?.File.GetStoragePath();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the file usage for the file in this beatmapset with the given filename, if any exists, otherwise null.
|
||||||
|
/// The path returned is relative to the user file storage.
|
||||||
|
/// The lookup is case insensitive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The model to operate on.</param>
|
||||||
|
/// <param name="filename">The name of the file to get the storage path of.</param>
|
||||||
|
public static RealmNamedFileUsage? GetFile(this IHasRealmFiles model, string filename) =>
|
||||||
|
model.Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
@ -51,6 +52,9 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queue an update for a beatmap set.
|
/// Queue an update for a beatmap set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This may happen during initial import, or at a later stage in response to a user action or server event.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="beatmapSet">The beatmap set to update. Updates will be applied directly (so a transaction should be started if this instance is managed).</param>
|
/// <param name="beatmapSet">The beatmap set to update. Updates will be applied directly (so a transaction should be started if this instance is managed).</param>
|
||||||
/// <param name="preferOnlineFetch">Whether metadata from an online source should be preferred. If <c>true</c>, the local cache will be skipped to ensure the freshest data state possible.</param>
|
/// <param name="preferOnlineFetch">Whether metadata from an online source should be preferred. If <c>true</c>, the local cache will be skipped to ensure the freshest data state possible.</param>
|
||||||
public void Update(BeatmapSetInfo beatmapSet, bool preferOnlineFetch)
|
public void Update(BeatmapSetInfo beatmapSet, bool preferOnlineFetch)
|
||||||
@ -89,21 +93,26 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
if (res != null)
|
if (res != null)
|
||||||
{
|
{
|
||||||
beatmapInfo.Status = res.Status;
|
beatmapInfo.OnlineID = res.OnlineID;
|
||||||
|
|
||||||
Debug.Assert(beatmapInfo.BeatmapSet != null);
|
|
||||||
|
|
||||||
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
|
|
||||||
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
|
|
||||||
beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked;
|
|
||||||
beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted;
|
|
||||||
|
|
||||||
beatmapInfo.OnlineMD5Hash = res.MD5Hash;
|
beatmapInfo.OnlineMD5Hash = res.MD5Hash;
|
||||||
beatmapInfo.LastOnlineUpdate = res.LastUpdated;
|
beatmapInfo.LastOnlineUpdate = res.LastUpdated;
|
||||||
|
|
||||||
beatmapInfo.OnlineID = res.OnlineID;
|
Debug.Assert(beatmapInfo.BeatmapSet != null);
|
||||||
|
beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID;
|
||||||
|
|
||||||
beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
|
// Some metadata should only be applied if there's no local changes.
|
||||||
|
if (shouldSaveOnlineMetadata(beatmapInfo))
|
||||||
|
{
|
||||||
|
beatmapInfo.Status = res.Status;
|
||||||
|
beatmapInfo.Metadata.Author.OnlineID = res.AuthorID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata))
|
||||||
|
{
|
||||||
|
beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None;
|
||||||
|
beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked;
|
||||||
|
beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted;
|
||||||
|
}
|
||||||
|
|
||||||
logForModel(set, $"Online retrieval mapped {beatmapInfo} to {res.OnlineBeatmapSetID} / {res.OnlineID}.");
|
logForModel(set, $"Online retrieval mapped {beatmapInfo} to {res.OnlineBeatmapSetID} / {res.OnlineID}.");
|
||||||
}
|
}
|
||||||
@ -202,19 +211,26 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
var status = (BeatmapOnlineStatus)reader.GetByte(2);
|
var status = (BeatmapOnlineStatus)reader.GetByte(2);
|
||||||
|
|
||||||
beatmapInfo.Status = status;
|
// Some metadata should only be applied if there's no local changes.
|
||||||
|
if (shouldSaveOnlineMetadata(beatmapInfo))
|
||||||
|
{
|
||||||
|
beatmapInfo.Status = status;
|
||||||
|
beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
|
||||||
|
}
|
||||||
|
|
||||||
Debug.Assert(beatmapInfo.BeatmapSet != null);
|
|
||||||
|
|
||||||
beatmapInfo.BeatmapSet.Status = status;
|
|
||||||
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
|
|
||||||
// TODO: DateSubmitted and DateRanked are not provided by local cache.
|
// TODO: DateSubmitted and DateRanked are not provided by local cache.
|
||||||
beatmapInfo.OnlineID = reader.GetInt32(1);
|
beatmapInfo.OnlineID = reader.GetInt32(1);
|
||||||
beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3);
|
|
||||||
|
|
||||||
beatmapInfo.OnlineMD5Hash = reader.GetString(4);
|
beatmapInfo.OnlineMD5Hash = reader.GetString(4);
|
||||||
beatmapInfo.LastOnlineUpdate = reader.GetDateTimeOffset(5);
|
beatmapInfo.LastOnlineUpdate = reader.GetDateTimeOffset(5);
|
||||||
|
|
||||||
|
Debug.Assert(beatmapInfo.BeatmapSet != null);
|
||||||
|
beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0);
|
||||||
|
|
||||||
|
if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata))
|
||||||
|
{
|
||||||
|
beatmapInfo.BeatmapSet.Status = status;
|
||||||
|
}
|
||||||
|
|
||||||
logForModel(set, $"Cached local retrieval for {beatmapInfo}.");
|
logForModel(set, $"Cached local retrieval for {beatmapInfo}.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -233,6 +249,12 @@ namespace osu.Game.Beatmaps
|
|||||||
private void logForModel(BeatmapSetInfo set, string message) =>
|
private void logForModel(BeatmapSetInfo set, string message) =>
|
||||||
RealmArchiveModelImporter<BeatmapSetInfo>.LogForModel(set, $"[{nameof(BeatmapUpdaterMetadataLookup)}] {message}");
|
RealmArchiveModelImporter<BeatmapSetInfo>.LogForModel(set, $"[{nameof(BeatmapUpdaterMetadataLookup)}] {message}");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check whether the provided beatmap is in a state where online "ranked" status metadata should be saved against it.
|
||||||
|
/// Handles the case where a user may have locally modified a beatmap in the editor and expects the local status to stick.
|
||||||
|
/// </summary>
|
||||||
|
private static bool shouldSaveOnlineMetadata(BeatmapInfo beatmapInfo) => beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
cacheDownloadRequest?.Dispose();
|
cacheDownloadRequest?.Dispose();
|
||||||
|
@ -6,15 +6,18 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Drawables
|
namespace osu.Game.Beatmaps.Drawables
|
||||||
{
|
{
|
||||||
public class BeatmapSetOnlineStatusPill : CircularContainer
|
public class BeatmapSetOnlineStatusPill : CircularContainer, IHasTooltip
|
||||||
{
|
{
|
||||||
private BeatmapOnlineStatus status;
|
private BeatmapOnlineStatus status;
|
||||||
|
|
||||||
@ -96,5 +99,19 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
background.Colour = OsuColour.ForBeatmapSetOnlineStatus(Status) ?? colourProvider?.Light1 ?? colours.GreySeaFoamLighter;
|
background.Colour = OsuColour.ForBeatmapSetOnlineStatus(Status) ?? colourProvider?.Light1 ?? colours.GreySeaFoamLighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LocalisableString TooltipText
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Status)
|
||||||
|
{
|
||||||
|
case BeatmapOnlineStatus.LocallyModified:
|
||||||
|
return SongSelectStrings.LocallyModifiedTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
|
|||||||
// another async load might have completed before this one.
|
// another async load might have completed before this one.
|
||||||
// if so, do not make any changes.
|
// if so, do not make any changes.
|
||||||
if (loadedPreview != previewTrack)
|
if (loadedPreview != previewTrack)
|
||||||
|
{
|
||||||
|
loadedPreview.Dispose();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AddInternal(loadedPreview);
|
AddInternal(loadedPreview);
|
||||||
toggleLoading(false);
|
toggleLoading(false);
|
||||||
|
@ -9,6 +9,8 @@ using System.Linq;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
|
using osu.Framework.Graphics.Rendering.Dummy;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
@ -56,7 +58,7 @@ namespace osu.Game.Beatmaps
|
|||||||
this.resources = resources;
|
this.resources = resources;
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.files = files;
|
this.files = files;
|
||||||
largeTextureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(files));
|
largeTextureStore = new LargeTextureStore(host?.Renderer ?? new DummyRenderer(), host?.CreateTextureLoaderStore(files));
|
||||||
this.trackStore = trackStore;
|
this.trackStore = trackStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +112,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore;
|
TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore;
|
||||||
ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
|
ITrackStore IBeatmapResourceProvider.Tracks => trackStore;
|
||||||
|
IRenderer IStorageResourceProvider.Renderer => host?.Renderer ?? new DummyRenderer();
|
||||||
AudioManager IStorageResourceProvider.AudioManager => audioManager;
|
AudioManager IStorageResourceProvider.AudioManager => audioManager;
|
||||||
RealmAccess IStorageResourceProvider.RealmAccess => null;
|
RealmAccess IStorageResourceProvider.RealmAccess => null;
|
||||||
IResourceStore<byte[]> IStorageResourceProvider.Files => files;
|
IResourceStore<byte[]> IStorageResourceProvider.Files => files;
|
||||||
|
@ -3,33 +3,17 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Overlays.Dialog;
|
using osu.Game.Overlays.Dialog;
|
||||||
|
|
||||||
namespace osu.Game.Collections
|
namespace osu.Game.Collections
|
||||||
{
|
{
|
||||||
public class DeleteCollectionDialog : PopupDialog
|
public class DeleteCollectionDialog : DeleteConfirmationDialog
|
||||||
{
|
{
|
||||||
public DeleteCollectionDialog(Live<BeatmapCollection> collection, Action deleteAction)
|
public DeleteCollectionDialog(Live<BeatmapCollection> collection, Action deleteAction)
|
||||||
{
|
{
|
||||||
HeaderText = "Confirm deletion of";
|
|
||||||
BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})");
|
BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})");
|
||||||
|
DeleteAction = deleteAction;
|
||||||
Icon = FontAwesome.Regular.TrashAlt;
|
|
||||||
|
|
||||||
Buttons = new PopupDialogButton[]
|
|
||||||
{
|
|
||||||
new PopupDialogOkButton
|
|
||||||
{
|
|
||||||
Text = @"Yes. Go for it.",
|
|
||||||
Action = deleteAction
|
|
||||||
},
|
|
||||||
new PopupDialogCancelButton
|
|
||||||
{
|
|
||||||
Text = @"No! Abort mission!",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,20 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum BackgroundSource
|
public enum BackgroundSource
|
||||||
{
|
{
|
||||||
|
[LocalisableDescription(typeof(SkinSettingsStrings), nameof(SkinSettingsStrings.SkinSectionHeader))]
|
||||||
Skin,
|
Skin,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.BeatmapHeader))]
|
||||||
Beatmap,
|
Beatmap,
|
||||||
|
|
||||||
[Description("Beatmap (with storyboard / video)")]
|
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.BeatmapWithStoryboard))]
|
||||||
BeatmapWithStoryboard,
|
BeatmapWithStoryboard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,20 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum DiscordRichPresenceMode
|
public enum DiscordRichPresenceMode
|
||||||
{
|
{
|
||||||
|
[LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.DiscordPresenceOff))]
|
||||||
Off,
|
Off,
|
||||||
|
|
||||||
[Description("Hide identifiable information")]
|
[LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.HideIdentifiableInformation))]
|
||||||
Limited,
|
Limited,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.DiscordPresenceFull))]
|
||||||
Full
|
Full
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,20 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum HUDVisibilityMode
|
public enum HUDVisibilityMode
|
||||||
{
|
{
|
||||||
|
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.NeverShowHUD))]
|
||||||
Never,
|
Never,
|
||||||
|
|
||||||
[Description("Hide during gameplay")]
|
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.HideDuringGameplay))]
|
||||||
HideDuringGameplay,
|
HideDuringGameplay,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.AlwaysShowHUD))]
|
||||||
Always
|
Always
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,17 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum RandomSelectAlgorithm
|
public enum RandomSelectAlgorithm
|
||||||
{
|
{
|
||||||
[Description("Never repeat")]
|
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.NeverRepeat))]
|
||||||
RandomPermutation,
|
RandomPermutation,
|
||||||
|
|
||||||
[Description("True Random")]
|
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.TrueRandom))]
|
||||||
Random
|
Random
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum ScalingMode
|
public enum ScalingMode
|
||||||
{
|
{
|
||||||
|
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScalingOff))]
|
||||||
Off,
|
Off,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverything))]
|
||||||
Everything,
|
Everything,
|
||||||
|
|
||||||
[Description("Excluding overlays")]
|
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverythingExcludingOverlays))]
|
||||||
ExcludeOverlays,
|
ExcludeOverlays,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleGameplay))]
|
||||||
Gameplay,
|
Gameplay,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,17 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum ScreenshotFormat
|
public enum ScreenshotFormat
|
||||||
{
|
{
|
||||||
[Description("JPG (web-friendly)")]
|
[LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.Jpg))]
|
||||||
Jpg = 1,
|
Jpg = 1,
|
||||||
|
|
||||||
[Description("PNG (lossless)")]
|
[LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.Png))]
|
||||||
Png = 2
|
Png = 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public enum SeasonalBackgroundMode
|
public enum SeasonalBackgroundMode
|
||||||
@ -10,16 +13,19 @@ namespace osu.Game.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seasonal backgrounds are shown regardless of season, if at all available.
|
/// Seasonal backgrounds are shown regardless of season, if at all available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.AlwaysSeasonalBackground))]
|
||||||
Always,
|
Always,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seasonal backgrounds are shown only during their corresponding season.
|
/// Seasonal backgrounds are shown only during their corresponding season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.SometimesSeasonalBackground))]
|
||||||
Sometimes,
|
Sometimes,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seasonal backgrounds are never shown.
|
/// Seasonal backgrounds are never shown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.NeverSeasonalBackground))]
|
||||||
Never
|
Never
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
@ -11,8 +12,16 @@ namespace osu.Game.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHasRealmFiles
|
public interface IHasRealmFiles
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Available files in this model, with locally filenames.
|
||||||
|
/// When performing lookups, consider using <see cref="BeatmapSetInfoExtensions.GetFile"/> or <see cref="BeatmapSetInfoExtensions.GetPathForFile"/> to do case-insensitive lookups.
|
||||||
|
/// </summary>
|
||||||
IList<RealmNamedFileUsage> Files { get; }
|
IList<RealmNamedFileUsage> Files { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A combined hash representing the model, based on the files it contains.
|
||||||
|
/// Implementation specific.
|
||||||
|
/// </summary>
|
||||||
string Hash { get; set; }
|
string Hash { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -27,27 +25,30 @@ namespace osu.Game.Database
|
|||||||
public class LegacyImportManager : Component
|
public class LegacyImportManager : Component
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skins { get; set; }
|
private SkinManager skins { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private ScoreManager scores { get; set; }
|
private ScoreManager scores { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private OsuGame game { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IDialogOverlay dialogOverlay { get; set; }
|
private OsuGame? game { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private RealmAccess realmAccess { get; set; }
|
private IDialogOverlay dialogOverlay { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved]
|
||||||
private DesktopGameHost desktopGameHost { get; set; }
|
private RealmAccess realmAccess { get; set; } = null!;
|
||||||
|
|
||||||
private StableStorage cachedStorage;
|
[Resolved(canBeNull: true)] // canBeNull required while we remain on mono for mobile platforms.
|
||||||
|
private DesktopGameHost? desktopGameHost { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private INotificationOverlay? notifications { get; set; }
|
||||||
|
|
||||||
|
private StableStorage? cachedStorage;
|
||||||
|
|
||||||
public bool SupportsImportFromStable => RuntimeInfo.IsDesktop;
|
public bool SupportsImportFromStable => RuntimeInfo.IsDesktop;
|
||||||
|
|
||||||
@ -98,6 +99,9 @@ namespace osu.Game.Database
|
|||||||
stableStorage = GetCurrentStableStorage();
|
stableStorage = GetCurrentStableStorage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stableStorage == null)
|
||||||
|
return;
|
||||||
|
|
||||||
var importTasks = new List<Task>();
|
var importTasks = new List<Task>();
|
||||||
|
|
||||||
Task beatmapImportTask = Task.CompletedTask;
|
Task beatmapImportTask = Task.CompletedTask;
|
||||||
@ -108,7 +112,14 @@ namespace osu.Game.Database
|
|||||||
importTasks.Add(new LegacySkinImporter(skins).ImportFromStableAsync(stableStorage));
|
importTasks.Add(new LegacySkinImporter(skins).ImportFromStableAsync(stableStorage));
|
||||||
|
|
||||||
if (content.HasFlagFast(StableContent.Collections))
|
if (content.HasFlagFast(StableContent.Collections))
|
||||||
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyCollectionImporter(realmAccess).ImportFromStorage(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
{
|
||||||
|
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyCollectionImporter(realmAccess)
|
||||||
|
{
|
||||||
|
// Other legacy importers import via model managers which handle the posting of notifications.
|
||||||
|
// Collections are an exception.
|
||||||
|
PostNotification = n => notifications?.Post(n)
|
||||||
|
}.ImportFromStorage(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
||||||
|
}
|
||||||
|
|
||||||
if (content.HasFlagFast(StableContent.Scores))
|
if (content.HasFlagFast(StableContent.Scores))
|
||||||
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyScoreImporter(scores).ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyScoreImporter(scores).ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
|
||||||
@ -116,7 +127,7 @@ namespace osu.Game.Database
|
|||||||
await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false);
|
await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StableStorage GetCurrentStableStorage()
|
public StableStorage? GetCurrentStableStorage()
|
||||||
{
|
{
|
||||||
if (cachedStorage != null)
|
if (cachedStorage != null)
|
||||||
return cachedStorage;
|
return cachedStorage;
|
||||||
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
@ -79,7 +80,7 @@ namespace osu.Game.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void AddFile(TModel item, Stream contents, string filename, Realm realm)
|
public void AddFile(TModel item, Stream contents, string filename, Realm realm)
|
||||||
{
|
{
|
||||||
var existing = item.Files.FirstOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase));
|
var existing = item.GetFile(filename);
|
||||||
|
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
{
|
{
|
||||||
|
@ -25,6 +25,7 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Models;
|
using osu.Game.Models;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using Realms;
|
using Realms;
|
||||||
@ -172,6 +173,11 @@ namespace osu.Game.Database
|
|||||||
if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal))
|
if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal))
|
||||||
Filename += realm_extension;
|
Filename += realm_extension;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (!DebugUtils.IsNUnitRunning)
|
||||||
|
applyFilenameSchemaSuffix(ref Filename);
|
||||||
|
#endif
|
||||||
|
|
||||||
string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}";
|
string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}";
|
||||||
|
|
||||||
// Attempt to recover a newer database version if available.
|
// Attempt to recover a newer database version if available.
|
||||||
@ -211,6 +217,51 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Some developers may be annoyed if a newer version migration (ie. caused by testing a pull request)
|
||||||
|
/// cause their test database to be unusable with previous versions.
|
||||||
|
/// To get around this, store development databases against their realm version.
|
||||||
|
/// Note that this means changes made on newer realm versions will disappear.
|
||||||
|
/// </summary>
|
||||||
|
private void applyFilenameSchemaSuffix(ref string filename)
|
||||||
|
{
|
||||||
|
string originalFilename = filename;
|
||||||
|
|
||||||
|
filename = getVersionedFilename(schema_version);
|
||||||
|
|
||||||
|
// First check if the current realm version already exists...
|
||||||
|
if (storage.Exists(filename))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check for a previous version we can use as a base database to migrate from...
|
||||||
|
for (int i = schema_version - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
string previousFilename = getVersionedFilename(i);
|
||||||
|
|
||||||
|
if (storage.Exists(previousFilename))
|
||||||
|
{
|
||||||
|
copyPreviousVersion(previousFilename, filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, check for a non-versioned file exists (aka before this method was added)...
|
||||||
|
if (storage.Exists(originalFilename))
|
||||||
|
copyPreviousVersion(originalFilename, filename);
|
||||||
|
|
||||||
|
void copyPreviousVersion(string previousFilename, string newFilename)
|
||||||
|
{
|
||||||
|
using (var previous = storage.GetStream(previousFilename))
|
||||||
|
using (var current = storage.CreateFileSafely(newFilename))
|
||||||
|
{
|
||||||
|
Logger.Log(@$"Copying previous realm database {previousFilename} to {newFilename} for migration to schema version {schema_version}");
|
||||||
|
previous.CopyTo(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string getVersionedFilename(int version) => originalFilename.Replace(realm_extension, $"_{version}{realm_extension}");
|
||||||
|
}
|
||||||
|
|
||||||
private void attemptRecoverFromFile(string recoveryFilename)
|
private void attemptRecoverFromFile(string recoveryFilename)
|
||||||
{
|
{
|
||||||
Logger.Log($@"Performing recovery from {recoveryFilename}", LoggingTarget.Database);
|
Logger.Log($@"Performing recovery from {recoveryFilename}", LoggingTarget.Database);
|
||||||
@ -292,6 +343,11 @@ namespace osu.Game.Database
|
|||||||
foreach (var s in pendingDeleteSkins)
|
foreach (var s in pendingDeleteSkins)
|
||||||
realm.Remove(s);
|
realm.Remove(s);
|
||||||
|
|
||||||
|
var pendingDeletePresets = realm.All<ModPreset>().Where(s => s.DeletePending);
|
||||||
|
|
||||||
|
foreach (var s in pendingDeletePresets)
|
||||||
|
realm.Remove(s);
|
||||||
|
|
||||||
transaction.Commit();
|
transaction.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,8 @@ using osu.Framework.Graphics.Colour;
|
|||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics.Batches;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.OpenGL.Buffers;
|
using osu.Framework.Graphics.Rendering.Vertices;
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
|
||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Backgrounds
|
namespace osu.Game.Graphics.Backgrounds
|
||||||
@ -88,7 +87,7 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
|
|
||||||
private Random stableRandom;
|
private Random stableRandom;
|
||||||
private IShader shader;
|
private IShader shader;
|
||||||
private readonly Texture texture;
|
private Texture texture;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a new triangle visualisation.
|
/// Construct a new triangle visualisation.
|
||||||
@ -98,13 +97,12 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
{
|
{
|
||||||
if (seed != null)
|
if (seed != null)
|
||||||
stableRandom = new Random(seed.Value);
|
stableRandom = new Random(seed.Value);
|
||||||
|
|
||||||
texture = Texture.WhitePixel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ShaderManager shaders)
|
private void load(IRenderer renderer, ShaderManager shaders)
|
||||||
{
|
{
|
||||||
|
texture = renderer.WhitePixel;
|
||||||
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
|
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,8 +182,8 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
|
|
||||||
private void addTriangles(bool randomY)
|
private void addTriangles(bool randomY)
|
||||||
{
|
{
|
||||||
// limited by the maximum size of QuadVertexBuffer for safety.
|
// Limited by the maximum size of QuadVertexBuffer for safety.
|
||||||
const int max_triangles = QuadVertexBuffer<TexturedVertex2D>.MAX_QUADS;
|
const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2);
|
||||||
|
|
||||||
AimCount = (int)Math.Min(max_triangles, (DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio));
|
AimCount = (int)Math.Min(max_triangles, (DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio));
|
||||||
|
|
||||||
@ -251,7 +249,7 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
private readonly List<TriangleParticle> parts = new List<TriangleParticle>();
|
||||||
private Vector2 size;
|
private Vector2 size;
|
||||||
|
|
||||||
private QuadBatch<TexturedVertex2D> vertexBatch;
|
private IVertexBatch<TexturedVertex2D> vertexBatch;
|
||||||
|
|
||||||
public TrianglesDrawNode(Triangles source)
|
public TrianglesDrawNode(Triangles source)
|
||||||
: base(source)
|
: base(source)
|
||||||
@ -270,14 +268,14 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
parts.AddRange(Source.parts);
|
parts.AddRange(Source.parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(Action<TexturedVertex2D> vertexAction)
|
public override void Draw(IRenderer renderer)
|
||||||
{
|
{
|
||||||
base.Draw(vertexAction);
|
base.Draw(renderer);
|
||||||
|
|
||||||
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
|
if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount))
|
||||||
{
|
{
|
||||||
vertexBatch?.Dispose();
|
vertexBatch?.Dispose();
|
||||||
vertexBatch = new QuadBatch<TexturedVertex2D>(Source.AimCount, 1);
|
vertexBatch = renderer.CreateQuadBatch<TexturedVertex2D>(Source.AimCount, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
shader.Bind();
|
shader.Bind();
|
||||||
@ -297,7 +295,7 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
ColourInfo colourInfo = DrawColourInfo.Colour;
|
ColourInfo colourInfo = DrawColourInfo.Colour;
|
||||||
colourInfo.ApplyChild(particle.Colour);
|
colourInfo.ApplyChild(particle.Colour);
|
||||||
|
|
||||||
DrawTriangle(
|
renderer.DrawTriangle(
|
||||||
texture,
|
texture,
|
||||||
triangle,
|
triangle,
|
||||||
colourInfo,
|
colourInfo,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
using osu.Framework.Graphics.Rendering.Vertices;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Graphics.ES30;
|
using osuTK.Graphics.ES30;
|
||||||
|
@ -137,6 +137,9 @@ namespace osu.Game.Graphics
|
|||||||
{
|
{
|
||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
|
case BeatmapOnlineStatus.LocallyModified:
|
||||||
|
return Color4.OrangeRed;
|
||||||
|
|
||||||
case BeatmapOnlineStatus.Ranked:
|
case BeatmapOnlineStatus.Ranked:
|
||||||
case BeatmapOnlineStatus.Approved:
|
case BeatmapOnlineStatus.Approved:
|
||||||
return Color4Extensions.FromHex(@"b3ff66");
|
return Color4Extensions.FromHex(@"b3ff66");
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@ -89,7 +89,7 @@ namespace osu.Game.Graphics
|
|||||||
currentTime = source.Time.Current;
|
currentTime = source.Time.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Blit(Action<TexturedVertex2D> vertexAction)
|
protected override void Blit(IRenderer renderer)
|
||||||
{
|
{
|
||||||
double time = currentTime - startTime;
|
double time = currentTime - startTime;
|
||||||
|
|
||||||
@ -112,9 +112,9 @@ namespace osu.Game.Graphics
|
|||||||
Vector2Extensions.Transform(rect.BottomRight, DrawInfo.Matrix)
|
Vector2Extensions.Transform(rect.BottomRight, DrawInfo.Matrix)
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction,
|
renderer.DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha),
|
||||||
new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
||||||
null, TextureCoords);
|
textureCoords: TextureCoords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ using System;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@ -107,7 +107,7 @@ namespace osu.Game.Graphics
|
|||||||
sourceSize = Source.DrawSize;
|
sourceSize = Source.DrawSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Blit(Action<TexturedVertex2D> vertexAction)
|
protected override void Blit(IRenderer renderer)
|
||||||
{
|
{
|
||||||
foreach (var p in particles)
|
foreach (var p in particles)
|
||||||
{
|
{
|
||||||
@ -136,9 +136,9 @@ namespace osu.Game.Graphics
|
|||||||
transformPosition(rect.BottomRight, rect.Centre, angle)
|
transformPosition(rect.BottomRight, rect.Centre, angle)
|
||||||
);
|
);
|
||||||
|
|
||||||
DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction,
|
renderer.DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha),
|
||||||
new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
|
||||||
null, TextureCoords);
|
textureCoords: TextureCoords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,10 +3,9 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.OpenGL.Vertices;
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Shaders;
|
using osu.Framework.Graphics.Shaders;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
|
||||||
@ -57,11 +56,11 @@ namespace osu.Game.Graphics.Sprites
|
|||||||
progress = source.animationProgress;
|
progress = source.animationProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Blit(Action<TexturedVertex2D> vertexAction)
|
protected override void Blit(IRenderer renderer)
|
||||||
{
|
{
|
||||||
Shader.GetUniform<float>("progress").UpdateValue(ref progress);
|
GetAppropriateShader(renderer).GetUniform<float>("progress").UpdateValue(ref progress);
|
||||||
|
|
||||||
base.Blit(vertexAction);
|
base.Blit(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool CanDrawOpaqueInterior => false;
|
protected override bool CanDrawOpaqueInterior => false;
|
||||||
|
@ -167,6 +167,11 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
|
// If the game goes into a suspended state (ie. debugger attached or backgrounded on a mobile device)
|
||||||
|
// we want to ignore really long periods of no processing.
|
||||||
|
if (updateClock.ElapsedFrameTime > 10000)
|
||||||
|
return;
|
||||||
|
|
||||||
mainContent.Width = Math.Max(mainContent.Width, counters.DrawWidth);
|
mainContent.Width = Math.Max(mainContent.Width, counters.DrawWidth);
|
||||||
|
|
||||||
// Handle the case where the window has become inactive or the user changed the
|
// Handle the case where the window has become inactive or the user changed the
|
||||||
@ -177,15 +182,15 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
// use elapsed frame time rather then FramesPerSecond to better catch stutter frames.
|
// use elapsed frame time rather then FramesPerSecond to better catch stutter frames.
|
||||||
bool hasDrawSpike = displayedFpsCount > (1000 / spike_time_ms) && drawClock.ElapsedFrameTime > spike_time_ms;
|
bool hasDrawSpike = displayedFpsCount > (1000 / spike_time_ms) && drawClock.ElapsedFrameTime > spike_time_ms;
|
||||||
|
|
||||||
// note that we use an elapsed time here of 1 intentionally.
|
const float damp_time = 100;
|
||||||
// this weights all updates equally. if we passed in the elapsed time, longer frames would be weighted incorrectly lower.
|
|
||||||
displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : 100, 1);
|
displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : damp_time, updateClock.ElapsedFrameTime);
|
||||||
|
|
||||||
if (hasDrawSpike)
|
if (hasDrawSpike)
|
||||||
// show spike time using raw elapsed value, to account for `FramesPerSecond` being so averaged spike frames don't show.
|
// show spike time using raw elapsed value, to account for `FramesPerSecond` being so averaged spike frames don't show.
|
||||||
displayedFpsCount = 1000 / drawClock.ElapsedFrameTime;
|
displayedFpsCount = 1000 / drawClock.ElapsedFrameTime;
|
||||||
else
|
else
|
||||||
displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, 100, Time.Elapsed);
|
displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, damp_time, Time.Elapsed);
|
||||||
|
|
||||||
if (Time.Current - lastUpdate > min_time_between_updates)
|
if (Time.Current - lastUpdate > min_time_between_updates)
|
||||||
{
|
{
|
||||||
@ -203,7 +208,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
if (hasSignificantChanges)
|
if (hasSignificantChanges)
|
||||||
requestDisplay();
|
requestDisplay();
|
||||||
else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000)
|
else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000 && !IsHovered)
|
||||||
{
|
{
|
||||||
mainContent.FadeTo(0, 300, Easing.OutQuint);
|
mainContent.FadeTo(0, 300, Easing.OutQuint);
|
||||||
isDisplayed = false;
|
isDisplayed = false;
|
||||||
|
@ -20,6 +20,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LoadingLayer : LoadingSpinner
|
public class LoadingLayer : LoadingSpinner
|
||||||
{
|
{
|
||||||
|
private readonly bool blockInput;
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
protected Box BackgroundDimLayer { get; }
|
protected Box BackgroundDimLayer { get; }
|
||||||
|
|
||||||
@ -28,9 +30,11 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dimBackground">Whether the full background area should be dimmed while loading.</param>
|
/// <param name="dimBackground">Whether the full background area should be dimmed while loading.</param>
|
||||||
/// <param name="withBox">Whether the spinner should have a surrounding black box for visibility.</param>
|
/// <param name="withBox">Whether the spinner should have a surrounding black box for visibility.</param>
|
||||||
public LoadingLayer(bool dimBackground = false, bool withBox = true)
|
/// <param name="blockInput">Whether to block input of components behind the loading layer.</param>
|
||||||
|
public LoadingLayer(bool dimBackground = false, bool withBox = true, bool blockInput = true)
|
||||||
: base(withBox)
|
: base(withBox)
|
||||||
{
|
{
|
||||||
|
this.blockInput = blockInput;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Size = new Vector2(1);
|
Size = new Vector2(1);
|
||||||
|
|
||||||
@ -52,6 +56,9 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
protected override bool Handle(UIEvent e)
|
protected override bool Handle(UIEvent e)
|
||||||
{
|
{
|
||||||
|
if (!blockInput)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
// blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer.
|
// blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer.
|
||||||
@ -83,7 +90,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
|
MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 20, 100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Graphics.Rendering;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
@ -12,10 +11,15 @@ namespace osu.Game.IO
|
|||||||
{
|
{
|
||||||
public interface IStorageResourceProvider
|
public interface IStorageResourceProvider
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The game renderer.
|
||||||
|
/// </summary>
|
||||||
|
IRenderer Renderer { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the game-wide audio manager.
|
/// Retrieve the game-wide audio manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
AudioManager AudioManager { get; }
|
AudioManager? AudioManager { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Access game-wide user files.
|
/// Access game-wide user files.
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -15,8 +13,9 @@ namespace osu.Game.Input.Bindings
|
|||||||
{
|
{
|
||||||
public class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalKeyboardInput
|
public class GlobalActionContainer : DatabasedKeyBindingContainer<GlobalAction>, IHandleGlobalKeyboardInput
|
||||||
{
|
{
|
||||||
private readonly Drawable handler;
|
private readonly Drawable? handler;
|
||||||
private InputManager parentInputManager;
|
|
||||||
|
private InputManager? parentInputManager;
|
||||||
|
|
||||||
public GlobalActionContainer(OsuGameBase game)
|
public GlobalActionContainer(OsuGameBase game)
|
||||||
: base(matchingMode: KeyCombinationMatchingMode.Modifiers)
|
: base(matchingMode: KeyCombinationMatchingMode.Modifiers)
|
||||||
@ -32,7 +31,10 @@ namespace osu.Game.Input.Bindings
|
|||||||
parentInputManager = GetContainingInputManager();
|
parentInputManager = GetContainingInputManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IMPORTANT: Do not change the order of key bindings in this list.
|
||||||
|
// It is used to decide the order of precedence (see note in DatabasedKeyBindingContainer).
|
||||||
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings
|
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings
|
||||||
|
.Concat(OverlayKeyBindings)
|
||||||
.Concat(EditorKeyBindings)
|
.Concat(EditorKeyBindings)
|
||||||
.Concat(InGameKeyBindings)
|
.Concat(InGameKeyBindings)
|
||||||
.Concat(SongSelectKeyBindings)
|
.Concat(SongSelectKeyBindings)
|
||||||
@ -40,25 +42,6 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
|
public IEnumerable<KeyBinding> GlobalKeyBindings => new[]
|
||||||
{
|
{
|
||||||
new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying),
|
|
||||||
new KeyBinding(InputKey.F8, GlobalAction.ToggleChat),
|
|
||||||
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
|
|
||||||
new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons),
|
|
||||||
new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot),
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, GlobalAction.ToggleFPSDisplay),
|
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor),
|
|
||||||
|
|
||||||
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
|
||||||
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Home }, GlobalAction.Home),
|
|
||||||
|
|
||||||
new KeyBinding(InputKey.Up, GlobalAction.SelectPrevious),
|
new KeyBinding(InputKey.Up, GlobalAction.SelectPrevious),
|
||||||
new KeyBinding(InputKey.Down, GlobalAction.SelectNext),
|
new KeyBinding(InputKey.Down, GlobalAction.SelectNext),
|
||||||
|
|
||||||
@ -69,7 +52,31 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(InputKey.Enter, GlobalAction.Select),
|
new KeyBinding(InputKey.Enter, GlobalAction.Select),
|
||||||
new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select),
|
new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select),
|
||||||
|
|
||||||
|
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||||
|
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
|
||||||
|
|
||||||
|
new KeyBinding(new[] { InputKey.Alt, InputKey.Home }, GlobalAction.Home),
|
||||||
|
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, GlobalAction.ToggleFPSDisplay),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor),
|
||||||
|
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin),
|
||||||
|
|
||||||
|
new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons),
|
||||||
|
new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot),
|
||||||
|
};
|
||||||
|
|
||||||
|
public IEnumerable<KeyBinding> OverlayKeyBindings => new[]
|
||||||
|
{
|
||||||
|
new KeyBinding(InputKey.F8, GlobalAction.ToggleChat),
|
||||||
|
new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying),
|
||||||
|
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications),
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> EditorKeyBindings => new[]
|
public IEnumerable<KeyBinding> EditorKeyBindings => new[]
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.ComponentModel;
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Input
|
namespace osu.Game.Input
|
||||||
{
|
{
|
||||||
@ -17,18 +18,20 @@ namespace osu.Game.Input
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The mouse cursor will be free to move outside the game window.
|
/// The mouse cursor will be free to move outside the game window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.NeverConfine))]
|
||||||
Never,
|
Never,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The mouse cursor will be locked to the window bounds during gameplay,
|
/// The mouse cursor will be locked to the window bounds during gameplay,
|
||||||
/// but may otherwise move freely.
|
/// but may otherwise move freely.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("During Gameplay")]
|
[LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.ConfineDuringGameplay))]
|
||||||
DuringGameplay,
|
DuringGameplay,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The mouse cursor will always be locked to the window bounds while the game has focus.
|
/// The mouse cursor will always be locked to the window bounds while the game has focus.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.AlwaysConfine))]
|
||||||
Always
|
Always
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,4 +101,4 @@ namespace osu.Game.Localisation
|
|||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
osu.Game/Localisation/DeleteConfirmationDialogStrings.cs
Normal file
29
osu.Game/Localisation/DeleteConfirmationDialogStrings.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// 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 osu.Framework.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Localisation
|
||||||
|
{
|
||||||
|
public static class DeleteConfirmationDialogStrings
|
||||||
|
{
|
||||||
|
private const string prefix = @"osu.Game.Resources.Localisation.DeleteConfirmationDialog";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Confirm deletion of"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString HeaderText => new TranslatableString(getKey(@"header_text"), @"Confirm deletion of");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Yes. Go for it."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString Confirm => new TranslatableString(getKey(@"confirm"), @"Yes. Go for it.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "No! Abort mission"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"No! Abort mission");
|
||||||
|
|
||||||
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
|
}
|
||||||
|
}
|
@ -104,6 +104,31 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled");
|
public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Hide during gameplay"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString HideDuringGameplay => new TranslatableString(getKey(@"hide_during_gameplay"), @"Hide during gameplay");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Always"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString AlwaysShowHUD => new TranslatableString(getKey(@"always_show_hud"), @"Always");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Never"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString NeverShowHUD => new TranslatableString(getKey(@"never_show_hud"), @"Never");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Standardised"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString StandardisedScoreDisplay => new TranslatableString(getKey(@"standardised_score_display"), @"Standardised");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Classic"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ClassicScoreDisplay => new TranslatableString(getKey(@"classic_score_display"), @"Classic");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,16 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString UseHardwareAcceleration => new TranslatableString(getKey(@"use_hardware_acceleration"), @"Use hardware acceleration");
|
public static LocalisableString UseHardwareAcceleration => new TranslatableString(getKey(@"use_hardware_acceleration"), @"Use hardware acceleration");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "JPG (web-friendly)"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString Jpg => new TranslatableString(getKey(@"jpg_web_friendly"), @"JPG (web-friendly)");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "PNG (lossless)"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString Png => new TranslatableString(getKey(@"png_lossless"), @"PNG (lossless)");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString GlobalKeyBindingHeader => new TranslatableString(getKey(@"global_key_binding_header"), @"Global");
|
public static LocalisableString GlobalKeyBindingHeader => new TranslatableString(getKey(@"global_key_binding_header"), @"Global");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Overlays"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString OverlaysSection => new TranslatableString(getKey(@"overlays_section"), @"Overlays");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Song Select"
|
/// "Song Select"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -29,6 +29,26 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString FullscreenMacOSNote => new TranslatableString(getKey(@"fullscreen_macos_note"), @"Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended.");
|
public static LocalisableString FullscreenMacOSNote => new TranslatableString(getKey(@"fullscreen_macos_note"), @"Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Excluding overlays"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ScaleEverythingExcludingOverlays => new TranslatableString(getKey(@"scale_everything_excluding_overlays"), @"Excluding overlays");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Everything"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ScaleEverything => new TranslatableString(getKey(@"scale_everything"), @"Everything");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Gameplay"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ScaleGameplay => new TranslatableString(getKey(@"scale_gameplay"), @"Gameplay");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Off"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ScalingOff => new TranslatableString(getKey(@"scaling_off"), @"Off");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,16 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString RestoreAllRecentlyDeletedBeatmaps => new TranslatableString(getKey(@"restore_all_recently_deleted_beatmaps"), @"Restore all recently deleted beatmaps");
|
public static LocalisableString RestoreAllRecentlyDeletedBeatmaps => new TranslatableString(getKey(@"restore_all_recently_deleted_beatmaps"), @"Restore all recently deleted beatmaps");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Delete ALL mod presets"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString DeleteAllModPresets => new TranslatableString(getKey(@"delete_all_mod_presets"), @"Delete ALL mod presets");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Restore all recently deleted mod presets"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString RestoreAllRecentlyDeletedModPresets => new TranslatableString(getKey(@"restore_all_recently_deleted_mod_presets"), @"Restore all recently deleted mod presets");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,21 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString HighPrecisionPlatformWarning => new TranslatableString(getKey(@"high_precision_platform_warning"), @"This setting has known issues on your platform. If you encounter problems, it is recommended to adjust sensitivity externally and keep this disabled for now.");
|
public static LocalisableString HighPrecisionPlatformWarning => new TranslatableString(getKey(@"high_precision_platform_warning"), @"This setting has known issues on your platform. If you encounter problems, it is recommended to adjust sensitivity externally and keep this disabled for now.");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Always"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString AlwaysConfine => new TranslatableString(getKey(@"always_confine"), @"Always");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "During Gameplay"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ConfineDuringGameplay => new TranslatableString(getKey(@"confine_during_gameplay"), @"During Gameplay");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Never"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString NeverConfine => new TranslatableString(getKey(@"never_confine"), @"Never");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,21 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ShowExplicitContent => new TranslatableString(getKey(@"show_explicit_content"), @"Show explicit content in search results");
|
public static LocalisableString ShowExplicitContent => new TranslatableString(getKey(@"show_explicit_content"), @"Show explicit content in search results");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Hide identifiable information"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString HideIdentifiableInformation => new TranslatableString(getKey(@"hide_identifiable_information"), @"Hide identifiable information");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Full"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString DiscordPresenceFull => new TranslatableString(getKey(@"discord_presence_full"), @"Full");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Off"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString DiscordPresenceOff => new TranslatableString(getKey(@"discord_presence_off"), @"Off");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,21 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString Rulesets => new TranslatableString(getKey(@"rulesets"), @"Rulesets");
|
public static LocalisableString Rulesets => new TranslatableString(getKey(@"rulesets"), @"Rulesets");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "None"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString BorderNone => new TranslatableString(getKey(@"no_borders"), @"None");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Corners"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString BorderCorners => new TranslatableString(getKey(@"corner_borders"), @"Corners");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Full"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString BorderFull => new TranslatableString(getKey(@"full_borders"), @"Full");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
osu.Game/Localisation/SongSelectStrings.cs
Normal file
24
osu.Game/Localisation/SongSelectStrings.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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 osu.Framework.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Localisation
|
||||||
|
{
|
||||||
|
public static class SongSelectStrings
|
||||||
|
{
|
||||||
|
private const string prefix = @"osu.Game.Resources.Localisation.SongSelect";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Local"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString LocallyModified => new TranslatableString(getKey(@"locally_modified"), @"Local");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Has been locally modified"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString LocallyModifiedTooltip => new TranslatableString(getKey(@"locally_modified_tooltip"), @"Has been locally modified");
|
||||||
|
|
||||||
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
|
}
|
||||||
|
}
|
24
osu.Game/Localisation/ToolbarStrings.cs
Normal file
24
osu.Game/Localisation/ToolbarStrings.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// 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 osu.Framework.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Localisation
|
||||||
|
{
|
||||||
|
public static class ToolbarStrings
|
||||||
|
{
|
||||||
|
private const string prefix = @"osu.Game.Resources.Localisation.Toolbar";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Connection interrupted, will try to reconnect..."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString AttemptingToReconnect => new TranslatableString(getKey(@"attempting_to_reconnect"), @"Connection interrupted, will try to reconnect...");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Connecting..."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString Connecting => new TranslatableString(getKey(@"connecting"), @"Connecting...");
|
||||||
|
|
||||||
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
|
}
|
||||||
|
}
|
@ -114,6 +114,46 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString NoLimit => new TranslatableString(getKey(@"no_limit"), @"no limit");
|
public static LocalisableString NoLimit => new TranslatableString(getKey(@"no_limit"), @"no limit");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Beatmap (with storyboard / video)"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString BeatmapWithStoryboard => new TranslatableString(getKey(@"beatmap_with_storyboard"), @"Beatmap (with storyboard / video)");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Always"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString AlwaysSeasonalBackground => new TranslatableString(getKey(@"always_seasonal_backgrounds"), @"Always");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Never"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString NeverSeasonalBackground => new TranslatableString(getKey(@"never_seasonal_backgrounds"), @"Never");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Sometimes"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString SometimesSeasonalBackground => new TranslatableString(getKey(@"sometimes_seasonal_backgrounds"), @"Sometimes");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Sequential"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString SequentialHotkeyStyle => new TranslatableString(getKey(@"mods_sequential_hotkeys"), @"Sequential");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Classic"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ClassicHotkeyStyle => new TranslatableString(getKey(@"mods_classic_hotkeys"), @"Classic");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Never repeat"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString NeverRepeat => new TranslatableString(getKey(@"never_repeat_random"), @"Never repeat");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "True Random"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString TrueRandom => new TranslatableString(getKey(@"true_random"), @"True Random");
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
private static string getKey(string key) => $"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,120 +104,39 @@ namespace osu.Game.Online.API
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private int failureCount;
|
private int failureCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The main API thread loop, which will continue to run until the game is shut down.
|
||||||
|
/// </summary>
|
||||||
private void run()
|
private void run()
|
||||||
{
|
{
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
switch (State.Value)
|
if (state.Value == APIState.Failing)
|
||||||
{
|
{
|
||||||
case APIState.Failing:
|
// To recover from a failing state, falling through and running the full reconnection process seems safest for now.
|
||||||
//todo: replace this with a ping request.
|
// This could probably be replaced with a ping-style request if we want to avoid the reconnection overheads.
|
||||||
log.Add(@"In a failing state, waiting a bit before we try again...");
|
log.Add($@"{nameof(APIAccess)} is in a failing state, waiting a bit before we try again...");
|
||||||
Thread.Sleep(5000);
|
Thread.Sleep(5000);
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsLoggedIn) goto case APIState.Connecting;
|
// Ensure that we have valid credentials.
|
||||||
|
// If not, setting the offline state will allow the game to prompt the user to provide new credentials.
|
||||||
|
if (!HasLogin)
|
||||||
|
{
|
||||||
|
state.Value = APIState.Offline;
|
||||||
|
Thread.Sleep(50);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (queue.Count == 0)
|
Debug.Assert(HasLogin);
|
||||||
{
|
|
||||||
log.Add(@"Queueing a ping request");
|
|
||||||
Queue(new GetUserRequest());
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
// Ensure that we are in an online state. If not, attempt a connect.
|
||||||
|
if (state.Value != APIState.Online)
|
||||||
|
{
|
||||||
|
attemptConnect();
|
||||||
|
|
||||||
case APIState.Offline:
|
if (state.Value != APIState.Online)
|
||||||
case APIState.Connecting:
|
continue;
|
||||||
// work to restore a connection...
|
|
||||||
if (!HasLogin)
|
|
||||||
{
|
|
||||||
state.Value = APIState.Offline;
|
|
||||||
Thread.Sleep(50);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.Value = APIState.Connecting;
|
|
||||||
|
|
||||||
// save the username at this point, if the user requested for it to be.
|
|
||||||
config.SetValue(OsuSetting.Username, config.Get<bool>(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty);
|
|
||||||
|
|
||||||
if (!authentication.HasValidAccessToken)
|
|
||||||
{
|
|
||||||
LastLoginError = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
authentication.AuthenticateWithLogin(ProvidedUsername, password);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
//todo: this fails even on network-related issues. we should probably handle those differently.
|
|
||||||
LastLoginError = e;
|
|
||||||
log.Add(@"Login failed!");
|
|
||||||
password = null;
|
|
||||||
authentication.Clear();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var userReq = new GetUserRequest();
|
|
||||||
|
|
||||||
userReq.Failure += ex =>
|
|
||||||
{
|
|
||||||
if (ex is APIException)
|
|
||||||
{
|
|
||||||
LastLoginError = ex;
|
|
||||||
log.Add("Login failed on local user retrieval!");
|
|
||||||
Logout();
|
|
||||||
}
|
|
||||||
else if (ex is WebException webException && webException.Message == @"Unauthorized")
|
|
||||||
{
|
|
||||||
log.Add(@"Login no longer valid");
|
|
||||||
Logout();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
failConnectionProcess();
|
|
||||||
};
|
|
||||||
userReq.Success += u =>
|
|
||||||
{
|
|
||||||
localUser.Value = u;
|
|
||||||
|
|
||||||
// todo: save/pull from settings
|
|
||||||
localUser.Value.Status.Value = new UserStatusOnline();
|
|
||||||
|
|
||||||
failureCount = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!handleRequest(userReq))
|
|
||||||
{
|
|
||||||
failConnectionProcess();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// getting user's friends is considered part of the connection process.
|
|
||||||
var friendsReq = new GetFriendsRequest();
|
|
||||||
|
|
||||||
friendsReq.Failure += _ => failConnectionProcess();
|
|
||||||
friendsReq.Success += res =>
|
|
||||||
{
|
|
||||||
friends.AddRange(res);
|
|
||||||
|
|
||||||
//we're connected!
|
|
||||||
state.Value = APIState.Online;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!handleRequest(friendsReq))
|
|
||||||
{
|
|
||||||
failConnectionProcess();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Success callback event is fired on the main thread, so we should wait for that to run before proceeding.
|
|
||||||
// Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests
|
|
||||||
// before actually going online.
|
|
||||||
while (State.Value > APIState.Offline && State.Value < APIState.Online)
|
|
||||||
Thread.Sleep(500);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hard bail if we can't get a valid access token.
|
// hard bail if we can't get a valid access token.
|
||||||
@ -227,31 +146,132 @@ namespace osu.Game.Online.API
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
processQueuedRequests();
|
||||||
{
|
|
||||||
APIRequest req;
|
|
||||||
|
|
||||||
lock (queue)
|
|
||||||
{
|
|
||||||
if (queue.Count == 0) break;
|
|
||||||
|
|
||||||
req = queue.Dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRequest(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(50);
|
Thread.Sleep(50);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void failConnectionProcess()
|
/// <summary>
|
||||||
|
/// Dequeue from the queue and run each request synchronously until the queue is empty.
|
||||||
|
/// </summary>
|
||||||
|
private void processQueuedRequests()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
// if something went wrong during the connection process, we want to reset the state (but only if still connecting).
|
APIRequest req;
|
||||||
if (State.Value == APIState.Connecting)
|
|
||||||
state.Value = APIState.Failing;
|
lock (queue)
|
||||||
|
{
|
||||||
|
if (queue.Count == 0) return;
|
||||||
|
|
||||||
|
req = queue.Dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleRequest(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// From a non-connected state, perform a full connection flow, obtaining OAuth tokens and populating the local user and friends.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method takes control of <see cref="state"/> and transitions from <see cref="APIState.Connecting"/> to either
|
||||||
|
/// - <see cref="APIState.Online"/> (successful connection)
|
||||||
|
/// - <see cref="APIState.Failing"/> (failed connection but retrying)
|
||||||
|
/// - <see cref="APIState.Offline"/> (failed and can't retry, clear credentials and require user interaction)
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>Whether the connection attempt was successful.</returns>
|
||||||
|
private void attemptConnect()
|
||||||
|
{
|
||||||
|
state.Value = APIState.Connecting;
|
||||||
|
|
||||||
|
if (localUser.IsDefault)
|
||||||
|
{
|
||||||
|
// Show a placeholder user if saved credentials are available.
|
||||||
|
// This is useful for storing local scores and showing a placeholder username after starting the game,
|
||||||
|
// until a valid connection has been established.
|
||||||
|
setLocalUser(new APIUser
|
||||||
|
{
|
||||||
|
Username = ProvidedUsername,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the username at this point, if the user requested for it to be.
|
||||||
|
config.SetValue(OsuSetting.Username, config.Get<bool>(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty);
|
||||||
|
|
||||||
|
if (!authentication.HasValidAccessToken)
|
||||||
|
{
|
||||||
|
LastLoginError = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
authentication.AuthenticateWithLogin(ProvidedUsername, password);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
//todo: this fails even on network-related issues. we should probably handle those differently.
|
||||||
|
LastLoginError = e;
|
||||||
|
log.Add($@"Login failed for username {ProvidedUsername} ({LastLoginError.Message})!");
|
||||||
|
|
||||||
|
Logout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var userReq = new GetUserRequest();
|
||||||
|
userReq.Failure += ex =>
|
||||||
|
{
|
||||||
|
if (ex is APIException)
|
||||||
|
{
|
||||||
|
LastLoginError = ex;
|
||||||
|
log.Add($@"Login failed for username {ProvidedUsername} on user retrieval ({LastLoginError.Message})!");
|
||||||
|
Logout();
|
||||||
|
}
|
||||||
|
else if (ex is WebException webException && webException.Message == @"Unauthorized")
|
||||||
|
{
|
||||||
|
log.Add(@"Login no longer valid");
|
||||||
|
Logout();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state.Value = APIState.Failing;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
userReq.Success += user =>
|
||||||
|
{
|
||||||
|
// todo: save/pull from settings
|
||||||
|
user.Status.Value = new UserStatusOnline();
|
||||||
|
|
||||||
|
setLocalUser(user);
|
||||||
|
|
||||||
|
// we're connected!
|
||||||
|
state.Value = APIState.Online;
|
||||||
|
failureCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!handleRequest(userReq))
|
||||||
|
{
|
||||||
|
state.Value = APIState.Failing;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var friendsReq = new GetFriendsRequest();
|
||||||
|
friendsReq.Failure += _ => state.Value = APIState.Failing;
|
||||||
|
friendsReq.Success += res => friends.AddRange(res);
|
||||||
|
|
||||||
|
if (!handleRequest(friendsReq))
|
||||||
|
{
|
||||||
|
state.Value = APIState.Failing;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Success callback event is fired on the main thread, so we should wait for that to run before proceeding.
|
||||||
|
// Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests
|
||||||
|
// before actually going online.
|
||||||
|
while (State.Value == APIState.Connecting && !cancellationToken.IsCancellationRequested)
|
||||||
|
Thread.Sleep(500);
|
||||||
|
}
|
||||||
|
|
||||||
public void Perform(APIRequest request)
|
public void Perform(APIRequest request)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -327,8 +347,7 @@ namespace osu.Game.Online.API
|
|||||||
if (req.CompletionState != APIRequestCompletionState.Completed)
|
if (req.CompletionState != APIRequestCompletionState.Completed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// we could still be in initialisation, at which point we don't want to say we're Online yet.
|
// Reset failure count if this request succeeded.
|
||||||
if (IsLoggedIn) state.Value = APIState.Online;
|
|
||||||
failureCount = 0;
|
failureCount = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -402,7 +421,7 @@ namespace osu.Game.Online.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsLoggedIn => localUser.Value.Id > 1; // TODO: should this also be true if attempting to connect?
|
public bool IsLoggedIn => State.Value > APIState.Offline;
|
||||||
|
|
||||||
public void Queue(APIRequest request)
|
public void Queue(APIRequest request)
|
||||||
{
|
{
|
||||||
@ -442,7 +461,7 @@ namespace osu.Game.Online.API
|
|||||||
// Scheduled prior to state change such that the state changed event is invoked with the correct user and their friends present
|
// Scheduled prior to state change such that the state changed event is invoked with the correct user and their friends present
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
localUser.Value = createGuestUser();
|
setLocalUser(createGuestUser());
|
||||||
friends.Clear();
|
friends.Clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -452,6 +471,8 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
private static APIUser createGuestUser() => new GuestUser();
|
private static APIUser createGuestUser() => new GuestUser();
|
||||||
|
|
||||||
|
private void setLocalUser(APIUser user) => Scheduler.Add(() => localUser.Value = user, false);
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MessagePack;
|
using MessagePack;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -23,7 +20,7 @@ namespace osu.Game.Online.API
|
|||||||
{
|
{
|
||||||
[JsonProperty("acronym")]
|
[JsonProperty("acronym")]
|
||||||
[Key(0)]
|
[Key(0)]
|
||||||
public string Acronym { get; set; }
|
public string Acronym { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonProperty("settings")]
|
[JsonProperty("settings")]
|
||||||
[Key(1)]
|
[Key(1)]
|
||||||
@ -49,7 +46,7 @@ namespace osu.Game.Online.API
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mod ToMod([NotNull] Ruleset ruleset)
|
public Mod ToMod(Ruleset ruleset)
|
||||||
{
|
{
|
||||||
Mod resultMod = ruleset.CreateModFromAcronym(Acronym);
|
Mod resultMod = ruleset.CreateModFromAcronym(Acronym);
|
||||||
|
|
||||||
@ -80,6 +77,8 @@ namespace osu.Game.Online.API
|
|||||||
return resultMod;
|
return resultMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool ShouldSerializeSettings() => Settings.Count > 0;
|
||||||
|
|
||||||
public bool Equals(APIMod other)
|
public bool Equals(APIMod other)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(null, other)) return false;
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user