mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 08:23:00 +08:00
Merge branch 'master' into fix-multiplayer-mods-cheesing
This commit is contained in:
commit
6dee2860d2
@ -10,7 +10,7 @@
|
|||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2024.113.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2024.114.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||||
|
@ -30,12 +30,19 @@ namespace osu.Desktop
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
// NVIDIA profiles are based on the executable name of a process.
|
/*
|
||||||
// Lazer and stable share the same executable name.
|
* WARNING: DO NOT PLACE **ANY** CODE ABOVE THE FOLLOWING BLOCK!
|
||||||
// Stable sets this setting to "Off", which may not be what we want, so let's force it back to the default "Auto" on startup.
|
*
|
||||||
NVAPI.ThreadedOptimisations = NvThreadControlSetting.OGL_THREAD_CONTROL_DEFAULT;
|
* Logic handling Squirrel MUST run before EVERYTHING if you do not want to break it.
|
||||||
|
* To be more precise: Squirrel is internally using a rather... crude method to determine whether it is running under NUnit,
|
||||||
// run Squirrel first, as the app may exit after these run
|
* namely by checking loaded assemblies:
|
||||||
|
* https://github.com/clowd/Clowd.Squirrel/blob/24427217482deeeb9f2cacac555525edfc7bd9ac/src/Squirrel/SimpleSplat/PlatformModeDetector.cs#L17-L32
|
||||||
|
*
|
||||||
|
* If it finds ANY assembly from the ones listed above - REGARDLESS of the reason why it is loaded -
|
||||||
|
* the app will then do completely broken things like:
|
||||||
|
* - not creating system shortcuts (as the logic is if'd out if "running tests")
|
||||||
|
* - not exiting after the install / first-update / uninstall hooks are ran (as the `Environment.Exit()` calls are if'd out if "running tests")
|
||||||
|
*/
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
var windowsVersion = Environment.OSVersion.Version;
|
var windowsVersion = Environment.OSVersion.Version;
|
||||||
@ -59,6 +66,11 @@ namespace osu.Desktop
|
|||||||
setupSquirrel();
|
setupSquirrel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NVIDIA profiles are based on the executable name of a process.
|
||||||
|
// Lazer and stable share the same executable name.
|
||||||
|
// Stable sets this setting to "Off", which may not be what we want, so let's force it back to the default "Auto" on startup.
|
||||||
|
NVAPI.ThreadedOptimisations = NvThreadControlSetting.OGL_THREAD_CONTROL_DEFAULT;
|
||||||
|
|
||||||
// Back up the cwd before DesktopGameHost changes it
|
// Back up the cwd before DesktopGameHost changes it
|
||||||
string cwd = Environment.CurrentDirectory;
|
string cwd = Environment.CurrentDirectory;
|
||||||
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
// 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.Linq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
|
||||||
using osu.Game.Tests.Beatmaps;
|
|
||||||
using osu.Game.Tests.Visual;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This test covers autoplay working correctly in the editor on fast streams.
|
|
||||||
/// Might seem like a weird test, but frame stability being toggled can cause autoplay to operation incorrectly.
|
|
||||||
/// This is clearly a bug with the autoplay algorithm, but is worked around at an editor level for now.
|
|
||||||
/// </summary>
|
|
||||||
public partial class TestSceneEditorAutoplayFastStreams : EditorTestScene
|
|
||||||
{
|
|
||||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
|
|
||||||
{
|
|
||||||
var testBeatmap = new TestBeatmap(ruleset, false);
|
|
||||||
testBeatmap.HitObjects.AddRange(new[]
|
|
||||||
{
|
|
||||||
new HitCircle { StartTime = 500 },
|
|
||||||
new HitCircle { StartTime = 530 },
|
|
||||||
new HitCircle { StartTime = 560 },
|
|
||||||
new HitCircle { StartTime = 590 },
|
|
||||||
new HitCircle { StartTime = 620 },
|
|
||||||
});
|
|
||||||
|
|
||||||
return testBeatmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestAllHit()
|
|
||||||
{
|
|
||||||
AddStep("start playback", () => EditorClock.Start());
|
|
||||||
AddUntilStep("wait for all hit", () =>
|
|
||||||
{
|
|
||||||
DrawableHitCircle[] hitCircles = Editor.ChildrenOfType<DrawableHitCircle>().OrderBy(s => s.HitObject.StartTime).ToArray();
|
|
||||||
|
|
||||||
return hitCircles.Length == 5 && hitCircles.All(h => h.IsHit);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -46,12 +46,10 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
moveMouseToObject(() => slider);
|
moveMouseToObject(() => slider);
|
||||||
|
|
||||||
AddStep("seek after end", () => EditorClock.Seek(750));
|
AddStep("seek after end", () => EditorClock.Seek(750));
|
||||||
AddUntilStep("wait for seek", () => !EditorClock.IsSeeking);
|
|
||||||
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
AddAssert("slider not selected", () => EditorBeatmap.SelectedHitObjects.Count == 0);
|
AddAssert("slider not selected", () => EditorBeatmap.SelectedHitObjects.Count == 0);
|
||||||
|
|
||||||
AddStep("seek to visible", () => EditorClock.Seek(650));
|
AddStep("seek to visible", () => EditorClock.Seek(650));
|
||||||
AddUntilStep("wait for seek", () => !EditorClock.IsSeeking);
|
|
||||||
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
AddUntilStep("slider selected", () => EditorBeatmap.SelectedHitObjects.Single() == slider);
|
AddUntilStep("slider selected", () => EditorBeatmap.SelectedHitObjects.Single() == slider);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,18 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
{
|
{
|
||||||
@ -21,5 +31,51 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods
|
|||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new OsuModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true });
|
public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new OsuModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true });
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSliderDimsOnlyAfterStartTime()
|
||||||
|
{
|
||||||
|
bool sliderDimmedBeforeStartTime = false;
|
||||||
|
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModFlashlight(),
|
||||||
|
PassCondition = () =>
|
||||||
|
{
|
||||||
|
sliderDimmedBeforeStartTime |=
|
||||||
|
Player.GameplayClockContainer.CurrentTime < 1000 && Player.ChildrenOfType<ModFlashlight<OsuHitObject>.Flashlight>().Single().FlashlightDim > 0;
|
||||||
|
return Player.GameplayState.HasPassed && !sliderDimmedBeforeStartTime;
|
||||||
|
},
|
||||||
|
Beatmap = new OsuBeatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<OsuHitObject>
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 0, },
|
||||||
|
new Slider
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Path = new SliderPath(new[]
|
||||||
|
{
|
||||||
|
new PathControlPoint(),
|
||||||
|
new PathControlPoint(new Vector2(100))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BeatmapInfo =
|
||||||
|
{
|
||||||
|
StackLeniency = 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(0, new Vector2(), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(990, new Vector2()),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(2000, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(2001, new Vector2(100)),
|
||||||
|
},
|
||||||
|
Autoplay = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,20 +4,15 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
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.Cursor;
|
||||||
using osu.Framework.Graphics.Primitives;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -41,8 +36,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
public Action<DragEvent> DragInProgress;
|
public Action<DragEvent> DragInProgress;
|
||||||
public Action DragEnded;
|
public Action DragEnded;
|
||||||
|
|
||||||
public List<PathControlPoint> PointsInSegment;
|
|
||||||
|
|
||||||
public readonly BindableBool IsSelected = new BindableBool();
|
public readonly BindableBool IsSelected = new BindableBool();
|
||||||
public readonly PathControlPoint ControlPoint;
|
public readonly PathControlPoint ControlPoint;
|
||||||
|
|
||||||
@ -56,27 +49,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
private IBindable<Vector2> hitObjectPosition;
|
private IBindable<Vector2> hitObjectPosition;
|
||||||
private IBindable<float> hitObjectScale;
|
private IBindable<float> hitObjectScale;
|
||||||
|
|
||||||
[UsedImplicitly]
|
|
||||||
private readonly IBindable<int> hitObjectVersion;
|
|
||||||
|
|
||||||
public PathControlPointPiece(T hitObject, PathControlPoint controlPoint)
|
public PathControlPointPiece(T hitObject, PathControlPoint controlPoint)
|
||||||
{
|
{
|
||||||
this.hitObject = hitObject;
|
this.hitObject = hitObject;
|
||||||
ControlPoint = controlPoint;
|
ControlPoint = controlPoint;
|
||||||
|
|
||||||
// we don't want to run the path type update on construction as it may inadvertently change the hit object.
|
|
||||||
cachePoints(hitObject);
|
|
||||||
|
|
||||||
hitObjectVersion = hitObject.Path.Version.GetBoundCopy();
|
|
||||||
|
|
||||||
// schedule ensure that updates are only applied after all operations from a single frame are applied.
|
|
||||||
// this avoids inadvertently changing the hit object path type for batch operations.
|
|
||||||
hitObjectVersion.BindValueChanged(_ => Scheduler.AddOnce(() =>
|
|
||||||
{
|
|
||||||
cachePoints(hitObject);
|
|
||||||
updatePathType();
|
|
||||||
}));
|
|
||||||
|
|
||||||
controlPoint.Changed += updateMarkerDisplay;
|
controlPoint.Changed += updateMarkerDisplay;
|
||||||
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
@ -214,28 +191,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
|
|
||||||
protected override void OnDragEnd(DragEndEvent e) => DragEnded?.Invoke();
|
protected override void OnDragEnd(DragEndEvent e) => DragEnded?.Invoke();
|
||||||
|
|
||||||
private void cachePoints(T hitObject) => PointsInSegment = hitObject.Path.PointsInSegment(ControlPoint);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles correction of invalid path types.
|
|
||||||
/// </summary>
|
|
||||||
private void updatePathType()
|
|
||||||
{
|
|
||||||
if (ControlPoint.Type != PathType.PERFECT_CURVE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (PointsInSegment.Count > 3)
|
|
||||||
ControlPoint.Type = PathType.BEZIER;
|
|
||||||
|
|
||||||
if (PointsInSegment.Count != 3)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ReadOnlySpan<Vector2> points = PointsInSegment.Select(p => p.Position).ToArray();
|
|
||||||
RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points);
|
|
||||||
if (boundingBox.Width >= 640 || boundingBox.Height >= 480)
|
|
||||||
ControlPoint.Type = PathType.BEZIER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the state of the circular control point marker.
|
/// Updates the state of the circular control point marker.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -14,10 +14,12 @@ 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.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -76,6 +78,50 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
controlPoints.BindTo(hitObject.Path.ControlPoints);
|
controlPoints.BindTo(hitObject.Path.ControlPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles correction of invalid path types.
|
||||||
|
/// </summary>
|
||||||
|
public void EnsureValidPathTypes()
|
||||||
|
{
|
||||||
|
List<PathControlPoint> pointsInCurrentSegment = new List<PathControlPoint>();
|
||||||
|
|
||||||
|
foreach (var controlPoint in controlPoints)
|
||||||
|
{
|
||||||
|
if (controlPoint.Type != null)
|
||||||
|
{
|
||||||
|
pointsInCurrentSegment.Add(controlPoint);
|
||||||
|
ensureValidPathType(pointsInCurrentSegment);
|
||||||
|
pointsInCurrentSegment.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pointsInCurrentSegment.Add(controlPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureValidPathType(pointsInCurrentSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureValidPathType(IReadOnlyList<PathControlPoint> segment)
|
||||||
|
{
|
||||||
|
if (segment.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var first = segment[0];
|
||||||
|
|
||||||
|
if (first.Type != PathType.PERFECT_CURVE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (segment.Count > 3)
|
||||||
|
first.Type = PathType.BEZIER;
|
||||||
|
|
||||||
|
if (segment.Count != 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ReadOnlySpan<Vector2> points = segment.Select(p => p.Position).ToArray();
|
||||||
|
RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points);
|
||||||
|
if (boundingBox.Width >= 640 || boundingBox.Height >= 480)
|
||||||
|
first.Type = PathType.BEZIER;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Selects the <see cref="PathControlPointPiece{T}"/> corresponding to the given <paramref name="pathControlPoint"/>,
|
/// Selects the <see cref="PathControlPointPiece{T}"/> corresponding to the given <paramref name="pathControlPoint"/>,
|
||||||
/// and deselects all other <see cref="PathControlPointPiece{T}"/>s.
|
/// and deselects all other <see cref="PathControlPointPiece{T}"/>s.
|
||||||
@ -240,7 +286,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
/// <param name="type">The path type we want to assign to the given control point piece.</param>
|
/// <param name="type">The path type we want to assign to the given control point piece.</param>
|
||||||
private void updatePathType(PathControlPointPiece<T> piece, PathType? type)
|
private void updatePathType(PathControlPointPiece<T> piece, PathType? type)
|
||||||
{
|
{
|
||||||
int indexInSegment = piece.PointsInSegment.IndexOf(piece.ControlPoint);
|
var pointsInSegment = hitObject.Path.PointsInSegment(piece.ControlPoint);
|
||||||
|
int indexInSegment = pointsInSegment.IndexOf(piece.ControlPoint);
|
||||||
|
|
||||||
if (type?.Type == SplineType.PerfectCurve)
|
if (type?.Type == SplineType.PerfectCurve)
|
||||||
{
|
{
|
||||||
@ -249,8 +296,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
// and one segment of the previous type.
|
// and one segment of the previous type.
|
||||||
int thirdPointIndex = indexInSegment + 2;
|
int thirdPointIndex = indexInSegment + 2;
|
||||||
|
|
||||||
if (piece.PointsInSegment.Count > thirdPointIndex + 1)
|
if (pointsInSegment.Count > thirdPointIndex + 1)
|
||||||
piece.PointsInSegment[thirdPointIndex].Type = piece.PointsInSegment[0].Type;
|
pointsInSegment[thirdPointIndex].Type = pointsInSegment[0].Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
hitObject.Path.ExpectedDistance.Value = null;
|
hitObject.Path.ExpectedDistance.Value = null;
|
||||||
@ -339,6 +386,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
// Maintain the path types in case they got defaulted to bezier at some point during the drag.
|
// Maintain the path types in case they got defaulted to bezier at some point during the drag.
|
||||||
for (int i = 0; i < hitObject.Path.ControlPoints.Count; i++)
|
for (int i = 0; i < hitObject.Path.ControlPoints.Count; i++)
|
||||||
hitObject.Path.ControlPoints[i].Type = dragPathTypes[i];
|
hitObject.Path.ControlPoints[i].Type = dragPathTypes[i];
|
||||||
|
|
||||||
|
EnsureValidPathTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DragEnded() => changeHandler?.EndChange();
|
public void DragEnded() => changeHandler?.EndChange();
|
||||||
@ -412,6 +461,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
{
|
{
|
||||||
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
|
foreach (var p in Pieces.Where(p => p.IsSelected.Value))
|
||||||
updatePathType(p, type);
|
updatePathType(p, type);
|
||||||
|
|
||||||
|
EnsureValidPathTypes();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (countOfState == totalCount)
|
if (countOfState == totalCount)
|
||||||
|
@ -267,6 +267,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
segmentStart.Type = PathType.BEZIER;
|
segmentStart.Type = PathType.BEZIER;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controlPointVisualiser.EnsureValidPathTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateCursor()
|
private void updateCursor()
|
||||||
|
@ -254,6 +254,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
// Move the control points from the insertion index onwards to make room for the insertion
|
// Move the control points from the insertion index onwards to make room for the insertion
|
||||||
controlPoints.Insert(insertionIndex, pathControlPoint);
|
controlPoints.Insert(insertionIndex, pathControlPoint);
|
||||||
|
|
||||||
|
ControlPointVisualiser?.EnsureValidPathTypes();
|
||||||
|
|
||||||
HitObject.SnapTo(distanceSnapProvider);
|
HitObject.SnapTo(distanceSnapProvider);
|
||||||
|
|
||||||
return pathControlPoint;
|
return pathControlPoint;
|
||||||
@ -275,6 +277,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
controlPoints.Remove(c);
|
controlPoints.Remove(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ControlPointVisualiser?.EnsureValidPathTypes();
|
||||||
|
|
||||||
// Snap the slider to the current beat divisor before checking length validity.
|
// Snap the slider to the current beat divisor before checking length validity.
|
||||||
HitObject.SnapTo(distanceSnapProvider);
|
HitObject.SnapTo(distanceSnapProvider);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
public void ApplyToDrawableHitObject(DrawableHitObject drawable)
|
||||||
{
|
{
|
||||||
if (drawable is DrawableSlider s)
|
if (drawable is DrawableSlider s)
|
||||||
s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange;
|
s.Tracking.ValueChanged += _ => flashlight.OnSliderTrackingChange(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private partial class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
private partial class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition
|
||||||
@ -66,10 +66,10 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
FlashlightSmoothness = 1.4f;
|
FlashlightSmoothness = 1.4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSliderTrackingChange(ValueChangedEvent<bool> e)
|
public void OnSliderTrackingChange(DrawableSlider e)
|
||||||
{
|
{
|
||||||
// If a slider is in a tracking state, a further dim should be applied to the (remaining) visible portion of the playfield.
|
// If a slider is in a tracking state, a further dim should be applied to the (remaining) visible portion of the playfield.
|
||||||
FlashlightDim = e.NewValue ? 0.8f : 0.0f;
|
FlashlightDim = Time.Current >= e.HitObject.StartTime && e.Tracking.Value ? 0.8f : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
|
@ -10,12 +10,14 @@ using osu.Framework.Allocation;
|
|||||||
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.Sprites;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.OnlinePlay;
|
using osu.Game.Screens.OnlinePlay;
|
||||||
|
using osu.Game.Utils;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
@ -23,6 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
public partial class TestSceneFreeModSelectOverlay : MultiplayerTestScene
|
public partial class TestSceneFreeModSelectOverlay : MultiplayerTestScene
|
||||||
{
|
{
|
||||||
private FreeModSelectOverlay freeModSelectOverlay;
|
private FreeModSelectOverlay freeModSelectOverlay;
|
||||||
|
private FooterButtonFreeMods footerButtonFreeMods;
|
||||||
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
|
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -119,11 +122,46 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddAssert("select all button enabled", () => this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
|
AddAssert("select all button enabled", () => this.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSelectAllViaFooterButtonThenDeselectFromOverlay()
|
||||||
|
{
|
||||||
|
createFreeModSelect();
|
||||||
|
|
||||||
|
AddAssert("overlay select all button enabled", () => freeModSelectOverlay.ChildrenOfType<SelectAllModsButton>().Single().Enabled.Value);
|
||||||
|
AddAssert("footer button displays off", () => footerButtonFreeMods.ChildrenOfType<IHasText>().Any(t => t.Text == "off"));
|
||||||
|
|
||||||
|
AddStep("click footer select all button", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(footerButtonFreeMods);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("all mods selected", assertAllAvailableModsSelected);
|
||||||
|
AddAssert("footer button displays all", () => footerButtonFreeMods.ChildrenOfType<IHasText>().Any(t => t.Text == "all"));
|
||||||
|
|
||||||
|
AddStep("click deselect all button", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<DeselectAllModsButton>().Single());
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
AddUntilStep("all mods deselected", () => !freeModSelectOverlay.SelectedMods.Value.Any());
|
||||||
|
AddAssert("footer button displays off", () => footerButtonFreeMods.ChildrenOfType<IHasText>().Any(t => t.Text == "off"));
|
||||||
|
}
|
||||||
|
|
||||||
private void createFreeModSelect()
|
private void createFreeModSelect()
|
||||||
{
|
{
|
||||||
AddStep("create free mod select screen", () => Child = freeModSelectOverlay = new FreeModSelectOverlay
|
AddStep("create free mod select screen", () => Children = new Drawable[]
|
||||||
{
|
{
|
||||||
State = { Value = Visibility.Visible }
|
freeModSelectOverlay = new FreeModSelectOverlay
|
||||||
|
{
|
||||||
|
State = { Value = Visibility.Visible }
|
||||||
|
},
|
||||||
|
footerButtonFreeMods = new FooterButtonFreeMods(freeModSelectOverlay)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
Current = { BindTarget = freeModSelectOverlay.SelectedMods },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
AddUntilStep("all column content loaded",
|
AddUntilStep("all column content loaded",
|
||||||
() => freeModSelectOverlay.ChildrenOfType<ModColumn>().Any()
|
() => freeModSelectOverlay.ChildrenOfType<ModColumn>().Any()
|
||||||
@ -134,10 +172,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
{
|
{
|
||||||
var allAvailableMods = availableMods.Value
|
var allAvailableMods = availableMods.Value
|
||||||
.Where(pair => pair.Key != ModType.System)
|
.Where(pair => pair.Key != ModType.System)
|
||||||
.SelectMany(pair => pair.Value)
|
.SelectMany(pair => ModUtils.FlattenMods(pair.Value))
|
||||||
.Where(mod => mod.UserPlayable && mod.HasImplementation)
|
.Where(mod => mod.UserPlayable && mod.HasImplementation)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
if (freeModSelectOverlay.SelectedMods.Value.Count != allAvailableMods.Count)
|
||||||
|
return false;
|
||||||
|
|
||||||
foreach (var availableMod in allAvailableMods)
|
foreach (var availableMod in allAvailableMods)
|
||||||
{
|
{
|
||||||
if (freeModSelectOverlay.SelectedMods.Value.All(selectedMod => selectedMod.GetType() != availableMod.GetType()))
|
if (freeModSelectOverlay.SelectedMods.Value.All(selectedMod => selectedMod.GetType() != availableMod.GetType()))
|
||||||
|
@ -268,6 +268,26 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert("update not received", () => update == null);
|
AddAssert("update not received", () => update == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestGlobalStatisticsUpdatedAfterRegistrationAddedAndScoreProcessed()
|
||||||
|
{
|
||||||
|
int userId = getUserId();
|
||||||
|
long scoreId = getScoreId();
|
||||||
|
setUpUser(userId);
|
||||||
|
|
||||||
|
var ruleset = new OsuRuleset().RulesetInfo;
|
||||||
|
|
||||||
|
SoloStatisticsUpdate? update = null;
|
||||||
|
registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate);
|
||||||
|
|
||||||
|
feignScoreProcessing(userId, ruleset, 5_000_000);
|
||||||
|
|
||||||
|
AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId));
|
||||||
|
AddUntilStep("update received", () => update != null);
|
||||||
|
AddAssert("local user values are correct", () => dummyAPI.LocalUser.Value.Statistics.TotalScore, () => Is.EqualTo(5_000_000));
|
||||||
|
AddAssert("statistics values are correct", () => dummyAPI.Statistics.Value!.TotalScore, () => Is.EqualTo(5_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
private int nextUserId = 2000;
|
private int nextUserId = 2000;
|
||||||
private long nextScoreId = 50000;
|
private long nextScoreId = 50000;
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ namespace osu.Game.Extensions
|
|||||||
/// <returns>A short relative string representing the input time.</returns>
|
/// <returns>A short relative string representing the input time.</returns>
|
||||||
public static string ToShortRelativeTime(this DateTimeOffset time, TimeSpan lowerCutoff)
|
public static string ToShortRelativeTime(this DateTimeOffset time, TimeSpan lowerCutoff)
|
||||||
{
|
{
|
||||||
if (time == default)
|
// covers all `DateTimeOffset` instances with the date portion of 0001-01-01.
|
||||||
|
if (time.Date == default)
|
||||||
return "-";
|
return "-";
|
||||||
|
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
|
@ -95,6 +95,7 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
case HitResult.SmallTickHit:
|
case HitResult.SmallTickHit:
|
||||||
case HitResult.LargeTickHit:
|
case HitResult.LargeTickHit:
|
||||||
|
case HitResult.SliderTailHit:
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
return Blue;
|
return Blue;
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ namespace osu.Game.Input
|
|||||||
{
|
{
|
||||||
private Bindable<ConfineMouseMode> frameworkConfineMode;
|
private Bindable<ConfineMouseMode> frameworkConfineMode;
|
||||||
private Bindable<WindowMode> frameworkWindowMode;
|
private Bindable<WindowMode> frameworkWindowMode;
|
||||||
|
private Bindable<bool> frameworkMinimiseOnFocusLossInFullscreen;
|
||||||
|
|
||||||
private Bindable<OsuConfineMouseMode> osuConfineMode;
|
private Bindable<OsuConfineMouseMode> osuConfineMode;
|
||||||
private IBindable<bool> localUserPlaying;
|
private IBindable<bool> localUserPlaying;
|
||||||
@ -31,7 +32,9 @@ namespace osu.Game.Input
|
|||||||
{
|
{
|
||||||
frameworkConfineMode = frameworkConfigManager.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode);
|
frameworkConfineMode = frameworkConfigManager.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode);
|
||||||
frameworkWindowMode = frameworkConfigManager.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
frameworkWindowMode = frameworkConfigManager.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
||||||
|
frameworkMinimiseOnFocusLossInFullscreen = frameworkConfigManager.GetBindable<bool>(FrameworkSetting.MinimiseOnFocusLossInFullscreen);
|
||||||
frameworkWindowMode.BindValueChanged(_ => updateConfineMode());
|
frameworkWindowMode.BindValueChanged(_ => updateConfineMode());
|
||||||
|
frameworkMinimiseOnFocusLossInFullscreen.BindValueChanged(_ => updateConfineMode());
|
||||||
|
|
||||||
osuConfineMode = osuConfigManager.GetBindable<OsuConfineMouseMode>(OsuSetting.ConfineMouseMode);
|
osuConfineMode = osuConfigManager.GetBindable<OsuConfineMouseMode>(OsuSetting.ConfineMouseMode);
|
||||||
localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
|
localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
|
||||||
@ -46,7 +49,8 @@ namespace osu.Game.Input
|
|||||||
if (frameworkConfineMode.Disabled)
|
if (frameworkConfineMode.Disabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (frameworkWindowMode.Value == WindowMode.Fullscreen)
|
// override confine mode only when clicking outside the window minimises it.
|
||||||
|
if (frameworkWindowMode.Value == WindowMode.Fullscreen && frameworkMinimiseOnFocusLossInFullscreen.Value)
|
||||||
{
|
{
|
||||||
frameworkConfineMode.Value = ConfineMouseMode.Fullscreen;
|
frameworkConfineMode.Value = ConfineMouseMode.Fullscreen;
|
||||||
return;
|
return;
|
||||||
|
@ -152,9 +152,13 @@ namespace osu.Game.Localisation
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// "In order to change the renderer, the game will close. Please open it again."
|
/// "In order to change the renderer, the game will close. Please open it again."
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ChangeRendererConfirmation =>
|
public static LocalisableString ChangeRendererConfirmation => new TranslatableString(getKey(@"change_renderer_configuration"), @"In order to change the renderer, the game will close. Please open it again.");
|
||||||
new TranslatableString(getKey(@"change_renderer_configuration"), @"In order to change the renderer, the game will close. Please open it again.");
|
|
||||||
|
|
||||||
private static string getKey(string key) => $"{prefix}:{key}";
|
/// <summary>
|
||||||
|
/// "Minimise osu! when switching to another app"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString MinimiseOnFocusLoss => new TranslatableString(getKey(@"minimise_on_focus_loss"), @"Minimise osu! when switching to another app");
|
||||||
|
|
||||||
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ namespace osu.Game.Online.API
|
|||||||
public IBindable<APIUser> LocalUser => localUser;
|
public IBindable<APIUser> LocalUser => localUser;
|
||||||
public IBindableList<APIUser> Friends => friends;
|
public IBindableList<APIUser> Friends => friends;
|
||||||
public IBindable<UserActivity> Activity => activity;
|
public IBindable<UserActivity> Activity => activity;
|
||||||
|
public IBindable<UserStatistics> Statistics => statistics;
|
||||||
|
|
||||||
public Language Language => game.CurrentLanguage.Value;
|
public Language Language => game.CurrentLanguage.Value;
|
||||||
|
|
||||||
@ -65,6 +66,8 @@ namespace osu.Game.Online.API
|
|||||||
private Bindable<UserStatus?> configStatus { get; } = new Bindable<UserStatus?>();
|
private Bindable<UserStatus?> configStatus { get; } = new Bindable<UserStatus?>();
|
||||||
private Bindable<UserStatus?> localUserStatus { get; } = new Bindable<UserStatus?>();
|
private Bindable<UserStatus?> localUserStatus { get; } = new Bindable<UserStatus?>();
|
||||||
|
|
||||||
|
private Bindable<UserStatistics> statistics { get; } = new Bindable<UserStatistics>();
|
||||||
|
|
||||||
protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password));
|
protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password));
|
||||||
|
|
||||||
private readonly CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
private readonly CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
||||||
@ -517,9 +520,21 @@ namespace osu.Game.Online.API
|
|||||||
flushQueue();
|
flushQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateStatistics(UserStatistics newStatistics)
|
||||||
|
{
|
||||||
|
statistics.Value = newStatistics;
|
||||||
|
|
||||||
|
if (IsLoggedIn)
|
||||||
|
localUser.Value.Statistics = newStatistics;
|
||||||
|
}
|
||||||
|
|
||||||
private static APIUser createGuestUser() => new GuestUser();
|
private static APIUser createGuestUser() => new GuestUser();
|
||||||
|
|
||||||
private void setLocalUser(APIUser user) => Scheduler.Add(() => localUser.Value = user, false);
|
private void setLocalUser(APIUser user) => Scheduler.Add(() =>
|
||||||
|
{
|
||||||
|
localUser.Value = user;
|
||||||
|
statistics.Value = user.Statistics;
|
||||||
|
}, false);
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,8 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
|
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
|
||||||
|
|
||||||
|
public Bindable<UserStatistics?> Statistics { get; } = new Bindable<UserStatistics?>();
|
||||||
|
|
||||||
public Language Language => Language.en;
|
public Language Language => Language.en;
|
||||||
|
|
||||||
public string AccessToken => "token";
|
public string AccessToken => "token";
|
||||||
@ -115,6 +117,12 @@ namespace osu.Game.Online.API
|
|||||||
Id = DUMMY_USER_ID,
|
Id = DUMMY_USER_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Statistics.Value = new UserStatistics
|
||||||
|
{
|
||||||
|
GlobalRank = 1,
|
||||||
|
CountryRank = 1
|
||||||
|
};
|
||||||
|
|
||||||
state.Value = APIState.Online;
|
state.Value = APIState.Online;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,6 +134,14 @@ namespace osu.Game.Online.API
|
|||||||
LocalUser.Value = new GuestUser();
|
LocalUser.Value = new GuestUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateStatistics(UserStatistics newStatistics)
|
||||||
|
{
|
||||||
|
Statistics.Value = newStatistics;
|
||||||
|
|
||||||
|
if (IsLoggedIn)
|
||||||
|
LocalUser.Value.Statistics = newStatistics;
|
||||||
|
}
|
||||||
|
|
||||||
public IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null;
|
public IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null;
|
||||||
|
|
||||||
public NotificationsClientConnector GetNotificationsConnector() => new PollingNotificationsClientConnector(this);
|
public NotificationsClientConnector GetNotificationsConnector() => new PollingNotificationsClientConnector(this);
|
||||||
@ -141,6 +157,7 @@ namespace osu.Game.Online.API
|
|||||||
IBindable<APIUser> IAPIProvider.LocalUser => LocalUser;
|
IBindable<APIUser> IAPIProvider.LocalUser => LocalUser;
|
||||||
IBindableList<APIUser> IAPIProvider.Friends => Friends;
|
IBindableList<APIUser> IAPIProvider.Friends => Friends;
|
||||||
IBindable<UserActivity> IAPIProvider.Activity => Activity;
|
IBindable<UserActivity> IAPIProvider.Activity => Activity;
|
||||||
|
IBindable<UserStatistics?> IAPIProvider.Statistics => Statistics;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// During the next simulated login, the process will fail immediately.
|
/// During the next simulated login, the process will fail immediately.
|
||||||
|
@ -28,6 +28,11 @@ namespace osu.Game.Online.API
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IBindable<UserActivity> Activity { get; }
|
IBindable<UserActivity> Activity { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current user's online statistics.
|
||||||
|
/// </summary>
|
||||||
|
IBindable<UserStatistics?> Statistics { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The language supplied by this provider to API requests.
|
/// The language supplied by this provider to API requests.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -111,6 +116,11 @@ namespace osu.Game.Online.API
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void Logout();
|
void Logout();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets Statistics bindable.
|
||||||
|
/// </summary>
|
||||||
|
void UpdateStatistics(UserStatistics newStatistics);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new <see cref="IHubClientConnector"/>. May be null if not supported.
|
/// Constructs a new <see cref="IHubClientConnector"/>. May be null if not supported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -127,6 +127,8 @@ namespace osu.Game.Online.Solo
|
|||||||
{
|
{
|
||||||
string rulesetName = callback.Score.Ruleset.ShortName;
|
string rulesetName = callback.Score.Ruleset.ShortName;
|
||||||
|
|
||||||
|
api.UpdateStatistics(updatedStatistics);
|
||||||
|
|
||||||
if (latestStatistics == null)
|
if (latestStatistics == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -447,7 +447,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
private void filterMods()
|
private void filterMods()
|
||||||
{
|
{
|
||||||
foreach (var modState in AllAvailableMods)
|
foreach (var modState in AllAvailableMods)
|
||||||
modState.ValidForSelection.Value = modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
|
modState.ValidForSelection.Value = modState.Mod.Type != ModType.System && modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMultiplier()
|
private void updateMultiplier()
|
||||||
|
@ -41,8 +41,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
private void updateEnabledState()
|
private void updateEnabledState()
|
||||||
{
|
{
|
||||||
Enabled.Value = availableMods.Value
|
Enabled.Value = availableMods.Value
|
||||||
.Where(pair => pair.Key != ModType.System)
|
|
||||||
.SelectMany(pair => pair.Value)
|
.SelectMany(pair => pair.Value)
|
||||||
|
.Where(modState => modState.ValidForSelection.Value)
|
||||||
.Any(modState => !modState.Active.Value && modState.Visible);
|
.Any(modState => !modState.Active.Value && modState.Visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
private SettingsDropdown<Size> resolutionDropdown = null!;
|
private SettingsDropdown<Size> resolutionDropdown = null!;
|
||||||
private SettingsDropdown<Display> displayDropdown = null!;
|
private SettingsDropdown<Display> displayDropdown = null!;
|
||||||
private SettingsDropdown<WindowMode> windowModeDropdown = null!;
|
private SettingsDropdown<WindowMode> windowModeDropdown = null!;
|
||||||
|
private SettingsCheckbox minimiseOnFocusLossCheckbox = null!;
|
||||||
private SettingsCheckbox safeAreaConsiderationsCheckbox = null!;
|
private SettingsCheckbox safeAreaConsiderationsCheckbox = null!;
|
||||||
|
|
||||||
private Bindable<float> scalingPositionX = null!;
|
private Bindable<float> scalingPositionX = null!;
|
||||||
@ -106,6 +107,12 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
ItemSource = resolutions,
|
ItemSource = resolutions,
|
||||||
Current = sizeFullscreen
|
Current = sizeFullscreen
|
||||||
},
|
},
|
||||||
|
minimiseOnFocusLossCheckbox = new SettingsCheckbox
|
||||||
|
{
|
||||||
|
LabelText = GraphicsSettingsStrings.MinimiseOnFocusLoss,
|
||||||
|
Current = config.GetBindable<bool>(FrameworkSetting.MinimiseOnFocusLossInFullscreen),
|
||||||
|
Keywords = new[] { "alt-tab", "minimize", "focus", "hide" },
|
||||||
|
},
|
||||||
safeAreaConsiderationsCheckbox = new SettingsCheckbox
|
safeAreaConsiderationsCheckbox = new SettingsCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Shrink game to avoid cameras and notches",
|
LabelText = "Shrink game to avoid cameras and notches",
|
||||||
@ -255,6 +262,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
{
|
{
|
||||||
resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen;
|
resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen;
|
||||||
displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1;
|
displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1;
|
||||||
|
minimiseOnFocusLossCheckbox.CanBeShown.Value = RuntimeInfo.IsDesktop && windowModeDropdown.Current.Value == WindowMode.Fullscreen;
|
||||||
safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero;
|
safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
private Bindable<double> localSensitivity;
|
private Bindable<double> localSensitivity;
|
||||||
|
|
||||||
private Bindable<WindowMode> windowMode;
|
private Bindable<WindowMode> windowMode;
|
||||||
|
private Bindable<bool> minimiseOnFocusLoss;
|
||||||
private SettingsEnumDropdown<OsuConfineMouseMode> confineMouseModeSetting;
|
private SettingsEnumDropdown<OsuConfineMouseMode> confineMouseModeSetting;
|
||||||
private Bindable<bool> relativeMode;
|
private Bindable<bool> relativeMode;
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
|
|
||||||
relativeMode = mouseHandler.UseRelativeMode.GetBoundCopy();
|
relativeMode = mouseHandler.UseRelativeMode.GetBoundCopy();
|
||||||
windowMode = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
windowMode = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
||||||
|
minimiseOnFocusLoss = config.GetBindable<bool>(FrameworkSetting.MinimiseOnFocusLossInFullscreen);
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -98,21 +100,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
|
|
||||||
localSensitivity.BindValueChanged(val => handlerSensitivity.Value = val.NewValue);
|
localSensitivity.BindValueChanged(val => handlerSensitivity.Value = val.NewValue);
|
||||||
|
|
||||||
windowMode.BindValueChanged(mode =>
|
windowMode.BindValueChanged(_ => updateConfineMouseModeSettingVisibility());
|
||||||
{
|
minimiseOnFocusLoss.BindValueChanged(_ => updateConfineMouseModeSettingVisibility(), true);
|
||||||
bool isFullscreen = mode.NewValue == WindowMode.Fullscreen;
|
|
||||||
|
|
||||||
if (isFullscreen)
|
|
||||||
{
|
|
||||||
confineMouseModeSetting.Current.Disabled = true;
|
|
||||||
confineMouseModeSetting.TooltipText = MouseSettingsStrings.NotApplicableFullscreen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
confineMouseModeSetting.Current.Disabled = false;
|
|
||||||
confineMouseModeSetting.TooltipText = string.Empty;
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
highPrecisionMouse.Current.BindValueChanged(highPrecision =>
|
highPrecisionMouse.Current.BindValueChanged(highPrecision =>
|
||||||
{
|
{
|
||||||
@ -126,6 +115,25 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates disabled state and tooltip of <see cref="confineMouseModeSetting"/> to match when <see cref="ConfineMouseTracker"/> is overriding the confine mode.
|
||||||
|
/// </summary>
|
||||||
|
private void updateConfineMouseModeSettingVisibility()
|
||||||
|
{
|
||||||
|
bool confineModeOverriden = windowMode.Value == WindowMode.Fullscreen && minimiseOnFocusLoss.Value;
|
||||||
|
|
||||||
|
if (confineModeOverriden)
|
||||||
|
{
|
||||||
|
confineMouseModeSetting.Current.Disabled = true;
|
||||||
|
confineMouseModeSetting.TooltipText = MouseSettingsStrings.NotApplicableFullscreen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
confineMouseModeSetting.Current.Disabled = false;
|
||||||
|
confineMouseModeSetting.TooltipText = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public partial class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
|
public partial class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
|
||||||
{
|
{
|
||||||
public SensitivitySetting()
|
public SensitivitySetting()
|
||||||
|
@ -26,6 +26,8 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
{
|
{
|
||||||
public abstract partial class ToolbarButton : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
|
public abstract partial class ToolbarButton : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
|
public const float PADDING = 3;
|
||||||
|
|
||||||
protected GlobalAction? Hotkey { get; set; }
|
protected GlobalAction? Hotkey { get; set; }
|
||||||
|
|
||||||
public void SetIcon(Drawable icon)
|
public void SetIcon(Drawable icon)
|
||||||
@ -63,6 +65,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
protected virtual Anchor TooltipAnchor => Anchor.TopLeft;
|
protected virtual Anchor TooltipAnchor => Anchor.TopLeft;
|
||||||
|
|
||||||
|
protected readonly Container ButtonContent;
|
||||||
protected ConstrainedIconContainer IconContainer;
|
protected ConstrainedIconContainer IconContainer;
|
||||||
protected SpriteText DrawableText;
|
protected SpriteText DrawableText;
|
||||||
protected Box HoverBackground;
|
protected Box HoverBackground;
|
||||||
@ -80,59 +83,66 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
protected ToolbarButton()
|
protected ToolbarButton()
|
||||||
{
|
{
|
||||||
Width = Toolbar.HEIGHT;
|
AutoSizeAxes = Axes.X;
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
Padding = new MarginPadding(3);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
BackgroundContent = new Container
|
ButtonContent = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Width = Toolbar.HEIGHT,
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 6,
|
|
||||||
CornerExponent = 3f,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
HoverBackground = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = OsuColour.Gray(80).Opacity(180),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
Alpha = 0,
|
|
||||||
},
|
|
||||||
flashBackground = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0,
|
|
||||||
Colour = Color4.White.Opacity(100),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Flow = new FillFlowContainer
|
|
||||||
{
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(5),
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
Padding = new MarginPadding { Left = Toolbar.HEIGHT / 2, Right = Toolbar.HEIGHT / 2 },
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
AutoSizeAxes = Axes.X,
|
Padding = new MarginPadding(PADDING),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
IconContainer = new ConstrainedIconContainer
|
BackgroundContent = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.CentreLeft,
|
Masking = true,
|
||||||
Size = new Vector2(20),
|
CornerRadius = 6,
|
||||||
Alpha = 0,
|
CornerExponent = 3f,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
HoverBackground = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuColour.Gray(80).Opacity(180),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
flashBackground = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
Colour = Color4.White.Opacity(100),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
DrawableText = new OsuSpriteText
|
Flow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Direction = FillDirection.Horizontal,
|
||||||
Origin = Anchor.CentreLeft,
|
Spacing = new Vector2(5),
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Padding = new MarginPadding { Left = Toolbar.HEIGHT / 2, Right = Toolbar.HEIGHT / 2 },
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
IconContainer = new ConstrainedIconContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Size = new Vector2(20),
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
DrawableText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -42,52 +42,59 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
clockDisplayMode = config.GetBindable<ToolbarClockDisplayMode>(OsuSetting.ToolbarClockDisplayMode);
|
clockDisplayMode = config.GetBindable<ToolbarClockDisplayMode>(OsuSetting.ToolbarClockDisplayMode);
|
||||||
prefer24HourTime = config.GetBindable<bool>(OsuSetting.Prefer24HourTime);
|
prefer24HourTime = config.GetBindable<bool>(OsuSetting.Prefer24HourTime);
|
||||||
|
|
||||||
Padding = new MarginPadding(3);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
CornerRadius = 6,
|
|
||||||
CornerExponent = 3f,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
hoverBackground = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = OsuColour.Gray(80).Opacity(180),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
Alpha = 0,
|
|
||||||
},
|
|
||||||
flashBackground = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Alpha = 0,
|
|
||||||
Colour = Color4.White.Opacity(100),
|
|
||||||
Blending = BlendingParameters.Additive,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Direction = FillDirection.Horizontal,
|
Padding = new MarginPadding(ToolbarButton.PADDING),
|
||||||
Spacing = new Vector2(5),
|
|
||||||
Padding = new MarginPadding(10),
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
analog = new AnalogClockDisplay
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.CentreLeft,
|
Masking = true,
|
||||||
|
CornerRadius = 6,
|
||||||
|
CornerExponent = 3f,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
hoverBackground = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuColour.Gray(80).Opacity(180),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
flashBackground = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
Colour = Color4.White.Opacity(100),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
digital = new DigitalClockDisplay
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Origin = Anchor.CentreLeft,
|
AutoSizeAxes = Axes.X,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
Padding = new MarginPadding(10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
analog = new AnalogClockDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
},
|
||||||
|
digital = new DigitalClockDisplay
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
{
|
{
|
||||||
public ToolbarHomeButton()
|
public ToolbarHomeButton()
|
||||||
{
|
{
|
||||||
Width *= 1.4f;
|
ButtonContent.Width *= 1.4f;
|
||||||
Hotkey = GlobalAction.Home;
|
Hotkey = GlobalAction.Home;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
public ToolbarMusicButton()
|
public ToolbarMusicButton()
|
||||||
{
|
{
|
||||||
Hotkey = GlobalAction.ToggleNowPlaying;
|
Hotkey = GlobalAction.ToggleNowPlaying;
|
||||||
AutoSizeAxes = Axes.X;
|
ButtonContent.AutoSizeAxes = Axes.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
public RulesetButton()
|
public RulesetButton()
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(3)
|
ButtonContent.Padding = new MarginPadding(PADDING)
|
||||||
{
|
{
|
||||||
Bottom = 5
|
Bottom = 5
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
{
|
{
|
||||||
public ToolbarSettingsButton()
|
public ToolbarSettingsButton()
|
||||||
{
|
{
|
||||||
Width *= 1.4f;
|
ButtonContent.Width *= 1.4f;
|
||||||
Hotkey = GlobalAction.ToggleSettings;
|
Hotkey = GlobalAction.ToggleSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
|
|
||||||
public ToolbarUserButton()
|
public ToolbarUserButton()
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.X;
|
ButtonContent.AutoSizeAxes = Axes.X;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -1,7 +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.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
@ -27,9 +26,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private EditorBeatmap beatmap { get; set; } = null!;
|
private EditorBeatmap beatmap { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private EditorClock editorClock { get; set; } = null!;
|
|
||||||
|
|
||||||
public DrawableEditorRulesetWrapper(DrawableRuleset<TObject> drawableRuleset)
|
public DrawableEditorRulesetWrapper(DrawableRuleset<TObject> drawableRuleset)
|
||||||
{
|
{
|
||||||
this.drawableRuleset = drawableRuleset;
|
this.drawableRuleset = drawableRuleset;
|
||||||
@ -42,6 +38,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
drawableRuleset.FrameStablePlayback = false;
|
||||||
Playfield.DisplayJudgements.Value = false;
|
Playfield.DisplayJudgements.Value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,22 +65,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
Scheduler.AddOnce(regenerateAutoplay);
|
Scheduler.AddOnce(regenerateAutoplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
// Whenever possible, we want to stay in frame stability playback.
|
|
||||||
// Without doing so, we run into bugs with some gameplay elements not behaving as expected.
|
|
||||||
//
|
|
||||||
// Note that this is not using EditorClock.IsSeeking as that would exit frame stability
|
|
||||||
// on all seeks. The intention here is to retain frame stability for small seeks.
|
|
||||||
//
|
|
||||||
// I still think no gameplay elements should require frame stability in the first place, but maybe that ship has sailed already..
|
|
||||||
bool shouldBypassFrameStability = Math.Abs(drawableRuleset.FrameStableClock.CurrentTime - editorClock.CurrentTime) > 1000;
|
|
||||||
|
|
||||||
drawableRuleset.FrameStablePlayback = !shouldBypassFrameStability;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void regenerateAutoplay()
|
private void regenerateAutoplay()
|
||||||
{
|
{
|
||||||
var autoplayMod = drawableRuleset.Mods.OfType<ModAutoplay>().Single();
|
var autoplayMod = drawableRuleset.Mods.OfType<ModAutoplay>().Single();
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Description(@"")]
|
[Description(@"")]
|
||||||
[EnumMember(Value = "none")]
|
[EnumMember(Value = "none")]
|
||||||
[Order(14)]
|
[Order(15)]
|
||||||
None,
|
None,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Indicates small tick miss.
|
/// Indicates small tick miss.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumMember(Value = "small_tick_miss")]
|
[EnumMember(Value = "small_tick_miss")]
|
||||||
[Order(11)]
|
[Order(12)]
|
||||||
SmallTickMiss,
|
SmallTickMiss,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumMember(Value = "large_tick_miss")]
|
[EnumMember(Value = "large_tick_miss")]
|
||||||
[Description("-")]
|
[Description("-")]
|
||||||
[Order(10)]
|
[Order(11)]
|
||||||
LargeTickMiss,
|
LargeTickMiss,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("S Bonus")]
|
[Description("S Bonus")]
|
||||||
[EnumMember(Value = "small_bonus")]
|
[EnumMember(Value = "small_bonus")]
|
||||||
[Order(9)]
|
[Order(10)]
|
||||||
SmallBonus,
|
SmallBonus,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("L Bonus")]
|
[Description("L Bonus")]
|
||||||
[EnumMember(Value = "large_bonus")]
|
[EnumMember(Value = "large_bonus")]
|
||||||
[Order(8)]
|
[Order(9)]
|
||||||
LargeBonus,
|
LargeBonus,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -119,14 +119,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumMember(Value = "ignore_miss")]
|
[EnumMember(Value = "ignore_miss")]
|
||||||
[Description("-")]
|
[Description("-")]
|
||||||
[Order(13)]
|
[Order(14)]
|
||||||
IgnoreMiss,
|
IgnoreMiss,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates a hit that should be ignored for scoring purposes.
|
/// Indicates a hit that should be ignored for scoring purposes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumMember(Value = "ignore_hit")]
|
[EnumMember(Value = "ignore_hit")]
|
||||||
[Order(12)]
|
[Order(13)]
|
||||||
IgnoreHit,
|
IgnoreHit,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -136,14 +136,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// May be paired with <see cref="IgnoreHit"/>.
|
/// May be paired with <see cref="IgnoreHit"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[EnumMember(Value = "combo_break")]
|
[EnumMember(Value = "combo_break")]
|
||||||
[Order(15)]
|
[Order(16)]
|
||||||
ComboBreak,
|
ComboBreak,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A special judgement similar to <see cref="LargeTickHit"/> that's used to increase the valuation of the final tick of a slider.
|
/// A special judgement similar to <see cref="LargeTickHit"/> that's used to increase the valuation of the final tick of a slider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumMember(Value = "slider_tail_hit")]
|
[EnumMember(Value = "slider_tail_hit")]
|
||||||
[Order(16)]
|
[Order(8)]
|
||||||
SliderTailHit,
|
SliderTailHit,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -146,14 +146,6 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSuspending(ScreenTransitionEvent e)
|
|
||||||
{
|
|
||||||
// Scores will be refreshed on arriving at this screen.
|
|
||||||
// Clear them to avoid animation overload on returning to song select.
|
|
||||||
playBeatmapDetailArea.Leaderboard.ClearScores();
|
|
||||||
base.OnSuspending(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnResuming(ScreenTransitionEvent e)
|
public override void OnResuming(ScreenTransitionEvent e)
|
||||||
{
|
{
|
||||||
base.OnResuming(e);
|
base.OnResuming(e);
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="11.5.0" />
|
<PackageReference Include="Realm" Version="11.5.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2024.113.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2024.114.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.1228.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.1228.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.40.0" />
|
<PackageReference Include="Sentry" Version="3.40.0" />
|
||||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||||
|
@ -23,6 +23,6 @@
|
|||||||
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2024.113.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2024.114.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
Reference in New Issue
Block a user