mirror of
https://github.com/osukey/osukey.git
synced 2025-08-06 16:13:57 +09:00
Merge branch 'master' into hitobject-pooling-base
This commit is contained in:
50
.vscode/tasks.json
vendored
50
.vscode/tasks.json
vendored
@ -11,9 +11,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Desktop",
|
"osu.Desktop",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -26,10 +26,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Desktop",
|
"osu.Desktop",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -42,9 +42,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Tests",
|
"osu.Game.Tests",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -57,10 +57,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Tests",
|
"osu.Game.Tests",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -73,9 +73,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Tournament.Tests",
|
"osu.Game.Tournament.Tests",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -88,10 +88,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Tournament.Tests",
|
"osu.Game.Tournament.Tests",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -104,10 +104,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Benchmarks",
|
"osu.Game.Benchmarks",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
|
@ -135,6 +135,9 @@ namespace osu.Desktop
|
|||||||
|
|
||||||
case UserActivity.Editing edit:
|
case UserActivity.Editing edit:
|
||||||
return edit.Beatmap.ToString();
|
return edit.Beatmap.ToString();
|
||||||
|
|
||||||
|
case UserActivity.InLobby lobby:
|
||||||
|
return lobby.Room.Name.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
14
osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json
vendored
14
osu.Game.Rulesets.Catch.Tests/.vscode/tasks.json
vendored
@ -11,9 +11,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -26,10 +26,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Catch.Tests.csproj",
|
"osu.Game.Rulesets.Catch.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
|
14
osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json
vendored
14
osu.Game.Rulesets.Mania.Tests/.vscode/tasks.json
vendored
@ -11,9 +11,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -26,10 +26,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Mania.Tests.csproj",
|
"osu.Game.Rulesets.Mania.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
|
14
osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json
vendored
14
osu.Game.Rulesets.Osu.Tests/.vscode/tasks.json
vendored
@ -11,9 +11,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -26,10 +26,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Osu.Tests.csproj",
|
"osu.Game.Rulesets.Osu.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
|
@ -280,8 +280,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
|
|
||||||
private void addClickStep(MouseButton button)
|
private void addClickStep(MouseButton button)
|
||||||
{
|
{
|
||||||
AddStep($"press {button}", () => InputManager.PressButton(button));
|
AddStep($"click {button}", () => InputManager.Click(button));
|
||||||
AddStep($"release {button}", () => InputManager.ReleaseButton(button));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertPlaced(bool expected) => AddAssert($"slider {(expected ? "placed" : "not placed")}", () => (getSlider() != null) == expected);
|
private void assertPlaced(bool expected) => AddAssert($"slider {(expected ? "placed" : "not placed")}", () => (getSlider() != null) == expected);
|
||||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
public void UpdateProgress(double completionProgress)
|
public void UpdateProgress(double completionProgress)
|
||||||
{
|
{
|
||||||
if (drawableSlider == null)
|
if (drawableSlider?.HitObject == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Slider slider = drawableSlider.HitObject;
|
Slider slider = drawableSlider.HitObject;
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
public void Refresh()
|
public void Refresh()
|
||||||
{
|
{
|
||||||
if (drawableSlider == null)
|
if (drawableSlider?.HitObject == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Generate the entire curve
|
// Generate the entire curve
|
||||||
|
14
osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json
vendored
14
osu.Game.Rulesets.Taiko.Tests/.vscode/tasks.json
vendored
@ -11,9 +11,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -26,10 +26,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
"osu.Game.Rulesets.Taiko.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
|
@ -41,11 +41,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("store time", () => time = Player.GameplayClockContainer.GameplayClock.CurrentTime);
|
AddStep("store time", () => time = Player.GameplayClockContainer.GameplayClock.CurrentTime);
|
||||||
|
|
||||||
// test seek via keyboard
|
// test seek via keyboard
|
||||||
AddStep("seek with right arrow key", () => press(Key.Right));
|
AddStep("seek with right arrow key", () => InputManager.Key(Key.Right));
|
||||||
AddAssert("time seeked forward", () => Player.GameplayClockContainer.GameplayClock.CurrentTime > time + 2000);
|
AddAssert("time seeked forward", () => Player.GameplayClockContainer.GameplayClock.CurrentTime > time + 2000);
|
||||||
|
|
||||||
AddStep("store time", () => time = Player.GameplayClockContainer.GameplayClock.CurrentTime);
|
AddStep("store time", () => time = Player.GameplayClockContainer.GameplayClock.CurrentTime);
|
||||||
AddStep("seek with left arrow key", () => press(Key.Left));
|
AddStep("seek with left arrow key", () => InputManager.Key(Key.Left));
|
||||||
AddAssert("time seeked backward", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < time);
|
AddAssert("time seeked backward", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < time);
|
||||||
|
|
||||||
seekToBreak(0);
|
seekToBreak(0);
|
||||||
@ -67,11 +67,5 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
|
BreakPeriod destBreak() => Beatmap.Value.Beatmap.Breaks.ElementAt(breakIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void press(Key key)
|
|
||||||
{
|
|
||||||
InputManager.PressKey(key);
|
|
||||||
InputManager.ReleaseKey(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
showOverlay();
|
showOverlay();
|
||||||
|
|
||||||
AddStep("Up arrow", () => press(Key.Up));
|
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||||
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected.Value);
|
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
showOverlay();
|
showOverlay();
|
||||||
|
|
||||||
AddStep("Down arrow", () => press(Key.Down));
|
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,11 +110,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddStep("Show overlay", () => failOverlay.Show());
|
AddStep("Show overlay", () => failOverlay.Show());
|
||||||
|
|
||||||
AddStep("Up arrow", () => press(Key.Up));
|
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||||
AddStep("Up arrow", () => press(Key.Up));
|
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||||
AddStep("Up arrow", () => press(Key.Up));
|
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,11 +126,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddStep("Show overlay", () => failOverlay.Show());
|
AddStep("Show overlay", () => failOverlay.Show());
|
||||||
|
|
||||||
AddStep("Down arrow", () => press(Key.Down));
|
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||||
AddStep("Down arrow", () => press(Key.Down));
|
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||||
AddStep("Down arrow", () => press(Key.Down));
|
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
showOverlay();
|
showOverlay();
|
||||||
|
|
||||||
AddStep("Down arrow", () => press(Key.Down));
|
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||||
AddAssert("First button not selected", () => !getButton(0).Selected.Value);
|
AddAssert("First button not selected", () => !getButton(0).Selected.Value);
|
||||||
AddAssert("Second button selected", () => getButton(1).Selected.Value);
|
AddAssert("Second button selected", () => getButton(1).Selected.Value);
|
||||||
@ -195,7 +195,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||||
AddStep("Up arrow", () => press(Key.Up));
|
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||||
AddAssert("Second button not selected", () => !getButton(1).Selected.Value);
|
AddAssert("Second button not selected", () => !getButton(1).Selected.Value);
|
||||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||||
}
|
}
|
||||||
@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||||
AddStep("Unhover second button", () => InputManager.MoveMouseTo(Vector2.Zero));
|
AddStep("Unhover second button", () => InputManager.MoveMouseTo(Vector2.Zero));
|
||||||
AddStep("Down arrow", () => press(Key.Down));
|
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||||
AddAssert("First button selected", () => getButton(0).Selected.Value); // Initial state condition
|
AddAssert("First button selected", () => getButton(0).Selected.Value); // Initial state condition
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,8 +246,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddStep("Select second button", () =>
|
AddStep("Select second button", () =>
|
||||||
{
|
{
|
||||||
press(Key.Down);
|
InputManager.Key(Key.Down);
|
||||||
press(Key.Down);
|
InputManager.Key(Key.Down);
|
||||||
});
|
});
|
||||||
|
|
||||||
bool triggered = false;
|
bool triggered = false;
|
||||||
@ -256,7 +256,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
lastAction = pauseOverlay.OnRetry;
|
lastAction = pauseOverlay.OnRetry;
|
||||||
pauseOverlay.OnRetry = () => triggered = true;
|
pauseOverlay.OnRetry = () => triggered = true;
|
||||||
press(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Action was triggered", () =>
|
AddAssert("Action was triggered", () =>
|
||||||
@ -290,12 +290,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
private DialogButton getButton(int index) => pauseOverlay.Buttons.Skip(index).First();
|
private DialogButton getButton(int index) => pauseOverlay.Buttons.Skip(index).First();
|
||||||
|
|
||||||
private void press(Key key)
|
|
||||||
{
|
|
||||||
InputManager.PressKey(key);
|
|
||||||
InputManager.ReleaseKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void press(GlobalAction action)
|
private void press(GlobalAction action)
|
||||||
{
|
{
|
||||||
globalActionContainer.TriggerPressed(action);
|
globalActionContainer.TriggerPressed(action);
|
||||||
|
@ -32,11 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDefaultsWhenNotDatabased()
|
public void TestDefaultsWhenNotDatabased()
|
||||||
{
|
{
|
||||||
AddStep("fire key", () =>
|
AddStep("fire key", () => InputManager.Key(Key.A));
|
||||||
{
|
|
||||||
InputManager.PressKey(Key.A);
|
|
||||||
InputManager.ReleaseKey(Key.A);
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAssert("received key", () => receiver.ReceivedAction);
|
AddAssert("received key", () => receiver.ReceivedAction);
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
void addPressKeyStep()
|
void addPressKeyStep()
|
||||||
{
|
{
|
||||||
AddStep($"Press {testKey} key", () =>
|
AddStep($"Press {testKey} key", () => InputManager.Key(testKey));
|
||||||
{
|
|
||||||
InputManager.PressKey(testKey);
|
|
||||||
InputManager.ReleaseKey(testKey);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addPressKeyStep();
|
addPressKeyStep();
|
||||||
|
@ -59,11 +59,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
confirmClockRunning(false);
|
confirmClockRunning(false);
|
||||||
confirmPauseOverlayShown(false);
|
confirmPauseOverlayShown(false);
|
||||||
|
|
||||||
AddStep("click to resume", () =>
|
AddStep("click to resume", () => InputManager.Click(MouseButton.Left));
|
||||||
{
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
});
|
|
||||||
|
|
||||||
confirmClockRunning(true);
|
confirmClockRunning(true);
|
||||||
}
|
}
|
||||||
|
@ -158,8 +158,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("much move with press", () => moveFunction = Scheduler.AddDelayed(() =>
|
AddStep("much move with press", () => moveFunction = Scheduler.AddDelayed(() =>
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(-1, 0));
|
InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(-1, 0));
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
}, 10, true));
|
}, 10, true));
|
||||||
AddWaitStep("move", 10);
|
AddWaitStep("move", 10);
|
||||||
AddStep("stop move", () => moveFunction.Cancel());
|
AddStep("stop move", () => moveFunction.Cancel());
|
||||||
|
@ -65,10 +65,8 @@ namespace osu.Game.Tests.Visual.Menus
|
|||||||
AddStep($"switch to ruleset {i} via shortcut", () =>
|
AddStep($"switch to ruleset {i} via shortcut", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.ControlLeft);
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
InputManager.PressKey(numberKey);
|
InputManager.Key(numberKey);
|
||||||
|
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
InputManager.ReleaseKey(numberKey);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("ruleset switched", () => rulesetSelector.Current.Value.Equals(expected));
|
AddUntilStep("ruleset switched", () => rulesetSelector.Current.Value.Equals(expected));
|
||||||
|
@ -71,11 +71,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
|
|
||||||
private void press(Key down)
|
private void press(Key down)
|
||||||
{
|
{
|
||||||
AddStep($"press {down}", () =>
|
AddStep($"press {down}", () => InputManager.Key(down));
|
||||||
{
|
|
||||||
InputManager.PressKey(down);
|
|
||||||
InputManager.ReleaseKey(down);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
if (withUserPause)
|
if (withUserPause)
|
||||||
AddStep("pause", () => Game.Dependencies.Get<MusicController>().Stop(true));
|
AddStep("pause", () => Game.Dependencies.Get<MusicController>().Stop(true));
|
||||||
|
|
||||||
AddStep("press enter", () => pressAndRelease(Key.Enter));
|
AddStep("press enter", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
|
AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
|
||||||
AddUntilStep("wait for fail", () => player.HasFailed);
|
AddUntilStep("wait for fail", () => player.HasFailed);
|
||||||
@ -122,11 +122,11 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
public void TestOpenOptionsAndExitWithEscape()
|
public void TestOpenOptionsAndExitWithEscape()
|
||||||
{
|
{
|
||||||
AddUntilStep("Wait for options to load", () => Game.Settings.IsLoaded);
|
AddUntilStep("Wait for options to load", () => Game.Settings.IsLoaded);
|
||||||
AddStep("Enter menu", () => pressAndRelease(Key.Enter));
|
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
|
||||||
AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition));
|
AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition));
|
||||||
AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left));
|
AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Options overlay was opened", () => Game.Settings.State.Value == Visibility.Visible);
|
AddAssert("Options overlay was opened", () => Game.Settings.State.Value == Visibility.Visible);
|
||||||
AddStep("Hide options overlay using escape", () => pressAndRelease(Key.Escape));
|
AddStep("Hide options overlay using escape", () => InputManager.Key(Key.Escape));
|
||||||
AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
|
AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,10 +158,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddStep("Change ruleset to osu!taiko", () =>
|
AddStep("Change ruleset to osu!taiko", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.ControlLeft);
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
InputManager.PressKey(Key.Number2);
|
InputManager.Key(Key.Number2);
|
||||||
|
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
InputManager.ReleaseKey(Key.Number2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.ID == 1);
|
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.ID == 1);
|
||||||
@ -181,10 +179,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddStep("Change ruleset to osu!taiko", () =>
|
AddStep("Change ruleset to osu!taiko", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.ControlLeft);
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
InputManager.PressKey(Key.Number2);
|
InputManager.Key(Key.Number2);
|
||||||
|
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
InputManager.ReleaseKey(Key.Number2);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.ID == 1);
|
AddAssert("Ruleset changed to osu!taiko", () => Game.Toolbar.ChildrenOfType<ToolbarRulesetSelector>().Single().Current.Value.ID == 1);
|
||||||
@ -193,7 +189,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void pushEscape() =>
|
private void pushEscape() =>
|
||||||
AddStep("Press escape", () => pressAndRelease(Key.Escape));
|
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
private void exitViaEscapeAndConfirm()
|
private void exitViaEscapeAndConfirm()
|
||||||
{
|
{
|
||||||
@ -208,12 +204,6 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
ConfirmAtMainMenu();
|
ConfirmAtMainMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pressAndRelease(Key key)
|
|
||||||
{
|
|
||||||
InputManager.PressKey(key);
|
|
||||||
InputManager.ReleaseKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestSongSelect : PlaySongSelect
|
private class TestSongSelect : PlaySongSelect
|
||||||
{
|
{
|
||||||
public ModSelectOverlay ModSelectOverlay => ModSelect;
|
public ModSelectOverlay ModSelectOverlay => ModSelect;
|
||||||
|
@ -103,11 +103,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
public void TestChannelShortcutKeys()
|
public void TestChannelShortcutKeys()
|
||||||
{
|
{
|
||||||
AddStep("Join channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
AddStep("Join channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
|
||||||
AddStep("Close channel selector", () =>
|
AddStep("Close channel selector", () => InputManager.Key(Key.Escape));
|
||||||
{
|
|
||||||
InputManager.PressKey(Key.Escape);
|
|
||||||
InputManager.ReleaseKey(Key.Escape);
|
|
||||||
});
|
|
||||||
AddUntilStep("Wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
AddUntilStep("Wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
|
||||||
|
|
||||||
for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex)
|
for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex)
|
||||||
@ -216,9 +212,8 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
{
|
{
|
||||||
var channelKey = Key.Number0 + number;
|
var channelKey = Key.Number0 + number;
|
||||||
InputManager.PressKey(Key.AltLeft);
|
InputManager.PressKey(Key.AltLeft);
|
||||||
InputManager.PressKey(channelKey);
|
InputManager.Key(channelKey);
|
||||||
InputManager.ReleaseKey(Key.AltLeft);
|
InputManager.ReleaseKey(Key.AltLeft);
|
||||||
InputManager.ReleaseKey(channelKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clickDrawable(Drawable d)
|
private void clickDrawable(Drawable d)
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestGenericActivity()
|
public void TestGenericActivity()
|
||||||
{
|
{
|
||||||
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby());
|
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby(null));
|
||||||
|
|
||||||
AddStep("Run command", () => Add(new NowPlayingCommand()));
|
AddStep("Run command", () => Add(new NowPlayingCommand()));
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
public void TestLinkPresence(bool hasOnlineId)
|
public void TestLinkPresence(bool hasOnlineId)
|
||||||
{
|
{
|
||||||
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby());
|
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby(null));
|
||||||
|
|
||||||
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
|
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
|
||||||
{
|
{
|
||||||
|
57
osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs
Normal file
57
osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Game.Overlays.Profile.Sections.Historical;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using static osu.Game.Users.User;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Online
|
||||||
|
{
|
||||||
|
public class TestSceneUserHistoryGraph : OsuTestScene
|
||||||
|
{
|
||||||
|
[Cached]
|
||||||
|
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
|
||||||
|
|
||||||
|
public TestSceneUserHistoryGraph()
|
||||||
|
{
|
||||||
|
UserHistoryGraph graph;
|
||||||
|
|
||||||
|
Add(graph = new UserHistoryGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 200,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
TooltipCounterName = "Test"
|
||||||
|
});
|
||||||
|
|
||||||
|
var values = new[]
|
||||||
|
{
|
||||||
|
new UserHistoryCount { Date = new DateTime(2000, 1, 1), Count = 10 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2000, 2, 1), Count = 20 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2000, 3, 1), Count = 100 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2000, 4, 1), Count = 15 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2000, 5, 1), Count = 30 }
|
||||||
|
};
|
||||||
|
|
||||||
|
var moreValues = new[]
|
||||||
|
{
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 5, 1), Count = 1000 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 6, 1), Count = 20 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 7, 1), Count = 20000 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 8, 1), Count = 30 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 9, 1), Count = 50 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 10, 1), Count = 2000 },
|
||||||
|
new UserHistoryCount { Date = new DateTime(2010, 11, 1), Count = 2100 }
|
||||||
|
};
|
||||||
|
|
||||||
|
AddStep("Set fake values", () => graph.Values = values);
|
||||||
|
AddStep("Set more values", () => graph.Values = moreValues);
|
||||||
|
AddStep("Set null values", () => graph.Values = null);
|
||||||
|
AddStep("Set empty values", () => graph.Values = Array.Empty<UserHistoryCount>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -51,8 +51,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
|
|
||||||
clickDelegate = Scheduler.AddDelayed(() =>
|
clickDelegate = Scheduler.AddDelayed(() =>
|
||||||
{
|
{
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
|
|
||||||
if (++buttonClicks == 2)
|
if (++buttonClicks == 2)
|
||||||
{
|
{
|
||||||
|
@ -98,10 +98,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("select next and enter", () =>
|
AddStep("select next and enter", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.Down);
|
InputManager.Key(Key.Down);
|
||||||
InputManager.ReleaseKey(Key.Down);
|
InputManager.Key(Key.Enter);
|
||||||
InputManager.PressKey(Key.Enter);
|
|
||||||
InputManager.ReleaseKey(Key.Enter);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||||
@ -123,10 +121,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
AddStep("select next and enter", () =>
|
AddStep("select next and enter", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
InputManager.ReleaseKey(Key.Enter);
|
InputManager.Key(Key.Down);
|
||||||
InputManager.PressKey(Key.Down);
|
|
||||||
InputManager.ReleaseKey(Key.Down);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||||
@ -151,11 +147,9 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmap>()
|
InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmap>()
|
||||||
.First(b => ((CarouselBeatmap)b.Item).Beatmap != songSelect.Carousel.SelectedBeatmap));
|
.First(b => ((CarouselBeatmap)b.Item).Beatmap != songSelect.Carousel.SelectedBeatmap));
|
||||||
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
|
|
||||||
InputManager.PressKey(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
InputManager.ReleaseKey(Key.Enter);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||||
@ -182,8 +176,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
|
||||||
InputManager.PressKey(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
InputManager.ReleaseKey(Key.Enter);
|
|
||||||
|
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
InputManager.ReleaseButton(MouseButton.Left);
|
||||||
});
|
});
|
||||||
@ -567,10 +560,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddStep("press ctrl+enter", () =>
|
AddStep("press ctrl+enter", () =>
|
||||||
{
|
{
|
||||||
InputManager.PressKey(Key.ControlLeft);
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
InputManager.PressKey(Key.Enter);
|
InputManager.Key(Key.Enter);
|
||||||
|
|
||||||
InputManager.ReleaseKey(Key.ControlLeft);
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
InputManager.ReleaseKey(Key.Enter);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader);
|
AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader);
|
||||||
@ -617,8 +608,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(difficultyIcon);
|
InputManager.MoveMouseTo(difficultyIcon);
|
||||||
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon));
|
AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon));
|
||||||
@ -647,8 +637,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(filteredIcon);
|
InputManager.MoveMouseTo(filteredIcon);
|
||||||
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap);
|
AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmap == filteredBeatmap);
|
||||||
@ -691,8 +680,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(difficultyIcon);
|
InputManager.MoveMouseTo(difficultyIcon);
|
||||||
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
||||||
@ -738,8 +726,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(groupIcon);
|
InputManager.MoveMouseTo(groupIcon);
|
||||||
|
|
||||||
InputManager.PressButton(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
InputManager.ReleaseButton(MouseButton.Left);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
|
||||||
|
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
});
|
});
|
||||||
AddStep("enter text", () => commentEditor.Current.Value = "text");
|
AddStep("enter text", () => commentEditor.Current.Value = "text");
|
||||||
|
|
||||||
AddStep("press Enter", () => press(Key.Enter));
|
AddStep("press Enter", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
AddAssert("text committed", () => commentEditor.CommittedText == "text");
|
AddAssert("text committed", () => commentEditor.CommittedText == "text");
|
||||||
AddAssert("button is loading", () => commentEditor.IsLoading);
|
AddAssert("button is loading", () => commentEditor.IsLoading);
|
||||||
@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("press Enter", () => press(Key.Enter));
|
AddStep("press Enter", () => InputManager.Key(Key.Enter));
|
||||||
|
|
||||||
AddAssert("no text committed", () => commentEditor.CommittedText == null);
|
AddAssert("no text committed", () => commentEditor.CommittedText == null);
|
||||||
AddAssert("button is not loading", () => !commentEditor.IsLoading);
|
AddAssert("button is not loading", () => !commentEditor.IsLoading);
|
||||||
@ -101,12 +101,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
AddAssert("cancel action fired", () => cancellableCommentEditor.Cancelled);
|
AddAssert("cancel action fired", () => cancellableCommentEditor.Cancelled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void press(Key key)
|
|
||||||
{
|
|
||||||
InputManager.PressKey(key);
|
|
||||||
InputManager.ReleaseKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestCommentEditor : CommentEditor
|
private class TestCommentEditor : CommentEditor
|
||||||
{
|
{
|
||||||
public new Bindable<string> Current => base.Current;
|
public new Bindable<string> Current => base.Current;
|
||||||
|
14
osu.Game.Tournament.Tests/.vscode/tasks.json
vendored
14
osu.Game.Tournament.Tests/.vscode/tasks.json
vendored
@ -11,9 +11,9 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Tournament.Tests.csproj",
|
"osu.Game.Tournament.Tests.csproj",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
@ -26,10 +26,10 @@
|
|||||||
"build",
|
"build",
|
||||||
"--no-restore",
|
"--no-restore",
|
||||||
"osu.Game.Tournament.Tests.csproj",
|
"osu.Game.Tournament.Tests.csproj",
|
||||||
"/p:Configuration=Release",
|
"-p:Configuration=Release",
|
||||||
"/p:GenerateFullPaths=true",
|
"-p:GenerateFullPaths=true",
|
||||||
"/m",
|
"-m",
|
||||||
"/verbosity:m"
|
"-verbosity:m"
|
||||||
],
|
],
|
||||||
"group": "build",
|
"group": "build",
|
||||||
"problemMatcher": "$msCompile"
|
"problemMatcher": "$msCompile"
|
||||||
|
@ -30,8 +30,22 @@ namespace osu.Game.Beatmaps
|
|||||||
// Too many simultaneous updates can lead to stutters. One thread seems to work fine for song select display purposes.
|
// Too many simultaneous updates can lead to stutters. One thread seems to work fine for song select display purposes.
|
||||||
private readonly ThreadedTaskScheduler updateScheduler = new ThreadedTaskScheduler(1, nameof(BeatmapDifficultyCache));
|
private readonly ThreadedTaskScheduler updateScheduler = new ThreadedTaskScheduler(1, nameof(BeatmapDifficultyCache));
|
||||||
|
|
||||||
// All bindables that should be updated along with the current ruleset + mods.
|
/// <summary>
|
||||||
private readonly LockedWeakList<BindableStarDifficulty> trackedBindables = new LockedWeakList<BindableStarDifficulty>();
|
/// All bindables that should be updated along with the current ruleset + mods.
|
||||||
|
/// </summary>
|
||||||
|
private readonly WeakList<BindableStarDifficulty> trackedBindables = new WeakList<BindableStarDifficulty>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancellation sources used by tracked bindables.
|
||||||
|
/// </summary>
|
||||||
|
private readonly List<CancellationTokenSource> linkedCancellationSources = new List<CancellationTokenSource>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lock to be held when operating on <see cref="trackedBindables"/> or <see cref="linkedCancellationSources"/>.
|
||||||
|
/// </summary>
|
||||||
|
private readonly object bindableUpdateLock = new object();
|
||||||
|
|
||||||
|
private CancellationTokenSource trackedUpdateCancellationSource;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private BeatmapManager beatmapManager { get; set; }
|
private BeatmapManager beatmapManager { get; set; }
|
||||||
@ -59,7 +73,10 @@ namespace osu.Game.Beatmaps
|
|||||||
public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
|
public IBindable<StarDifficulty> GetBindableDifficulty([NotNull] BeatmapInfo beatmapInfo, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken);
|
var bindable = createBindable(beatmapInfo, currentRuleset.Value, currentMods.Value, cancellationToken);
|
||||||
trackedBindables.Add(bindable);
|
|
||||||
|
lock (bindableUpdateLock)
|
||||||
|
trackedBindables.Add(bindable);
|
||||||
|
|
||||||
return bindable;
|
return bindable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +103,8 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
|
/// <param name="mods">The <see cref="Mod"/>s to get the difficulty with.</param>
|
||||||
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
|
/// <param name="cancellationToken">An optional <see cref="CancellationToken"/> which stops computing the star difficulty.</param>
|
||||||
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
/// <returns>The <see cref="StarDifficulty"/>.</returns>
|
||||||
public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null, CancellationToken cancellationToken = default)
|
public Task<StarDifficulty> GetDifficultyAsync([NotNull] BeatmapInfo beatmapInfo, [CanBeNull] RulesetInfo rulesetInfo = null, [CanBeNull] IEnumerable<Mod> mods = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
// In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset.
|
||||||
rulesetInfo ??= beatmapInfo.Ruleset;
|
rulesetInfo ??= beatmapInfo.Ruleset;
|
||||||
@ -140,23 +158,23 @@ namespace osu.Game.Beatmaps
|
|||||||
return DifficultyRating.Easy;
|
return DifficultyRating.Easy;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CancellationTokenSource trackedUpdateCancellationSource;
|
|
||||||
private readonly List<CancellationTokenSource> linkedCancellationSources = new List<CancellationTokenSource>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates all tracked <see cref="BindableStarDifficulty"/> using the current ruleset and mods.
|
/// Updates all tracked <see cref="BindableStarDifficulty"/> using the current ruleset and mods.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void updateTrackedBindables()
|
private void updateTrackedBindables()
|
||||||
{
|
{
|
||||||
cancelTrackedBindableUpdate();
|
lock (bindableUpdateLock)
|
||||||
trackedUpdateCancellationSource = new CancellationTokenSource();
|
|
||||||
|
|
||||||
foreach (var b in trackedBindables)
|
|
||||||
{
|
{
|
||||||
var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(trackedUpdateCancellationSource.Token, b.CancellationToken);
|
cancelTrackedBindableUpdate();
|
||||||
linkedCancellationSources.Add(linkedSource);
|
trackedUpdateCancellationSource = new CancellationTokenSource();
|
||||||
|
|
||||||
updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token);
|
foreach (var b in trackedBindables)
|
||||||
|
{
|
||||||
|
var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(trackedUpdateCancellationSource.Token, b.CancellationToken);
|
||||||
|
linkedCancellationSources.Add(linkedSource);
|
||||||
|
|
||||||
|
updateBindable(b, currentRuleset.Value, currentMods.Value, linkedSource.Token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,15 +183,18 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void cancelTrackedBindableUpdate()
|
private void cancelTrackedBindableUpdate()
|
||||||
{
|
{
|
||||||
trackedUpdateCancellationSource?.Cancel();
|
lock (bindableUpdateLock)
|
||||||
trackedUpdateCancellationSource = null;
|
|
||||||
|
|
||||||
if (linkedCancellationSources != null)
|
|
||||||
{
|
{
|
||||||
foreach (var c in linkedCancellationSources)
|
trackedUpdateCancellationSource?.Cancel();
|
||||||
c.Dispose();
|
trackedUpdateCancellationSource = null;
|
||||||
|
|
||||||
linkedCancellationSources.Clear();
|
if (linkedCancellationSources != null)
|
||||||
|
{
|
||||||
|
foreach (var c in linkedCancellationSources)
|
||||||
|
c.Dispose();
|
||||||
|
|
||||||
|
linkedCancellationSources.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +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 System;
|
||||||
|
using System.Diagnostics;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
@ -8,6 +10,7 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
@ -172,12 +175,28 @@ namespace osu.Game.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
public override TrackedSettings CreateTrackedSettings()
|
||||||
{
|
{
|
||||||
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled")),
|
// these need to be assigned in normal game startup scenarios.
|
||||||
new TrackedSetting<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode, m => new SettingDescription(m, "HUD Visibility", m.GetDescription())),
|
Debug.Assert(LookupKeyBindings != null);
|
||||||
new TrackedSetting<ScalingMode>(OsuSetting.Scaling, m => new SettingDescription(m, "scaling", m.GetDescription())),
|
Debug.Assert(LookupSkinName != null);
|
||||||
};
|
|
||||||
|
return new TrackedSettings
|
||||||
|
{
|
||||||
|
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled", LookupKeyBindings(GlobalAction.ToggleGameplayMouseButtons))),
|
||||||
|
new TrackedSetting<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode, m => new SettingDescription(m, "HUD Visibility", m.GetDescription(), $"cycle: shift-tab quick view: {LookupKeyBindings(GlobalAction.HoldForHUD)}")),
|
||||||
|
new TrackedSetting<ScalingMode>(OsuSetting.Scaling, m => new SettingDescription(m, "scaling", m.GetDescription())),
|
||||||
|
new TrackedSetting<int>(OsuSetting.Skin, m =>
|
||||||
|
{
|
||||||
|
string skinName = LookupSkinName(m) ?? string.Empty;
|
||||||
|
return new SettingDescription(skinName, "skin", skinName, $"random: {LookupKeyBindings(GlobalAction.RandomSkin)}");
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<int, string> LookupSkinName { private get; set; }
|
||||||
|
|
||||||
|
public Func<GlobalAction, string> LookupKeyBindings { private get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OsuSetting
|
public enum OsuSetting
|
||||||
|
@ -48,6 +48,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(InputKey.Space, GlobalAction.Select),
|
new KeyBinding(InputKey.Space, GlobalAction.Select),
|
||||||
new KeyBinding(InputKey.Enter, GlobalAction.Select),
|
new KeyBinding(InputKey.Enter, GlobalAction.Select),
|
||||||
new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select),
|
new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select),
|
||||||
|
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin),
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> EditorKeyBindings => new[]
|
public IEnumerable<KeyBinding> EditorKeyBindings => new[]
|
||||||
@ -191,5 +193,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
[Description("Hold for HUD")]
|
[Description("Hold for HUD")]
|
||||||
HoldForHUD,
|
HoldForHUD,
|
||||||
|
|
||||||
|
[Description("Random Skin")]
|
||||||
|
RandomSkin,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,23 @@ namespace osu.Game.Input
|
|||||||
|
|
||||||
public void Register(KeyBindingContainer manager) => insertDefaults(manager.DefaultKeyBindings);
|
public void Register(KeyBindingContainer manager) => insertDefaults(manager.DefaultKeyBindings);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve all user-defined key combinations (in a format that can be displayed) for a specific action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="globalAction">The action to lookup.</param>
|
||||||
|
/// <returns>A set of display strings for all the user's key configuration for the action.</returns>
|
||||||
|
public IEnumerable<string> GetReadableKeyCombinationsFor(GlobalAction globalAction)
|
||||||
|
{
|
||||||
|
foreach (var action in Query().Where(b => (GlobalAction)b.Action == globalAction))
|
||||||
|
{
|
||||||
|
string str = action.KeyCombination.ReadableString();
|
||||||
|
|
||||||
|
// even if found, the readable string may be empty for an unbound action.
|
||||||
|
if (str.Length > 0)
|
||||||
|
yield return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void insertDefaults(IEnumerable<KeyBinding> defaults, int? rulesetId = null, int? variant = null)
|
private void insertDefaults(IEnumerable<KeyBinding> defaults, int? rulesetId = null, int? variant = null)
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
|
@ -51,6 +51,7 @@ using osu.Game.Screens.Select;
|
|||||||
using osu.Game.Updater;
|
using osu.Game.Updater;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using LogLevel = osu.Framework.Logging.LogLevel;
|
using LogLevel = osu.Framework.Logging.LogLevel;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game
|
namespace osu.Game
|
||||||
{
|
{
|
||||||
@ -547,6 +548,20 @@ namespace osu.Game
|
|||||||
ScoreManager.GetStableStorage = GetStorageForStableInstall;
|
ScoreManager.GetStableStorage = GetStorageForStableInstall;
|
||||||
ScoreManager.PresentImport = items => PresentScore(items.First());
|
ScoreManager.PresentImport = items => PresentScore(items.First());
|
||||||
|
|
||||||
|
// make config aware of how to lookup skins for on-screen display purposes.
|
||||||
|
// if this becomes a more common thing, tracked settings should be reconsidered to allow local DI.
|
||||||
|
LocalConfig.LookupSkinName = id => SkinManager.GetAllUsableSkins().FirstOrDefault(s => s.ID == id)?.ToString() ?? "Unknown";
|
||||||
|
|
||||||
|
LocalConfig.LookupKeyBindings = l =>
|
||||||
|
{
|
||||||
|
var combinations = KeyBindingStore.GetReadableKeyCombinationsFor(l).ToArray();
|
||||||
|
|
||||||
|
if (combinations.Length == 0)
|
||||||
|
return "none";
|
||||||
|
|
||||||
|
return string.Join(" or ", combinations);
|
||||||
|
};
|
||||||
|
|
||||||
Container logoContainer;
|
Container logoContainer;
|
||||||
BackButton.Receptor receptor;
|
BackButton.Receptor receptor;
|
||||||
|
|
||||||
@ -612,7 +627,12 @@ namespace osu.Game
|
|||||||
|
|
||||||
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add, true);
|
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(new OnScreenDisplay(), Add, true);
|
var onScreenDisplay = new OnScreenDisplay();
|
||||||
|
|
||||||
|
onScreenDisplay.BeginTracking(this, frameworkConfig);
|
||||||
|
onScreenDisplay.BeginTracking(this, LocalConfig);
|
||||||
|
|
||||||
|
loadComponentSingleFile(onScreenDisplay, Add, true);
|
||||||
|
|
||||||
loadComponentSingleFile(notifications.With(d =>
|
loadComponentSingleFile(notifications.With(d =>
|
||||||
{
|
{
|
||||||
@ -872,6 +892,10 @@ namespace osu.Game
|
|||||||
case GlobalAction.ToggleGameplayMouseButtons:
|
case GlobalAction.ToggleGameplayMouseButtons:
|
||||||
LocalConfig.Set(OsuSetting.MouseDisableButtons, !LocalConfig.Get<bool>(OsuSetting.MouseDisableButtons));
|
LocalConfig.Set(OsuSetting.MouseDisableButtons, !LocalConfig.Get<bool>(OsuSetting.MouseDisableButtons));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.RandomSkin:
|
||||||
|
SkinManager.SelectRandomSkin();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -961,11 +985,15 @@ namespace osu.Game
|
|||||||
LocalUserPlaying.Value = false;
|
LocalUserPlaying.Value = false;
|
||||||
|
|
||||||
if (current is IOsuScreen currentOsuScreen)
|
if (current is IOsuScreen currentOsuScreen)
|
||||||
|
{
|
||||||
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
|
OverlayActivationMode.UnbindFrom(currentOsuScreen.OverlayActivationMode);
|
||||||
|
API.Activity.UnbindFrom(currentOsuScreen.Activity);
|
||||||
|
}
|
||||||
|
|
||||||
if (newScreen is IOsuScreen newOsuScreen)
|
if (newScreen is IOsuScreen newOsuScreen)
|
||||||
{
|
{
|
||||||
OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode);
|
OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode);
|
||||||
|
((IBindable<UserActivity>)API.Activity).BindTo(newOsuScreen.Activity);
|
||||||
|
|
||||||
MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;
|
MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;
|
||||||
|
|
||||||
|
@ -32,6 +32,11 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Action SearchStarted;
|
public Action SearchStarted;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Any time the search text box receives key events (even while masked).
|
||||||
|
/// </summary>
|
||||||
|
public Action TypingStarted;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True when pagination has reached the end of available results.
|
/// True when pagination has reached the end of available results.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -82,7 +87,10 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
Radius = 3,
|
Radius = 3,
|
||||||
Offset = new Vector2(0f, 1f),
|
Offset = new Vector2(0f, 1f),
|
||||||
},
|
},
|
||||||
Child = searchControl = new BeatmapListingSearchControl(),
|
Child = searchControl = new BeatmapListingSearchControl
|
||||||
|
{
|
||||||
|
TypingStarted = () => TypingStarted?.Invoke()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
// 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 osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps.Drawables;
|
using osu.Game.Beatmaps.Drawables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
@ -19,6 +21,11 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
{
|
{
|
||||||
public class BeatmapListingSearchControl : CompositeDrawable
|
public class BeatmapListingSearchControl : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Any time the text box receives key events (even while masked).
|
||||||
|
/// </summary>
|
||||||
|
public Action TypingStarted;
|
||||||
|
|
||||||
public Bindable<string> Query => textBox.Current;
|
public Bindable<string> Query => textBox.Current;
|
||||||
|
|
||||||
public Bindable<RulesetInfo> Ruleset => modeFilter.Current;
|
public Bindable<RulesetInfo> Ruleset => modeFilter.Current;
|
||||||
@ -102,6 +109,7 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
textBox = new BeatmapSearchTextBox
|
textBox = new BeatmapSearchTextBox
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
TypingStarted = () => TypingStarted?.Invoke(),
|
||||||
},
|
},
|
||||||
new ReverseChildIDFillFlowContainer<Drawable>
|
new ReverseChildIDFillFlowContainer<Drawable>
|
||||||
{
|
{
|
||||||
@ -138,12 +146,26 @@ namespace osu.Game.Overlays.BeatmapListing
|
|||||||
|
|
||||||
private class BeatmapSearchTextBox : SearchTextBox
|
private class BeatmapSearchTextBox : SearchTextBox
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Any time the text box receives key events (even while masked).
|
||||||
|
/// </summary>
|
||||||
|
public Action TypingStarted;
|
||||||
|
|
||||||
protected override Color4 SelectionColour => Color4.Gray;
|
protected override Color4 SelectionColour => Color4.Gray;
|
||||||
|
|
||||||
public BeatmapSearchTextBox()
|
public BeatmapSearchTextBox()
|
||||||
{
|
{
|
||||||
PlaceholderText = @"type in keywords...";
|
PlaceholderText = @"type in keywords...";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
|
{
|
||||||
|
if (!base.OnKeyDown(e))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TypingStarted?.Invoke();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@ namespace osu.Game.Overlays
|
|||||||
Header,
|
Header,
|
||||||
filterControl = new BeatmapListingFilterControl
|
filterControl = new BeatmapListingFilterControl
|
||||||
{
|
{
|
||||||
|
TypingStarted = onTypingStarted,
|
||||||
SearchStarted = onSearchStarted,
|
SearchStarted = onSearchStarted,
|
||||||
SearchFinished = onSearchFinished,
|
SearchFinished = onSearchFinished,
|
||||||
},
|
},
|
||||||
@ -102,6 +103,12 @@ namespace osu.Game.Overlays
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onTypingStarted()
|
||||||
|
{
|
||||||
|
// temporary until the textbox/header is updated to always stay on screen.
|
||||||
|
resultScrollContainer.ScrollToStart();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnFocus(FocusEvent e)
|
protected override void OnFocus(FocusEvent e)
|
||||||
{
|
{
|
||||||
base.OnFocus(e);
|
base.OnFocus(e);
|
||||||
|
@ -110,7 +110,11 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
User = user;
|
User = user;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(IAPIProvider api)
|
||||||
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
@ -121,7 +125,7 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
Width = 290,
|
Width = 290,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new UserGridPanel(user)
|
new UserGridPanel(User)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
@ -133,7 +137,8 @@ namespace osu.Game.Overlays.Dashboard
|
|||||||
Text = "Watch",
|
Text = "Watch",
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Action = () => game?.PerformFromScreen(s => s.Push(new Spectator(user)))
|
Action = () => game?.PerformFromScreen(s => s.Push(new Spectator(User))),
|
||||||
|
Enabled = { Value = User.Id != api.LocalUser.Value.Id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -85,6 +85,8 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.ControlPressed) return false;
|
||||||
|
|
||||||
if (ToggleKeys != null)
|
if (ToggleKeys != null)
|
||||||
{
|
{
|
||||||
var index = Array.IndexOf(ToggleKeys, e.Key);
|
var index = Array.IndexOf(ToggleKeys, e.Key);
|
||||||
|
@ -3,16 +3,14 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osuTK;
|
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Overlays.OSD;
|
using osu.Game.Overlays.OSD;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
@ -47,13 +45,6 @@ namespace osu.Game.Overlays
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(FrameworkConfigManager frameworkConfig, OsuConfigManager osuConfig)
|
|
||||||
{
|
|
||||||
BeginTracking(this, frameworkConfig);
|
|
||||||
BeginTracking(this, osuConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<(object, IConfigManager), TrackedSettings> trackedConfigManagers = new Dictionary<(object, IConfigManager), TrackedSettings>();
|
private readonly Dictionary<(object, IConfigManager), TrackedSettings> trackedConfigManagers = new Dictionary<(object, IConfigManager), TrackedSettings>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -4,307 +4,89 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using Humanizer;
|
||||||
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.Cursor;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile.Header.Components
|
namespace osu.Game.Overlays.Profile.Header.Components
|
||||||
{
|
{
|
||||||
public class RankGraph : Container, IHasCustomTooltip
|
public class RankGraph : UserGraph<int, int>
|
||||||
{
|
{
|
||||||
private const float secondary_textsize = 13;
|
|
||||||
private const float padding = 10;
|
|
||||||
private const float fade_duration = 150;
|
|
||||||
private const int ranked_days = 88;
|
private const int ranked_days = 88;
|
||||||
|
|
||||||
private readonly RankChartLineGraph graph;
|
|
||||||
private readonly OsuSpriteText placeholder;
|
|
||||||
|
|
||||||
private KeyValuePair<int, int>[] ranks;
|
|
||||||
private int dayIndex;
|
|
||||||
public readonly Bindable<UserStatistics> Statistics = new Bindable<UserStatistics>();
|
public readonly Bindable<UserStatistics> Statistics = new Bindable<UserStatistics>();
|
||||||
|
|
||||||
|
private readonly OsuSpriteText placeholder;
|
||||||
|
|
||||||
public RankGraph()
|
public RankGraph()
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding { Vertical = padding };
|
Add(placeholder = new OsuSpriteText
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
placeholder = new OsuSpriteText
|
Anchor = Anchor.Centre,
|
||||||
{
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Text = "No recent plays",
|
||||||
Origin = Anchor.Centre,
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular)
|
||||||
Text = "No recent plays",
|
});
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular)
|
|
||||||
},
|
|
||||||
graph = new RankChartLineGraph
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Y = -secondary_textsize,
|
|
||||||
Alpha = 0,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
graph.OnBallMove += i => dayIndex = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
graph.LineColour = colours.Yellow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
Statistics.BindValueChanged(statistics => updateStatistics(statistics.NewValue), true);
|
Statistics.BindValueChanged(statistics => updateStatistics(statistics.NewValue), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStatistics(UserStatistics statistics)
|
private void updateStatistics(UserStatistics statistics)
|
||||||
{
|
{
|
||||||
placeholder.FadeIn(fade_duration, Easing.Out);
|
int[] userRanks = statistics?.RankHistory?.Data;
|
||||||
|
Data = userRanks?.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
|
||||||
if (statistics?.Ranks.Global == null)
|
|
||||||
{
|
|
||||||
graph.FadeOut(fade_duration, Easing.Out);
|
|
||||||
ranks = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] userRanks = statistics.RankHistory?.Data ?? new[] { statistics.Ranks.Global.Value };
|
|
||||||
ranks = userRanks.Select((x, index) => new KeyValuePair<int, int>(index, x)).Where(x => x.Value != 0).ToArray();
|
|
||||||
|
|
||||||
if (ranks.Length > 1)
|
|
||||||
{
|
|
||||||
placeholder.FadeOut(fade_duration, Easing.Out);
|
|
||||||
|
|
||||||
graph.DefaultValueCount = ranks.Length;
|
|
||||||
graph.Values = ranks.Select(x => -MathF.Log(x.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
graph.FadeTo(ranks.Length > 1 ? 1 : 0, fade_duration, Easing.Out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override float GetDataPointHeight(int rank) => -MathF.Log(rank);
|
||||||
{
|
|
||||||
if (ranks?.Length > 1)
|
|
||||||
{
|
|
||||||
graph.UpdateBallPosition(e.MousePosition.X);
|
|
||||||
graph.ShowBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnHover(e);
|
protected override void ShowGraph()
|
||||||
|
{
|
||||||
|
base.ShowGraph();
|
||||||
|
placeholder.FadeOut(FADE_DURATION, Easing.Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override void HideGraph()
|
||||||
{
|
{
|
||||||
if (ranks?.Length > 1)
|
base.HideGraph();
|
||||||
graph.UpdateBallPosition(e.MousePosition.X);
|
placeholder.FadeIn(FADE_DURATION, Easing.Out);
|
||||||
|
|
||||||
return base.OnMouseMove(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
protected override object GetTooltipContent(int index, int rank)
|
||||||
{
|
{
|
||||||
if (ranks?.Length > 1)
|
var days = ranked_days - index + 1;
|
||||||
{
|
|
||||||
graph.HideBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnHoverLost(e);
|
return new TooltipDisplayContent
|
||||||
|
{
|
||||||
|
Rank = $"#{rank:N0}",
|
||||||
|
Time = days == 0 ? "now" : $"{"day".ToQuantity(days)} ago"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RankChartLineGraph : LineGraph
|
protected override UserGraphTooltip GetTooltip() => new RankGraphTooltip();
|
||||||
|
|
||||||
|
private class RankGraphTooltip : UserGraphTooltip
|
||||||
{
|
{
|
||||||
private readonly CircularContainer movingBall;
|
|
||||||
private readonly Container bar;
|
|
||||||
private readonly Box ballBg;
|
|
||||||
private readonly Box line;
|
|
||||||
|
|
||||||
public Action<int> OnBallMove;
|
|
||||||
|
|
||||||
public RankChartLineGraph()
|
|
||||||
{
|
|
||||||
Add(bar = new Container
|
|
||||||
{
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Alpha = 0,
|
|
||||||
RelativePositionAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
line = new Box
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Width = 1.5f,
|
|
||||||
},
|
|
||||||
movingBall = new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Size = new Vector2(18),
|
|
||||||
Masking = true,
|
|
||||||
BorderThickness = 4,
|
|
||||||
RelativePositionAxes = Axes.Y,
|
|
||||||
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
|
||||||
{
|
|
||||||
ballBg.Colour = colourProvider.Background5;
|
|
||||||
movingBall.BorderColour = line.Colour = colours.Yellow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateBallPosition(float mouseXPosition)
|
|
||||||
{
|
|
||||||
const int duration = 200;
|
|
||||||
int index = calculateIndex(mouseXPosition);
|
|
||||||
Vector2 position = calculateBallPosition(index);
|
|
||||||
movingBall.MoveToY(position.Y, duration, Easing.OutQuint);
|
|
||||||
bar.MoveToX(position.X, duration, Easing.OutQuint);
|
|
||||||
OnBallMove.Invoke(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowBar() => bar.FadeIn(fade_duration);
|
|
||||||
|
|
||||||
public void HideBar() => bar.FadeOut(fade_duration);
|
|
||||||
|
|
||||||
private int calculateIndex(float mouseXPosition) => (int)MathF.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
|
|
||||||
|
|
||||||
private Vector2 calculateBallPosition(int index)
|
|
||||||
{
|
|
||||||
float y = GetYPosition(Values.ElementAt(index));
|
|
||||||
return new Vector2(index / (float)(DefaultValueCount - 1), y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object TooltipContent
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Statistics.Value?.Ranks.Global == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var days = ranked_days - ranks[dayIndex].Key + 1;
|
|
||||||
|
|
||||||
return new TooltipDisplayContent
|
|
||||||
{
|
|
||||||
Rank = $"#{ranks[dayIndex].Value:#,##0}",
|
|
||||||
Time = days == 0 ? "now" : $"{days} days ago"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ITooltip GetCustomTooltip() => new RankGraphTooltip();
|
|
||||||
|
|
||||||
private class RankGraphTooltip : VisibilityContainer, ITooltip
|
|
||||||
{
|
|
||||||
private readonly OsuSpriteText globalRankingText, timeText;
|
|
||||||
private readonly Box background;
|
|
||||||
|
|
||||||
public RankGraphTooltip()
|
public RankGraphTooltip()
|
||||||
|
: base("Global Ranking")
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
|
||||||
Masking = true;
|
|
||||||
CornerRadius = 10;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
background = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both
|
|
||||||
},
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Padding = new MarginPadding(10),
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
|
||||||
Text = "Global Ranking "
|
|
||||||
},
|
|
||||||
globalRankingText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
timeText = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
public override bool SetContent(object content)
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
// Temporary colour since it's currently impossible to change it without bugs (see https://github.com/ppy/osu-framework/issues/3231)
|
|
||||||
// If above is fixed, this should use OverlayColourProvider
|
|
||||||
background.Colour = colours.Gray1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetContent(object content)
|
|
||||||
{
|
{
|
||||||
if (!(content is TooltipDisplayContent info))
|
if (!(content is TooltipDisplayContent info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
globalRankingText.Text = info.Rank;
|
Counter.Text = info.Rank;
|
||||||
timeText.Text = info.Time;
|
BottomText.Text = info.Time;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool instantMove = true;
|
|
||||||
|
|
||||||
public void Move(Vector2 pos)
|
|
||||||
{
|
|
||||||
if (instantMove)
|
|
||||||
{
|
|
||||||
Position = pos;
|
|
||||||
instantMove = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
this.MoveTo(pos, 200, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopIn()
|
|
||||||
{
|
|
||||||
instantMove |= !IsPresent;
|
|
||||||
this.FadeIn(200, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TooltipDisplayContent
|
private class TooltipDisplayContent
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using static osu.Game.Users.User;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile.Sections.Historical
|
||||||
|
{
|
||||||
|
public class UserHistoryGraph : UserGraph<DateTime, long>
|
||||||
|
{
|
||||||
|
[CanBeNull]
|
||||||
|
public UserHistoryCount[] Values
|
||||||
|
{
|
||||||
|
set => Data = value?.Select(v => new KeyValuePair<DateTime, long>(v.Date, v.Count)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text describing the value being plotted on the graph, which will be displayed as a prefix to the value in the <see cref="HistoryGraphTooltip"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string TooltipCounterName { get; set; } = "Plays";
|
||||||
|
|
||||||
|
protected override float GetDataPointHeight(long playCount) => playCount;
|
||||||
|
|
||||||
|
protected override UserGraphTooltip GetTooltip() => new HistoryGraphTooltip(TooltipCounterName);
|
||||||
|
|
||||||
|
protected override object GetTooltipContent(DateTime date, long playCount)
|
||||||
|
{
|
||||||
|
return new TooltipDisplayContent
|
||||||
|
{
|
||||||
|
Count = playCount.ToString("N0"),
|
||||||
|
Date = date.ToString("MMMM yyyy")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class HistoryGraphTooltip : UserGraphTooltip
|
||||||
|
{
|
||||||
|
public HistoryGraphTooltip(string tooltipCounterName)
|
||||||
|
: base(tooltipCounterName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool SetContent(object content)
|
||||||
|
{
|
||||||
|
if (!(content is TooltipDisplayContent info))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Counter.Text = info.Count;
|
||||||
|
BottomText.Text = info.Date;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TooltipDisplayContent
|
||||||
|
{
|
||||||
|
public string Count;
|
||||||
|
public string Date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -46,6 +46,9 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
|||||||
|
|
||||||
protected override void OnItemsReceived(List<APILegacyScoreInfo> items)
|
protected override void OnItemsReceived(List<APILegacyScoreInfo> items)
|
||||||
{
|
{
|
||||||
|
if (VisiblePages == 0)
|
||||||
|
drawableItemIndex = 0;
|
||||||
|
|
||||||
base.OnItemsReceived(items);
|
base.OnItemsReceived(items);
|
||||||
|
|
||||||
if (type == ScoreType.Recent)
|
if (type == ScoreType.Recent)
|
||||||
@ -55,6 +58,8 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
|||||||
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
|
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
|
||||||
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
|
||||||
|
|
||||||
|
private int drawableItemIndex;
|
||||||
|
|
||||||
protected override Drawable CreateDrawableItem(APILegacyScoreInfo model)
|
protected override Drawable CreateDrawableItem(APILegacyScoreInfo model)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
@ -63,7 +68,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
|||||||
return new DrawableProfileScore(model.CreateScoreInfo(Rulesets));
|
return new DrawableProfileScore(model.CreateScoreInfo(Rulesets));
|
||||||
|
|
||||||
case ScoreType.Best:
|
case ScoreType.Best:
|
||||||
return new DrawableProfileWeightedScore(model.CreateScoreInfo(Rulesets), Math.Pow(0.95, ItemsContainer.Count));
|
return new DrawableProfileWeightedScore(model.CreateScoreInfo(Rulesets), Math.Pow(0.95, drawableItemIndex++));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
294
osu.Game/Overlays/Profile/UserGraph.cs
Normal file
294
osu.Game/Overlays/Profile/UserGraph.cs
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Profile
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Graph which is used in <see cref="UserProfileOverlay"/> to present changes in user statistics over time.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">Type of data to be used for X-axis of the graph.</typeparam>
|
||||||
|
/// <typeparam name="TValue">Type of data to be used for Y-axis of the graph.</typeparam>
|
||||||
|
public abstract class UserGraph<TKey, TValue> : Container, IHasCustomTooltip
|
||||||
|
{
|
||||||
|
protected const float FADE_DURATION = 150;
|
||||||
|
|
||||||
|
private readonly UserLineGraph graph;
|
||||||
|
private KeyValuePair<TKey, TValue>[] data;
|
||||||
|
private int hoveredIndex = -1;
|
||||||
|
|
||||||
|
protected UserGraph()
|
||||||
|
{
|
||||||
|
Add(graph = new UserLineGraph
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0
|
||||||
|
});
|
||||||
|
|
||||||
|
graph.OnBallMove += i => hoveredIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
graph.LineColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float lastHoverPosition;
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
if (data?.Length > 1)
|
||||||
|
{
|
||||||
|
graph.UpdateBallPosition(lastHoverPosition = e.MousePosition.X);
|
||||||
|
graph.ShowBar();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
|
{
|
||||||
|
if (data?.Length > 1)
|
||||||
|
graph.UpdateBallPosition(e.MousePosition.X);
|
||||||
|
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
graph.HideBar();
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set of values which will be used to create a graph.
|
||||||
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
|
protected KeyValuePair<TKey, TValue>[] Data
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
data = value;
|
||||||
|
redrawGraph();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void redrawGraph()
|
||||||
|
{
|
||||||
|
hoveredIndex = -1;
|
||||||
|
|
||||||
|
if (data?.Length > 1)
|
||||||
|
{
|
||||||
|
graph.DefaultValueCount = data.Length;
|
||||||
|
graph.Values = data.Select(pair => GetDataPointHeight(pair.Value)).ToArray();
|
||||||
|
ShowGraph();
|
||||||
|
|
||||||
|
if (IsHovered)
|
||||||
|
graph.UpdateBallPosition(lastHoverPosition);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HideGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Function used to convert <see cref="Data"/> point to it's Y-axis position on the graph.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value to convert.</param>
|
||||||
|
protected abstract float GetDataPointHeight(TValue value);
|
||||||
|
|
||||||
|
protected virtual void ShowGraph() => graph.FadeIn(FADE_DURATION, Easing.Out);
|
||||||
|
protected virtual void HideGraph() => graph.FadeOut(FADE_DURATION, Easing.Out);
|
||||||
|
|
||||||
|
public ITooltip GetCustomTooltip() => GetTooltip();
|
||||||
|
|
||||||
|
protected abstract UserGraphTooltip GetTooltip();
|
||||||
|
|
||||||
|
public object TooltipContent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (data == null || hoveredIndex == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var (key, value) = data[hoveredIndex];
|
||||||
|
return GetTooltipContent(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract object GetTooltipContent(TKey key, TValue value);
|
||||||
|
|
||||||
|
protected class UserLineGraph : LineGraph
|
||||||
|
{
|
||||||
|
private readonly CircularContainer movingBall;
|
||||||
|
private readonly Container bar;
|
||||||
|
private readonly Box ballBg;
|
||||||
|
private readonly Box line;
|
||||||
|
|
||||||
|
public Action<int> OnBallMove;
|
||||||
|
|
||||||
|
public UserLineGraph()
|
||||||
|
{
|
||||||
|
Add(bar = new Container
|
||||||
|
{
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Alpha = 0,
|
||||||
|
RelativePositionAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
line = new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 2,
|
||||||
|
},
|
||||||
|
movingBall = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(20),
|
||||||
|
Masking = true,
|
||||||
|
BorderThickness = 4,
|
||||||
|
RelativePositionAxes = Axes.Y,
|
||||||
|
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
||||||
|
{
|
||||||
|
ballBg.Colour = colourProvider.Background5;
|
||||||
|
movingBall.BorderColour = line.Colour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBallPosition(float mouseXPosition)
|
||||||
|
{
|
||||||
|
const int duration = 200;
|
||||||
|
int index = calculateIndex(mouseXPosition);
|
||||||
|
Vector2 position = calculateBallPosition(index);
|
||||||
|
movingBall.MoveToY(position.Y, duration, Easing.OutQuint);
|
||||||
|
bar.MoveToX(position.X, duration, Easing.OutQuint);
|
||||||
|
OnBallMove.Invoke(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowBar() => bar.FadeIn(FADE_DURATION);
|
||||||
|
|
||||||
|
public void HideBar() => bar.FadeOut(FADE_DURATION);
|
||||||
|
|
||||||
|
private int calculateIndex(float mouseXPosition) => (int)Math.Clamp(MathF.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1)), 0, DefaultValueCount - 1);
|
||||||
|
|
||||||
|
private Vector2 calculateBallPosition(int index)
|
||||||
|
{
|
||||||
|
float y = GetYPosition(Values.ElementAt(index));
|
||||||
|
return new Vector2(index / (float)(DefaultValueCount - 1), y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract class UserGraphTooltip : VisibilityContainer, ITooltip
|
||||||
|
{
|
||||||
|
protected readonly OsuSpriteText Counter, BottomText;
|
||||||
|
private readonly Box background;
|
||||||
|
|
||||||
|
protected UserGraphTooltip(string tooltipCounterName)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = 10;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Padding = new MarginPadding(10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(3, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
|
||||||
|
Text = tooltipCounterName
|
||||||
|
},
|
||||||
|
Counter = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BottomText = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
// Temporary colour since it's currently impossible to change it without bugs (see https://github.com/ppy/osu-framework/issues/3231)
|
||||||
|
// If above is fixed, this should use OverlayColourProvider
|
||||||
|
background.Colour = colours.Gray1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract bool SetContent(object content);
|
||||||
|
|
||||||
|
private bool instantMove = true;
|
||||||
|
|
||||||
|
public void Move(Vector2 pos)
|
||||||
|
{
|
||||||
|
if (instantMove)
|
||||||
|
{
|
||||||
|
Position = pos;
|
||||||
|
instantMove = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.MoveTo(pos, 200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
instantMove |= !IsPresent;
|
||||||
|
this.FadeIn(200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -29,6 +30,14 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
private readonly Bindable<SkinInfo> dropdownBindable = new Bindable<SkinInfo> { Default = SkinInfo.Default };
|
private readonly Bindable<SkinInfo> dropdownBindable = new Bindable<SkinInfo> { Default = SkinInfo.Default };
|
||||||
private readonly Bindable<int> configBindable = new Bindable<int>();
|
private readonly Bindable<int> configBindable = new Bindable<int>();
|
||||||
|
|
||||||
|
private static readonly SkinInfo random_skin_info = new SkinInfo
|
||||||
|
{
|
||||||
|
ID = SkinInfo.RANDOM_SKIN,
|
||||||
|
Name = "<Random Skin>",
|
||||||
|
};
|
||||||
|
|
||||||
|
private List<SkinInfo> skinItems;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skins { get; set; }
|
private SkinManager skins { get; set; }
|
||||||
|
|
||||||
@ -82,14 +91,37 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
config.BindWith(OsuSetting.Skin, configBindable);
|
config.BindWith(OsuSetting.Skin, configBindable);
|
||||||
|
|
||||||
skinDropdown.Current = dropdownBindable;
|
skinDropdown.Current = dropdownBindable;
|
||||||
skinDropdown.Items = skins.GetAllUsableSkins().ToArray();
|
updateItems();
|
||||||
|
|
||||||
// Todo: This should not be necessary when OsuConfigManager is databased
|
// Todo: This should not be necessary when OsuConfigManager is databased
|
||||||
if (skinDropdown.Items.All(s => s.ID != configBindable.Value))
|
if (skinDropdown.Items.All(s => s.ID != configBindable.Value))
|
||||||
configBindable.Value = 0;
|
configBindable.Value = 0;
|
||||||
|
|
||||||
configBindable.BindValueChanged(id => dropdownBindable.Value = skinDropdown.Items.Single(s => s.ID == id.NewValue), true);
|
configBindable.BindValueChanged(id => dropdownBindable.Value = skinDropdown.Items.Single(s => s.ID == id.NewValue), true);
|
||||||
dropdownBindable.BindValueChanged(skin => configBindable.Value = skin.NewValue.ID);
|
dropdownBindable.BindValueChanged(skin =>
|
||||||
|
{
|
||||||
|
if (skin.NewValue == random_skin_info)
|
||||||
|
{
|
||||||
|
skins.SelectRandomSkin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
configBindable.Value = skin.NewValue.ID;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItems()
|
||||||
|
{
|
||||||
|
skinItems = skins.GetAllUsableSkins();
|
||||||
|
|
||||||
|
// insert after lazer built-in skins
|
||||||
|
int firstNonDefault = skinItems.FindIndex(s => s.ID > 0);
|
||||||
|
if (firstNonDefault < 0)
|
||||||
|
firstNonDefault = skinItems.Count;
|
||||||
|
|
||||||
|
skinItems.Insert(firstNonDefault, random_skin_info);
|
||||||
|
|
||||||
|
skinDropdown.Items = skinItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void itemUpdated(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
|
private void itemUpdated(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
|
||||||
|
@ -290,7 +290,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void PopulateScore(ScoreInfo score)
|
public virtual void PopulateScore(ScoreInfo score)
|
||||||
{
|
{
|
||||||
score.TotalScore = (long)Math.Round(TotalScore.Value);
|
score.TotalScore = (long)Math.Round(GetStandardisedScore());
|
||||||
score.Combo = Combo.Value;
|
score.Combo = Combo.Value;
|
||||||
score.MaxCombo = HighestCombo.Value;
|
score.MaxCombo = HighestCombo.Value;
|
||||||
score.Accuracy = Math.Round(Accuracy.Value, 4);
|
score.Accuracy = Math.Round(Accuracy.Value, 4);
|
||||||
|
@ -295,21 +295,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <returns>Whether a selection was performed.</returns>
|
/// <returns>Whether a selection was performed.</returns>
|
||||||
private bool beginClickSelection(MouseButtonEvent e)
|
private bool beginClickSelection(MouseButtonEvent e)
|
||||||
{
|
{
|
||||||
Debug.Assert(!clickSelectionBegan);
|
|
||||||
|
|
||||||
bool selectedPerformed = true;
|
|
||||||
|
|
||||||
foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren)
|
foreach (SelectionBlueprint blueprint in SelectionBlueprints.AliveChildren)
|
||||||
{
|
{
|
||||||
if (blueprint.IsHovered)
|
if (!blueprint.IsHovered) continue;
|
||||||
{
|
|
||||||
selectedPerformed &= SelectionHandler.HandleSelectionRequested(blueprint, e.CurrentState);
|
if (SelectionHandler.HandleSelectionRequested(blueprint, e))
|
||||||
clickSelectionBegan = true;
|
return clickSelectionBegan = true;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectedPerformed;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -14,7 +14,7 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
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.States;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -218,17 +218,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// Handle a blueprint requesting selection.
|
/// Handle a blueprint requesting selection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="blueprint">The blueprint.</param>
|
/// <param name="blueprint">The blueprint.</param>
|
||||||
/// <param name="state">The input state at the point of selection.</param>
|
/// <param name="e">The mouse event responsible for selection.</param>
|
||||||
/// <returns>Whether a selection was performed.</returns>
|
/// <returns>Whether a selection was performed.</returns>
|
||||||
internal bool HandleSelectionRequested(SelectionBlueprint blueprint, InputState state)
|
internal bool HandleSelectionRequested(SelectionBlueprint blueprint, MouseButtonEvent e)
|
||||||
{
|
{
|
||||||
if (state.Keyboard.ShiftPressed && state.Mouse.IsPressed(MouseButton.Right))
|
if (e.ShiftPressed && e.Button == MouseButton.Right)
|
||||||
{
|
{
|
||||||
handleQuickDeletion(blueprint);
|
handleQuickDeletion(blueprint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.Keyboard.ControlPressed && state.Mouse.IsPressed(MouseButton.Left))
|
if (e.ControlPressed && e.Button == MouseButton.Left)
|
||||||
blueprint.ToggleSelection();
|
blueprint.ToggleSelection();
|
||||||
else
|
else
|
||||||
ensureSelected(blueprint);
|
ensureSelected(blueprint);
|
||||||
|
@ -85,12 +85,13 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
{
|
{
|
||||||
textBox.Text = string.Empty;
|
textBox.Text = string.Empty;
|
||||||
|
|
||||||
textBox.Current.Disabled = true;
|
// cannot use textBox.Current.Disabled due to https://github.com/ppy/osu-framework/issues/3919
|
||||||
|
textBox.ReadOnly = true;
|
||||||
button.Enabled.Value = false;
|
button.Enabled.Value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
textBox.Current.Disabled = false;
|
textBox.ReadOnly = false;
|
||||||
button.Enabled.Value = true;
|
button.Enabled.Value = true;
|
||||||
|
|
||||||
textBox.Text = $"{group.NewValue.Time:n0}";
|
textBox.Text = $"{group.NewValue.Time:n0}";
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Screens
|
namespace osu.Game.Screens
|
||||||
{
|
{
|
||||||
@ -43,6 +44,11 @@ namespace osu.Game.Screens
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IBindable<OverlayActivation> OverlayActivationMode { get; }
|
IBindable<OverlayActivation> OverlayActivationMode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current <see cref="UserActivity"/> for this screen.
|
||||||
|
/// </summary>
|
||||||
|
IBindable<UserActivity> Activity { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of parallax to be applied while this screen is displayed.
|
/// The amount of parallax to be applied while this screen is displayed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -14,6 +14,7 @@ using osu.Game.Online.Multiplayer;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Screens.Multi.Lounge.Components;
|
using osu.Game.Screens.Multi.Lounge.Components;
|
||||||
using osu.Game.Screens.Multi.Match;
|
using osu.Game.Screens.Multi.Match;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Multi.Lounge
|
namespace osu.Game.Screens.Multi.Lounge
|
||||||
{
|
{
|
||||||
@ -24,6 +25,8 @@ namespace osu.Game.Screens.Multi.Lounge
|
|||||||
|
|
||||||
protected FilterControl Filter;
|
protected FilterControl Filter;
|
||||||
|
|
||||||
|
protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby();
|
||||||
|
|
||||||
private readonly Bindable<bool> initialRoomsReceived = new Bindable<bool>();
|
private readonly Bindable<bool> initialRoomsReceived = new Bindable<bool>();
|
||||||
|
|
||||||
private Container content;
|
private Container content;
|
||||||
|
@ -21,6 +21,7 @@ using osu.Game.Screens.Multi.Play;
|
|||||||
using osu.Game.Screens.Multi.Ranking;
|
using osu.Game.Screens.Multi.Ranking;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
|
using osu.Game.Users;
|
||||||
using Footer = osu.Game.Screens.Multi.Match.Components.Footer;
|
using Footer = osu.Game.Screens.Multi.Match.Components.Footer;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Multi.Match
|
namespace osu.Game.Screens.Multi.Match
|
||||||
@ -60,6 +61,7 @@ namespace osu.Game.Screens.Multi.Match
|
|||||||
public MatchSubScreen(Room room)
|
public MatchSubScreen(Room room)
|
||||||
{
|
{
|
||||||
Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
|
Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
|
||||||
|
Activity.Value = new UserActivity.InLobby(room);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -24,6 +24,7 @@ using osu.Game.Screens.Multi.Lounge;
|
|||||||
using osu.Game.Screens.Multi.Lounge.Components;
|
using osu.Game.Screens.Multi.Lounge.Components;
|
||||||
using osu.Game.Screens.Multi.Match;
|
using osu.Game.Screens.Multi.Match;
|
||||||
using osu.Game.Screens.Multi.Match.Components;
|
using osu.Game.Screens.Multi.Match.Components;
|
||||||
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Multi
|
namespace osu.Game.Screens.Multi
|
||||||
@ -140,10 +141,10 @@ namespace osu.Game.Screens.Multi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
screenStack.Push(loungeSubScreen = new LoungeSubScreen());
|
|
||||||
|
|
||||||
screenStack.ScreenPushed += screenPushed;
|
screenStack.ScreenPushed += screenPushed;
|
||||||
screenStack.ScreenExited += screenExited;
|
screenStack.ScreenExited += screenExited;
|
||||||
|
|
||||||
|
screenStack.Push(loungeSubScreen = new LoungeSubScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
|
||||||
@ -311,18 +312,18 @@ namespace osu.Game.Screens.Multi
|
|||||||
|
|
||||||
private void screenPushed(IScreen lastScreen, IScreen newScreen)
|
private void screenPushed(IScreen lastScreen, IScreen newScreen)
|
||||||
{
|
{
|
||||||
subScreenChanged(newScreen);
|
subScreenChanged(lastScreen, newScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void screenExited(IScreen lastScreen, IScreen newScreen)
|
private void screenExited(IScreen lastScreen, IScreen newScreen)
|
||||||
{
|
{
|
||||||
subScreenChanged(newScreen);
|
subScreenChanged(lastScreen, newScreen);
|
||||||
|
|
||||||
if (screenStack.CurrentScreen == null && this.IsCurrentScreen())
|
if (screenStack.CurrentScreen == null && this.IsCurrentScreen())
|
||||||
this.Exit();
|
this.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void subScreenChanged(IScreen newScreen)
|
private void subScreenChanged(IScreen lastScreen, IScreen newScreen)
|
||||||
{
|
{
|
||||||
switch (newScreen)
|
switch (newScreen)
|
||||||
{
|
{
|
||||||
@ -337,6 +338,12 @@ namespace osu.Game.Screens.Multi
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lastScreen is IOsuScreen lastOsuScreen)
|
||||||
|
Activity.UnbindFrom(lastOsuScreen.Activity);
|
||||||
|
|
||||||
|
if (newScreen is IOsuScreen newOsuScreen)
|
||||||
|
((IBindable<UserActivity>)Activity).BindTo(newOsuScreen.Activity);
|
||||||
|
|
||||||
updatePollingRate(isIdle.Value);
|
updatePollingRate(isIdle.Value);
|
||||||
createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200);
|
createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200);
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ using osu.Game.Rulesets;
|
|||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osu.Game.Online.API;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Screens
|
namespace osu.Game.Screens
|
||||||
@ -57,28 +56,18 @@ namespace osu.Game.Screens
|
|||||||
protected new OsuGameBase Game => base.Game as OsuGameBase;
|
protected new OsuGameBase Game => base.Game as OsuGameBase;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="UserActivity"/> to set the user's activity automatically to when this screen is entered
|
/// The <see cref="UserActivity"/> to set the user's activity automatically to when this screen is entered.
|
||||||
/// <para>This <see cref="Activity"/> will be automatically set to <see cref="InitialActivity"/> for this screen on entering unless
|
/// <para>This <see cref="Activity"/> will be automatically set to <see cref="InitialActivity"/> for this screen on entering for the first time
|
||||||
/// <see cref="Activity"/> is manually set before.</para>
|
/// unless <see cref="Activity"/> is manually set before.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual UserActivity InitialActivity => null;
|
protected virtual UserActivity InitialActivity => null;
|
||||||
|
|
||||||
private UserActivity activity;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current <see cref="UserActivity"/> for this screen.
|
/// The current <see cref="UserActivity"/> for this screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected UserActivity Activity
|
protected readonly Bindable<UserActivity> Activity = new Bindable<UserActivity>();
|
||||||
{
|
|
||||||
get => activity;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == activity) return;
|
|
||||||
|
|
||||||
activity = value;
|
IBindable<UserActivity> IOsuScreen.Activity => Activity;
|
||||||
updateActivity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to disallow changes to game-wise Beatmap/Ruleset bindables for this screen (and all children).
|
/// Whether to disallow changes to game-wise Beatmap/Ruleset bindables for this screen (and all children).
|
||||||
@ -135,9 +124,6 @@ namespace osu.Game.Screens
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private OsuLogo logo { get; set; }
|
private OsuLogo logo { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private IAPIProvider api { get; set; }
|
|
||||||
|
|
||||||
protected OsuScreen()
|
protected OsuScreen()
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
@ -150,6 +136,8 @@ namespace osu.Game.Screens
|
|||||||
private void load(OsuGame osu, AudioManager audio)
|
private void load(OsuGame osu, AudioManager audio)
|
||||||
{
|
{
|
||||||
sampleExit = audio.Samples.Get(@"UI/screen-back");
|
sampleExit = audio.Samples.Get(@"UI/screen-back");
|
||||||
|
|
||||||
|
Activity.Value ??= InitialActivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnResuming(IScreen last)
|
public override void OnResuming(IScreen last)
|
||||||
@ -158,8 +146,6 @@ namespace osu.Game.Screens
|
|||||||
sampleExit?.Play();
|
sampleExit?.Play();
|
||||||
applyArrivingDefaults(true);
|
applyArrivingDefaults(true);
|
||||||
|
|
||||||
updateActivity();
|
|
||||||
|
|
||||||
base.OnResuming(last);
|
base.OnResuming(last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,9 +162,6 @@ namespace osu.Game.Screens
|
|||||||
|
|
||||||
backgroundStack?.Push(localBackground = CreateBackground());
|
backgroundStack?.Push(localBackground = CreateBackground());
|
||||||
|
|
||||||
if (activity == null)
|
|
||||||
Activity = InitialActivity;
|
|
||||||
|
|
||||||
base.OnEntering(last);
|
base.OnEntering(last);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,12 +179,6 @@ namespace osu.Game.Screens
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateActivity()
|
|
||||||
{
|
|
||||||
if (api != null)
|
|
||||||
api.Activity.Value = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when this screen was entered or resumed and the logo state is required to be adjusted.
|
/// Fired when this screen was entered or resumed and the logo state is required to be adjusted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -61,7 +62,9 @@ namespace osu.Game.Screens.Play
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private RulesetStore rulesets { get; set; }
|
private RulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
private Replay replay;
|
private Score score;
|
||||||
|
|
||||||
|
private readonly object scoreLock = new object();
|
||||||
|
|
||||||
private Container beatmapPanelContainer;
|
private Container beatmapPanelContainer;
|
||||||
|
|
||||||
@ -198,23 +201,32 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private void userSentFrames(int userId, FrameDataBundle data)
|
private void userSentFrames(int userId, FrameDataBundle data)
|
||||||
{
|
{
|
||||||
|
// this is not scheduled as it handles propagation of frames even when in a child screen (at which point we are not alive).
|
||||||
|
// probably not the safest way to handle this.
|
||||||
|
|
||||||
if (userId != targetUser.Id)
|
if (userId != targetUser.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// this should never happen as the server sends the user's state on watching,
|
lock (scoreLock)
|
||||||
// but is here as a safety measure.
|
|
||||||
if (replay == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var frame in data.Frames)
|
|
||||||
{
|
{
|
||||||
IConvertibleReplayFrame convertibleFrame = rulesetInstance.CreateConvertibleReplayFrame();
|
// this should never happen as the server sends the user's state on watching,
|
||||||
convertibleFrame.FromLegacy(frame, beatmap.Value.Beatmap);
|
// but is here as a safety measure.
|
||||||
|
if (score == null)
|
||||||
|
return;
|
||||||
|
|
||||||
var convertedFrame = (ReplayFrame)convertibleFrame;
|
// rulesetInstance should be guaranteed to be in sync with the score via scoreLock.
|
||||||
convertedFrame.Time = frame.Time;
|
Debug.Assert(rulesetInstance != null && rulesetInstance.RulesetInfo.Equals(score.ScoreInfo.Ruleset));
|
||||||
|
|
||||||
replay.Frames.Add(convertedFrame);
|
foreach (var frame in data.Frames)
|
||||||
|
{
|
||||||
|
IConvertibleReplayFrame convertibleFrame = rulesetInstance.CreateConvertibleReplayFrame();
|
||||||
|
convertibleFrame.FromLegacy(frame, beatmap.Value.Beatmap);
|
||||||
|
|
||||||
|
var convertedFrame = (ReplayFrame)convertibleFrame;
|
||||||
|
convertedFrame.Time = frame.Time;
|
||||||
|
|
||||||
|
score.Replay.Frames.Add(convertedFrame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,10 +259,13 @@ namespace osu.Game.Screens.Play
|
|||||||
if (userId != targetUser.Id)
|
if (userId != targetUser.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (replay != null)
|
lock (scoreLock)
|
||||||
{
|
{
|
||||||
replay.HasReceivedAllFrames = true;
|
if (score != null)
|
||||||
replay = null;
|
{
|
||||||
|
score.Replay.HasReceivedAllFrames = true;
|
||||||
|
score = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Schedule(clearDisplay);
|
Schedule(clearDisplay);
|
||||||
@ -283,27 +298,28 @@ namespace osu.Game.Screens.Play
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
replay ??= new Replay { HasReceivedAllFrames = false };
|
lock (scoreLock)
|
||||||
|
|
||||||
var scoreInfo = new ScoreInfo
|
|
||||||
{
|
{
|
||||||
Beatmap = resolvedBeatmap,
|
score = new Score
|
||||||
User = targetUser,
|
{
|
||||||
Mods = state.Mods.Select(m => m.ToMod(resolvedRuleset)).ToArray(),
|
ScoreInfo = new ScoreInfo
|
||||||
Ruleset = resolvedRuleset.RulesetInfo,
|
{
|
||||||
};
|
Beatmap = resolvedBeatmap,
|
||||||
|
User = targetUser,
|
||||||
|
Mods = state.Mods.Select(m => m.ToMod(resolvedRuleset)).ToArray(),
|
||||||
|
Ruleset = resolvedRuleset.RulesetInfo,
|
||||||
|
},
|
||||||
|
Replay = new Replay { HasReceivedAllFrames = false },
|
||||||
|
};
|
||||||
|
|
||||||
ruleset.Value = resolvedRuleset.RulesetInfo;
|
ruleset.Value = resolvedRuleset.RulesetInfo;
|
||||||
rulesetInstance = resolvedRuleset;
|
rulesetInstance = resolvedRuleset;
|
||||||
|
|
||||||
beatmap.Value = beatmaps.GetWorkingBeatmap(resolvedBeatmap);
|
beatmap.Value = beatmaps.GetWorkingBeatmap(resolvedBeatmap);
|
||||||
watchButton.Enabled.Value = true;
|
watchButton.Enabled.Value = true;
|
||||||
|
|
||||||
this.Push(new SpectatorPlayerLoader(new Score
|
this.Push(new SpectatorPlayerLoader(score));
|
||||||
{
|
}
|
||||||
ScoreInfo = scoreInfo,
|
|
||||||
Replay = replay,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showBeatmapPanel(SpectatorState state)
|
private void showBeatmapPanel(SpectatorState state)
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public static SkinInfo Info { get; } = new SkinInfo
|
public static SkinInfo Info { get; } = new SkinInfo
|
||||||
{
|
{
|
||||||
ID = -1, // this is temporary until database storage is decided upon.
|
ID = SkinInfo.CLASSIC_SKIN, // this is temporary until database storage is decided upon.
|
||||||
Name = "osu!classic",
|
Name = "osu!classic",
|
||||||
Creator = "team osu!"
|
Creator = "team osu!"
|
||||||
};
|
};
|
||||||
|
@ -80,7 +80,7 @@ namespace osu.Game.Skinning
|
|||||||
Math.Clamp(Clock.ElapsedFrameTime, 0, 200),
|
Math.Clamp(Clock.ElapsedFrameTime, 0, 200),
|
||||||
fill.Width, (float)Current.Value * maxFillWidth, 0, 200, Easing.OutQuint);
|
fill.Width, (float)Current.Value * maxFillWidth, 0, 200, Easing.OutQuint);
|
||||||
|
|
||||||
marker.Position = fill.Position + new Vector2(fill.DrawWidth, fill.DrawHeight / 2);
|
marker.Position = fill.Position + new Vector2(fill.DrawWidth, isNewStyle ? fill.DrawHeight / 2 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flash(JudgementResult result) => marker.Flash(result);
|
public void Flash(JudgementResult result) => marker.Flash(result);
|
||||||
|
@ -10,6 +10,10 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
public class SkinInfo : IHasFiles<SkinFileInfo>, IEquatable<SkinInfo>, IHasPrimaryKey, ISoftDelete
|
public class SkinInfo : IHasFiles<SkinFileInfo>, IEquatable<SkinInfo>, IHasPrimaryKey, ISoftDelete
|
||||||
{
|
{
|
||||||
|
internal const int DEFAULT_SKIN = 0;
|
||||||
|
internal const int CLASSIC_SKIN = -1;
|
||||||
|
internal const int RANDOM_SKIN = -2;
|
||||||
|
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
@ -26,6 +30,7 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public static SkinInfo Default { get; } = new SkinInfo
|
public static SkinInfo Default { get; } = new SkinInfo
|
||||||
{
|
{
|
||||||
|
ID = DEFAULT_SKIN,
|
||||||
Name = "osu!lazer",
|
Name = "osu!lazer",
|
||||||
Creator = "team osu!"
|
Creator = "team osu!"
|
||||||
};
|
};
|
||||||
|
@ -19,6 +19,7 @@ using osu.Framework.Graphics.Textures;
|
|||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
@ -72,7 +73,7 @@ namespace osu.Game.Skinning
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list of all usable <see cref="SkinInfo"/>s. Includes the special default skin plus all skins from <see cref="GetAllUserSkins"/>.
|
/// Returns a list of all usable <see cref="SkinInfo"/>s. Includes the special default skin plus all skins from <see cref="GetAllUserSkins"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of available <see cref="SkinInfo"/>.</returns>
|
/// <returns>A newly allocated list of available <see cref="SkinInfo"/>.</returns>
|
||||||
public List<SkinInfo> GetAllUsableSkins()
|
public List<SkinInfo> GetAllUsableSkins()
|
||||||
{
|
{
|
||||||
var userSkins = GetAllUserSkins();
|
var userSkins = GetAllUserSkins();
|
||||||
@ -84,9 +85,23 @@ namespace osu.Game.Skinning
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list of all usable <see cref="SkinInfo"/>s that have been loaded by the user.
|
/// Returns a list of all usable <see cref="SkinInfo"/>s that have been loaded by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of available <see cref="SkinInfo"/>.</returns>
|
/// <returns>A newly allocated list of available <see cref="SkinInfo"/>.</returns>
|
||||||
public List<SkinInfo> GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
public List<SkinInfo> GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
||||||
|
|
||||||
|
public void SelectRandomSkin()
|
||||||
|
{
|
||||||
|
// choose from only user skins, removing the current selection to ensure a new one is chosen.
|
||||||
|
var randomChoices = GetAllUsableSkins().Where(s => s.ID > 0 && s.ID != CurrentSkinInfo.Value.ID).ToArray();
|
||||||
|
|
||||||
|
if (randomChoices.Length == 0)
|
||||||
|
{
|
||||||
|
CurrentSkinInfo.Value = SkinInfo.Default;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentSkinInfo.Value = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length));
|
||||||
|
}
|
||||||
|
|
||||||
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
|
protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name };
|
||||||
|
|
||||||
private const string unknown_creator_string = "Unknown";
|
private const string unknown_creator_string = "Unknown";
|
||||||
|
@ -115,11 +115,11 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textureStore, Storyboard storyboard)
|
private void load(TextureStore textureStore, Storyboard storyboard)
|
||||||
{
|
{
|
||||||
for (int frame = 0; frame < Animation.FrameCount; frame++)
|
for (int frameIndex = 0; frameIndex < Animation.FrameCount; frameIndex++)
|
||||||
{
|
{
|
||||||
string framePath = Animation.Path.Replace(".", frame + ".");
|
string framePath = Animation.Path.Replace(".", frameIndex + ".");
|
||||||
|
Drawable frame = storyboard.CreateSpriteFromResourcePath(framePath, textureStore) ?? Empty();
|
||||||
AddFrame(storyboard.CreateSpriteFromResourcePath(framePath, textureStore), Animation.FrameDelay);
|
AddFrame(frame, Animation.FrameDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
Animation.ApplyTransforms(this);
|
Animation.ApplyTransforms(this);
|
||||||
|
@ -186,7 +186,7 @@ namespace osu.Game.Users
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonProperty(@"rankHistory")]
|
[JsonProperty(@"rank_history")]
|
||||||
private RankHistoryData rankHistory
|
private RankHistoryData rankHistory
|
||||||
{
|
{
|
||||||
set => statistics.RankHistory = value;
|
set => statistics.RankHistory = value;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -61,9 +62,21 @@ namespace osu.Game.Users
|
|||||||
public override string Status => @"Spectating a game";
|
public override string Status => @"Spectating a game";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SearchingForLobby : UserActivity
|
||||||
|
{
|
||||||
|
public override string Status => @"Looking for a lobby";
|
||||||
|
}
|
||||||
|
|
||||||
public class InLobby : UserActivity
|
public class InLobby : UserActivity
|
||||||
{
|
{
|
||||||
public override string Status => @"In a multiplayer lobby";
|
public override string Status => @"In a multiplayer lobby";
|
||||||
|
|
||||||
|
public readonly Room Room;
|
||||||
|
|
||||||
|
public InLobby(Room room)
|
||||||
|
{
|
||||||
|
Room = room;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user