mirror of
https://github.com/ppy/osu.git
synced 2025-02-28 03:53:20 +08:00
Merge branch 'master' into fix-spectator-random-mod
This commit is contained in:
commit
623377772c
@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
[TestCase(6.7568168283591499d, "diffcalc-test")]
|
[TestCase(6.6634445062299665d, "diffcalc-test")]
|
||||||
[TestCase(1.0348244046058293d, "zero-length-sliders")]
|
[TestCase(1.0414203870195022d, "zero-length-sliders")]
|
||||||
public void Test(double expected, string name)
|
public void Test(double expected, string name)
|
||||||
=> base.Test(expected, name);
|
=> base.Test(expected, name);
|
||||||
|
|
||||||
[TestCase(8.4783236764532557d, "diffcalc-test")]
|
[TestCase(8.3858089051603368d, "diffcalc-test")]
|
||||||
[TestCase(1.2708532136987165d, "zero-length-sliders")]
|
[TestCase(1.2723279173428435d, "zero-length-sliders")]
|
||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new OsuModDoubleTime());
|
=> Test(expected, name, new OsuModDoubleTime());
|
||||||
|
|
||||||
|
@ -34,7 +34,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||||
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
|
|
||||||
|
double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000;
|
||||||
|
double baseSpeedPerformance = Math.Pow(5 * Math.Max(1, speedRating / 0.0675) - 4, 3) / 100000;
|
||||||
|
double basePerformance = Math.Pow(Math.Pow(baseAimPerformance, 1.1) + Math.Pow(baseSpeedPerformance, 1.1), 1 / 1.1);
|
||||||
|
double starRating = basePerformance > 0.00001 ? Math.Cbrt(1.12) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0;
|
||||||
|
|
||||||
HitWindows hitWindows = new OsuHitWindows();
|
HitWindows hitWindows = new OsuHitWindows();
|
||||||
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||||
|
@ -55,6 +55,59 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClockPositionPreservedBetweenSwitches()
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
AddStep("seek editor to 00:05:00", () => EditorClock.Seek(5000));
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo)));
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
AddAssert("editor clock at 00:05:00", () => EditorClock.CurrentTime == 5000);
|
||||||
|
|
||||||
|
AddStep("exit editor", () => Stack.Exit());
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClipboardPreservedAfterSwitch([Values] bool sameRuleset)
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
|
||||||
|
AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.First()));
|
||||||
|
AddStep("copy object", () => Editor.Copy());
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () =>
|
||||||
|
{
|
||||||
|
targetDifficulty = sameRuleset
|
||||||
|
? importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.RulesetID == Beatmap.Value.BeatmapInfo.RulesetID)
|
||||||
|
: importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.RulesetID != Beatmap.Value.BeatmapInfo.RulesetID);
|
||||||
|
});
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
|
||||||
|
AddAssert("no objects selected", () => !EditorBeatmap.SelectedHitObjects.Any());
|
||||||
|
AddStep("paste object", () => Editor.Paste());
|
||||||
|
|
||||||
|
if (sameRuleset)
|
||||||
|
AddAssert("object was pasted", () => EditorBeatmap.SelectedHitObjects.Any());
|
||||||
|
else
|
||||||
|
AddAssert("object was not pasted", () => !EditorBeatmap.SelectedHitObjects.Any());
|
||||||
|
|
||||||
|
AddStep("exit editor", () => Stack.Exit());
|
||||||
|
|
||||||
|
if (sameRuleset)
|
||||||
|
{
|
||||||
|
AddUntilStep("prompt for save dialog shown", () => DialogOverlay.CurrentDialog is PromptForSaveDialog);
|
||||||
|
AddStep("discard changes", () => ((PromptForSaveDialog)DialogOverlay.CurrentDialog).PerformOkAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestPreventSwitchDueToUnsavedChanges()
|
public void TestPreventSwitchDueToUnsavedChanges()
|
||||||
{
|
{
|
||||||
@ -118,7 +171,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
private void confirmEditingBeatmap(Func<BeatmapInfo> targetDifficulty)
|
private void confirmEditingBeatmap(Func<BeatmapInfo> targetDifficulty)
|
||||||
{
|
{
|
||||||
AddUntilStep("current beatmap is correct", () => Beatmap.Value.BeatmapInfo.Equals(targetDifficulty.Invoke()));
|
AddUntilStep("current beatmap is correct", () => Beatmap.Value.BeatmapInfo.Equals(targetDifficulty.Invoke()));
|
||||||
AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor);
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen == Editor && Editor?.IsLoaded == true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -82,7 +83,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestJoinRoomWithPassword()
|
public void TestJoinRoomWithIncorrectPassword()
|
||||||
|
{
|
||||||
|
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||||
|
|
||||||
|
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
|
||||||
|
AddStep("select room", () => InputManager.Key(Key.Down));
|
||||||
|
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
|
||||||
|
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
|
||||||
|
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType<TextBox>().First().Text = "wrong");
|
||||||
|
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType<OsuButton>().First().TriggerClick());
|
||||||
|
|
||||||
|
AddAssert("room not joined", () => loungeScreen.IsCurrentScreen());
|
||||||
|
AddUntilStep("password prompt still visible", () => passwordEntryPopover.State.Value == Visibility.Visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestJoinRoomWithCorrectPassword()
|
||||||
{
|
{
|
||||||
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null;
|
||||||
|
|
||||||
|
@ -38,6 +38,33 @@ namespace osu.Game.Extensions
|
|||||||
return repeatDelegate;
|
return repeatDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shakes this drawable.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">The target to shake.</param>
|
||||||
|
/// <param name="shakeDuration">The length of a single shake.</param>
|
||||||
|
/// <param name="shakeMagnitude">Pixels of displacement per shake.</param>
|
||||||
|
/// <param name="maximumLength">The maximum length the shake should last.</param>
|
||||||
|
public static void Shake(this Drawable target, double shakeDuration = 80, float shakeMagnitude = 8, double? maximumLength = null)
|
||||||
|
{
|
||||||
|
// if we don't have enough time, don't bother shaking.
|
||||||
|
if (maximumLength < shakeDuration * 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var sequence = target.MoveToX(shakeMagnitude, shakeDuration / 2, Easing.OutSine).Then()
|
||||||
|
.MoveToX(-shakeMagnitude, shakeDuration, Easing.InOutSine).Then();
|
||||||
|
|
||||||
|
// if we don't have enough time for the second shake, skip it.
|
||||||
|
if (!maximumLength.HasValue || maximumLength >= shakeDuration * 4)
|
||||||
|
{
|
||||||
|
sequence = sequence
|
||||||
|
.MoveToX(shakeMagnitude, shakeDuration, Easing.InOutSine).Then()
|
||||||
|
.MoveToX(-shakeMagnitude, shakeDuration, Easing.InOutSine).Then();
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence.MoveToX(0, shakeDuration / 2, Easing.InSine);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Accepts a delta vector in screen-space coordinates and converts it to one which can be applied to this drawable's position.
|
/// Accepts a delta vector in screen-space coordinates and converts it to one which can be applied to this drawable's position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,8 +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.
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Extensions;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
@ -16,40 +16,10 @@ namespace osu.Game.Graphics.Containers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float ShakeDuration = 80;
|
public float ShakeDuration = 80;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Total number of shakes. May be shortened if possible.
|
|
||||||
/// </summary>
|
|
||||||
public float TotalShakes = 4;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Pixels of displacement per shake.
|
|
||||||
/// </summary>
|
|
||||||
public float ShakeMagnitude = 8;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shake the contents of this container.
|
/// Shake the contents of this container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="maximumLength">The maximum length the shake should last.</param>
|
/// <param name="maximumLength">The maximum length the shake should last.</param>
|
||||||
public void Shake(double? maximumLength = null)
|
public void Shake(double? maximumLength = null) => this.Shake(ShakeDuration, maximumLength: maximumLength);
|
||||||
{
|
|
||||||
const float shake_amount = 8;
|
|
||||||
|
|
||||||
// if we don't have enough time, don't bother shaking.
|
|
||||||
if (maximumLength < ShakeDuration * 2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var sequence = this.MoveToX(shake_amount, ShakeDuration / 2, Easing.OutSine).Then()
|
|
||||||
.MoveToX(-shake_amount, ShakeDuration, Easing.InOutSine).Then();
|
|
||||||
|
|
||||||
// if we don't have enough time for the second shake, skip it.
|
|
||||||
if (!maximumLength.HasValue || maximumLength >= ShakeDuration * 4)
|
|
||||||
{
|
|
||||||
sequence = sequence
|
|
||||||
.MoveToX(shake_amount, ShakeDuration, Easing.InOutSine).Then()
|
|
||||||
.MoveToX(-shake_amount, ShakeDuration, Easing.InOutSine).Then();
|
|
||||||
}
|
|
||||||
|
|
||||||
sequence.MoveToX(0, ShakeDuration / 2, Easing.InSine);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Screens.Edit.Compose
|
|||||||
public bool OnPressed(PlatformAction action)
|
public bool OnPressed(PlatformAction action)
|
||||||
{
|
{
|
||||||
if (action == PlatformAction.Copy)
|
if (action == PlatformAction.Copy)
|
||||||
host.GetClipboard().SetText(formatSelectionAsString());
|
host.GetClipboard()?.SetText(formatSelectionAsString());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -317,6 +317,16 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateClockSource() => clock.ChangeSource(Beatmap.Value.Track);
|
public void UpdateClockSource() => clock.ChangeSource(Beatmap.Value.Track);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restore the editor to a provided state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">The state to restore.</param>
|
||||||
|
public void RestoreState([NotNull] EditorState state) => Schedule(() =>
|
||||||
|
{
|
||||||
|
clock.Seek(state.Time);
|
||||||
|
clipboard.Value = state.ClipboardContent;
|
||||||
|
});
|
||||||
|
|
||||||
protected void Save()
|
protected void Save()
|
||||||
{
|
{
|
||||||
// no longer new after first user-triggered save.
|
// no longer new after first user-triggered save.
|
||||||
@ -740,7 +750,11 @@ namespace osu.Game.Screens.Edit
|
|||||||
return new DifficultyMenuItem(beatmapInfo, isCurrentDifficulty, SwitchToDifficulty);
|
return new DifficultyMenuItem(beatmapInfo, isCurrentDifficulty, SwitchToDifficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SwitchToDifficulty(BeatmapInfo beatmapInfo) => loader?.ScheduleDifficultySwitch(beatmapInfo);
|
protected void SwitchToDifficulty(BeatmapInfo nextBeatmap) => loader?.ScheduleDifficultySwitch(nextBeatmap, new EditorState
|
||||||
|
{
|
||||||
|
Time = clock.CurrentTimeAccurate,
|
||||||
|
ClipboardContent = editorBeatmap.BeatmapInfo.RulesetID == nextBeatmap.RulesetID ? clipboard.Value : string.Empty
|
||||||
|
});
|
||||||
|
|
||||||
private void cancelExit() => loader?.CancelPendingDifficultySwitch();
|
private void cancelExit() => loader?.CancelPendingDifficultySwitch();
|
||||||
|
|
||||||
|
@ -20,6 +20,13 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EditorLoader : ScreenWithBeatmapBackground
|
public class EditorLoader : ScreenWithBeatmapBackground
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The stored state from the last editor opened.
|
||||||
|
/// This will be read by the next editor instance to be opened to restore any relevant previous state.
|
||||||
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
|
private EditorState state;
|
||||||
|
|
||||||
public override float BackgroundParallaxAmount => 0.1f;
|
public override float BackgroundParallaxAmount => 0.1f;
|
||||||
|
|
||||||
public override bool AllowBackButton => false;
|
public override bool AllowBackButton => false;
|
||||||
@ -61,7 +68,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScheduleDifficultySwitch(BeatmapInfo beatmapInfo)
|
public void ScheduleDifficultySwitch(BeatmapInfo nextBeatmap, EditorState editorState)
|
||||||
{
|
{
|
||||||
scheduledDifficultySwitch?.Cancel();
|
scheduledDifficultySwitch?.Cancel();
|
||||||
ValidForResume = true;
|
ValidForResume = true;
|
||||||
@ -70,7 +77,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
scheduledDifficultySwitch = Schedule(() =>
|
scheduledDifficultySwitch = Schedule(() =>
|
||||||
{
|
{
|
||||||
Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo);
|
Beatmap.Value = beatmapManager.GetWorkingBeatmap(nextBeatmap);
|
||||||
|
state = editorState;
|
||||||
|
|
||||||
// This screen is a weird exception to the rule that nothing after song select changes the global beatmap.
|
// This screen is a weird exception to the rule that nothing after song select changes the global beatmap.
|
||||||
// Because of this, we need to update the background stack's beatmap to match.
|
// Because of this, we need to update the background stack's beatmap to match.
|
||||||
@ -83,7 +91,13 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private void pushEditor()
|
private void pushEditor()
|
||||||
{
|
{
|
||||||
this.Push(CreateEditor());
|
var editor = CreateEditor();
|
||||||
|
|
||||||
|
this.Push(editor);
|
||||||
|
|
||||||
|
if (state != null)
|
||||||
|
editor.RestoreState(state);
|
||||||
|
|
||||||
ValidForResume = false;
|
ValidForResume = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
23
osu.Game/Screens/Edit/EditorState.cs
Normal file
23
osu.Game/Screens/Edit/EditorState.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Structure used to convey the general state of an <see cref="Editor"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public class EditorState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The current audio time.
|
||||||
|
/// </summary>
|
||||||
|
public double Time { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The editor clipboard content.
|
||||||
|
/// </summary>
|
||||||
|
public string ClipboardContent { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
@ -87,9 +87,10 @@ namespace osu.Game.Screens.OnlinePlay.Components
|
|||||||
|
|
||||||
currentJoinRoomRequest.Failure += exception =>
|
currentJoinRoomRequest.Failure += exception =>
|
||||||
{
|
{
|
||||||
if (!(exception is OperationCanceledException))
|
if (exception is OperationCanceledException)
|
||||||
Logger.Log($"Failed to join room: {exception}", level: LogLevel.Important);
|
return;
|
||||||
onError?.Invoke(exception.ToString());
|
|
||||||
|
onError?.Invoke(exception.Message);
|
||||||
};
|
};
|
||||||
|
|
||||||
api.Queue(currentJoinRoomRequest);
|
api.Queue(currentJoinRoomRequest);
|
||||||
|
@ -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.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
@ -15,6 +14,9 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Extensions;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
@ -120,7 +122,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Popover GetPopover() => new PasswordEntryPopover(Room) { JoinRequested = lounge.Join };
|
public Popover GetPopover() => new PasswordEntryPopover(Room);
|
||||||
|
|
||||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
{
|
{
|
||||||
@ -176,7 +178,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
{
|
{
|
||||||
private readonly Room room;
|
private readonly Room room;
|
||||||
|
|
||||||
public Action<Room, string> JoinRequested;
|
[Resolved(canBeNull: true)]
|
||||||
|
private LoungeSubScreen lounge { get; set; }
|
||||||
|
|
||||||
public PasswordEntryPopover(Room room)
|
public PasswordEntryPopover(Room room)
|
||||||
{
|
{
|
||||||
@ -184,30 +187,61 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
}
|
}
|
||||||
|
|
||||||
private OsuPasswordTextBox passwordTextbox;
|
private OsuPasswordTextBox passwordTextbox;
|
||||||
|
private TriangleButton joinButton;
|
||||||
|
private OsuSpriteText errorText;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Child = new FillFlowContainer
|
Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding(10),
|
Margin = new MarginPadding(10),
|
||||||
Spacing = new Vector2(5),
|
Spacing = new Vector2(5),
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
passwordTextbox = new OsuPasswordTextBox
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Width = 200,
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
passwordTextbox = new OsuPasswordTextBox
|
||||||
|
{
|
||||||
|
Width = 200,
|
||||||
|
PlaceholderText = "password",
|
||||||
|
},
|
||||||
|
joinButton = new TriangleButton
|
||||||
|
{
|
||||||
|
Width = 80,
|
||||||
|
Text = "Join Room",
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new TriangleButton
|
errorText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Width = 80,
|
Colour = colours.Red,
|
||||||
Text = "Join Room",
|
},
|
||||||
Action = () => JoinRequested?.Invoke(room, passwordTextbox.Text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
joinButton.Action = () => lounge?.Join(room, passwordTextbox.Text, null, joinFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void joinFailed(string error)
|
||||||
|
{
|
||||||
|
passwordTextbox.Text = string.Empty;
|
||||||
|
|
||||||
|
errorText.Text = error;
|
||||||
|
errorText
|
||||||
|
.FadeIn()
|
||||||
|
.FlashColour(Color4.White, 200)
|
||||||
|
.Delay(1000)
|
||||||
|
.FadeOutFromOne(1000, Easing.In);
|
||||||
|
|
||||||
|
Body.Shake();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -215,7 +249,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox));
|
Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox));
|
||||||
passwordTextbox.OnCommit += (_, __) => JoinRequested?.Invoke(room, passwordTextbox.Text);
|
passwordTextbox.OnCommit += (_, __) => lounge?.Join(room, passwordTextbox.Text, null, joinFailed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
popoverContainer.HidePopover();
|
popoverContainer.HidePopover();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Join(Room room, string password) => Schedule(() =>
|
public void Join(Room room, string password, Action<Room> onSuccess = null, Action<string> onFailure = null) => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (joiningRoomOperation != null)
|
if (joiningRoomOperation != null)
|
||||||
return;
|
return;
|
||||||
@ -302,10 +302,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
Open(room);
|
Open(room);
|
||||||
joiningRoomOperation?.Dispose();
|
joiningRoomOperation?.Dispose();
|
||||||
joiningRoomOperation = null;
|
joiningRoomOperation = null;
|
||||||
}, _ =>
|
onSuccess?.Invoke(room);
|
||||||
|
}, error =>
|
||||||
{
|
{
|
||||||
joiningRoomOperation?.Dispose();
|
joiningRoomOperation?.Dispose();
|
||||||
joiningRoomOperation = null;
|
joiningRoomOperation = null;
|
||||||
|
onFailure?.Invoke(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,7 +23,10 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
protected abstract string ResourceAssembly { get; }
|
protected abstract string ResourceAssembly { get; }
|
||||||
|
|
||||||
protected void Test(double expected, string name, params Mod[] mods)
|
protected void Test(double expected, string name, params Mod[] mods)
|
||||||
=> Assert.AreEqual(expected, CreateDifficultyCalculator(getBeatmap(name)).Calculate(mods).StarRating);
|
{
|
||||||
|
// Platform-dependent math functions (Pow, Cbrt, Exp, etc) may result in minute differences.
|
||||||
|
Assert.That(CreateDifficultyCalculator(getBeatmap(name)).Calculate(mods).StarRating, Is.EqualTo(expected).Within(0.00001));
|
||||||
|
}
|
||||||
|
|
||||||
private WorkingBeatmap getBeatmap(string name)
|
private WorkingBeatmap getBeatmap(string name)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user