1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 16:12:57 +08:00

Merge branch 'master' into legacy-sprite-text-fonts

This commit is contained in:
Salman Ahmed 2021-03-25 14:52:01 +03:00
commit 6aa0c9d8fd
169 changed files with 2222 additions and 845 deletions

View File

@ -1,7 +1,18 @@
---
name: Bug Report
about: Issues regarding encountered bugs.
about: Report a bug or crash to desktop
---
<!--
IMPORTANT: Your issue may already be reported.
Please check:
- Pinned issues, at the top of https://github.com/ppy/osu/issues
- Current priority 0 issues at https://github.com/ppy/osu/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Apriority%3A0
- Search for your issue. If you find that it already exists, please respond with a reaction or add any further information that may be helpful.
-->
**Describe the bug:**
**Screenshots or videos showing encountered issue:**
@ -9,6 +20,7 @@ about: Issues regarding encountered bugs.
**osu!lazer version:**
**Logs:**
<!--
*please attach logs here, which are located at:*
- `%AppData%/osu/logs` *(on Windows),*

View File

@ -1,20 +0,0 @@
---
name: Crash Report
about: Issues regarding crashes or permanent freezes.
---
**Describe the crash:**
**Screenshots or videos showing encountered issue:**
**osu!lazer version:**
**Logs:**
<!--
*please attach logs here, which are located at:*
- `%AppData%/osu/logs` *(on Windows),*
- `~/.local/share/osu/logs` *(on Linux & macOS).*
- `Android/Data/sh.ppy.osulazer/logs` *(on Android)*,
- on iOS they can be obtained by connecting your device to your desktop and copying the `logs` directory from the app's own document storage using iTunes. (https://support.apple.com/en-us/HT201301#copy-to-computer)
-->
**Computer Specifications:**

View File

@ -1,6 +1,6 @@
---
name: Feature Request
about: Features you would like to see in the game!
about: Propose a feature you would like to see in the game!
---
**Describe the new feature:**

View File

@ -1,20 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu! (legacy osuTK)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="--tk" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net5.0" />
<method v="2">
<option name="Build" />
</method>
</configuration>
</component>

View File

@ -52,6 +52,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.309.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.323.0" />
</ItemGroup>
</Project>

View File

@ -136,24 +136,12 @@ namespace osu.Desktop
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
switch (host.Window)
{
// Legacy osuTK DesktopGameWindow
case OsuTKDesktopWindow desktopGameWindow:
desktopGameWindow.CursorState |= CursorState.Hidden;
desktopGameWindow.SetIconFromStream(iconStream);
desktopGameWindow.Title = Name;
desktopGameWindow.FileDrop += (_, e) => fileDrop(e.FileNames);
break;
var desktopWindow = (SDL2DesktopWindow)host.Window;
// SDL2 DesktopWindow
case SDL2DesktopWindow desktopWindow:
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.SetIconFromStream(iconStream);
desktopWindow.Title = Name;
desktopWindow.DragDrop += f => fileDrop(new[] { f });
break;
}
desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.SetIconFromStream(iconStream);
desktopWindow.Title = Name;
desktopWindow.DragDrop += f => fileDrop(new[] { f });
}
private void fileDrop(string[] filePaths)

View File

@ -22,9 +22,8 @@ namespace osu.Desktop
{
// Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory;
bool useOsuTK = args.Contains("--tk");
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true, useOsuTK: useOsuTK))
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
{
host.ExceptionThrown += handleException;

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[BackgroundDependencyLoader]
private void load()
{
LocalConfig.Set(OsuSetting.IncreaseFirstObjectVisibility, false);
LocalConfig.SetValue(OsuSetting.IncreaseFirstObjectVisibility, false);
}
[Test]

View File

@ -202,7 +202,7 @@ namespace osu.Game.Rulesets.Catch.Tests
public void TestHitLightingColour()
{
var fruitColour = SkinConfiguration.DefaultComboColours[1];
AddStep("enable hit lighting", () => config.Set(OsuSetting.HitLighting, true));
AddStep("enable hit lighting", () => config.SetValue(OsuSetting.HitLighting, true));
AddStep("catch fruit", () => attemptCatch(new Fruit()));
AddAssert("correct hit lighting colour", () =>
catcher.ChildrenOfType<HitExplosion>().First()?.ObjectColour == fruitColour);
@ -211,7 +211,7 @@ namespace osu.Game.Rulesets.Catch.Tests
[Test]
public void TestHitLightingDisabled()
{
AddStep("disable hit lighting", () => config.Set(OsuSetting.HitLighting, false));
AddStep("disable hit lighting", () => config.SetValue(OsuSetting.HitLighting, false));
AddStep("catch fruit", () => attemptCatch(new Fruit()));
AddAssert("no hit lighting", () => !catcher.ChildrenOfType<HitExplosion>().Any());
}

View File

@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames");
Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time");
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Special1), "Special1 has not been pressed");
Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Special1), "Special1 has not been released");
}
@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames");
Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time");
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released");
@ -148,9 +148,9 @@ namespace osu.Game.Rulesets.Mania.Tests
Assert.IsTrue(generated.Frames.Count == frame_offset + 4, "Replay must have 4 generated frames");
Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time");
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time");
Assert.AreEqual(3000, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time");
Assert.AreEqual(2000, generated.Frames[frame_offset + 1].Time, "Incorrect second note hit time");
Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time");
Assert.AreEqual(4000, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time");
Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed");
Assert.IsTrue(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
Assert.IsFalse(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key1), "Key1 has not been released");
@ -168,7 +168,7 @@ namespace osu.Game.Rulesets.Mania.Tests
// | | |
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 - ManiaAutoGenerator.RELEASE_DELAY });
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 });
var generated = new ManiaAutoGenerator(beatmap).Generate();

View File

@ -5,11 +5,13 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Replays;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Replays;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Objects;
@ -345,6 +347,14 @@ namespace osu.Game.Rulesets.Mania.Tests
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
AddUntilStep("wait for head", () => currentPlayer.GameplayClockContainer.GameplayClock.CurrentTime >= time_head);
AddAssert("head is visible",
() => currentPlayer.ChildrenOfType<DrawableHoldNote>()
.Single(note => note.HitObject == beatmap.HitObjects[0])
.Head
.Alpha == 1);
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
}
@ -352,6 +362,8 @@ namespace osu.Game.Rulesets.Mania.Tests
{
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
protected override bool PauseOnFocusLost => false;
public ScoreAccessibleReplayPlayer(Score score)

View File

@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Configuration
{
base.InitialiseDefaults();
Set(ManiaRulesetSetting.ScrollTime, 1500.0, DrawableManiaRuleset.MIN_TIME_RANGE, DrawableManiaRuleset.MAX_TIME_RANGE, 5);
Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
SetDefault(ManiaRulesetSetting.ScrollTime, 1500.0, DrawableManiaRuleset.MIN_TIME_RANGE, DrawableManiaRuleset.MAX_TIME_RANGE, 5);
SetDefault(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
}
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
/// <summary>
@ -25,6 +27,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
LifetimeEnd = LifetimeStart + 30000;
}
protected override void UpdateHitStateTransforms(ArmedState state)
{
// suppress the base call explicitly.
// the hold note head should never change its visual state on its own due to the "freezing" mechanic
// (when hit, it remains visible in place at the judgement line; when dropped, it will scroll past the line).
// it will be hidden along with its parenting hold note when required.
}
public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note
public override void OnReleased(ManiaAction action)

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Replays;
@ -85,20 +86,28 @@ namespace osu.Game.Rulesets.Mania.Replays
{
var currentObject = Beatmap.HitObjects[i];
var nextObjectInColumn = GetNextObject(i); // Get the next object that requires pressing the same button
double endTime = currentObject.GetEndTime();
bool canDelayKeyUp = nextObjectInColumn == null ||
nextObjectInColumn.StartTime > endTime + RELEASE_DELAY;
double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInColumn.StartTime - endTime) * 0.9;
var releaseTime = calculateReleaseTime(currentObject, nextObjectInColumn);
yield return new HitPoint { Time = currentObject.StartTime, Column = currentObject.Column };
yield return new ReleasePoint { Time = endTime + calculatedDelay, Column = currentObject.Column };
yield return new ReleasePoint { Time = releaseTime, Column = currentObject.Column };
}
}
private double calculateReleaseTime(HitObject currentObject, HitObject nextObject)
{
double endTime = currentObject.GetEndTime();
if (currentObject is HoldNote)
// hold note releases must be timed exactly.
return endTime;
bool canDelayKeyUpFully = nextObject == null ||
nextObject.StartTime > endTime + RELEASE_DELAY;
return endTime + (canDelayKeyUpFully ? RELEASE_DELAY : (nextObject.StartTime - endTime) * 0.9);
}
protected override HitObject GetNextObject(int currentIndex)
{
int desiredColumn = Beatmap.HitObjects[currentIndex].Column;

View File

@ -17,6 +17,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
{
public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion
{
public const double FADE_IN_DURATION = 80;
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private Drawable explosion;
@ -72,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
(explosion as IFramedAnimation)?.GotoFrame(0);
explosion?.FadeInFromZero(80)
explosion?.FadeInFromZero(FADE_IN_DURATION)
.Then().FadeOut(120);
}
}

View File

@ -101,8 +101,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
{
if (action == column.Action.Value)
{
upSprite.FadeTo(1);
downSprite.FadeTo(0);
upSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(1);
downSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(0);
}
}
}

View File

@ -140,7 +140,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
return animation == null ? null : new LegacyManiaJudgementPiece(result, animation);
}
public override Sample GetSample(ISampleInfo sampleInfo)
public override ISample GetSample(ISampleInfo sampleInfo)
{
// layered hit sounds never play in mania
if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample && legacySample.IsLayered)

View File

@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
[TestCase(6.9311451172608853d, "diffcalc-test")]
[TestCase(1.0736587013228804d, "zero-length-sliders")]
[TestCase(6.9311451172574934d, "diffcalc-test")]
[TestCase(1.0736586907780401d, "zero-length-sliders")]
public void Test(double expected, string name)
=> base.Test(expected, name);
[TestCase(8.6228371119393064d, "diffcalc-test")]
[TestCase(1.2864585434597433d, "zero-length-sliders")]
[TestCase(8.6228371119271454d, "diffcalc-test")]
[TestCase(1.2864585280364178d, "zero-length-sliders")]
public void TestClockRateAdjusted(double expected, string name)
=> Test(expected, name, new OsuModDoubleTime());

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,2 +1,6 @@
[General]
Version: 1.0
Version: 1.0
[Fonts]
HitCircleOverlap: 3
ScoreOverlap: 3

View File

@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests
return null;
}
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();

View File

@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[Test]
public void TestHitLightingDisabled()
{
AddStep("hit lighting disabled", () => config.Set(OsuSetting.HitLighting, false));
AddStep("hit lighting disabled", () => config.SetValue(OsuSetting.HitLighting, false));
showResult(HitResult.Great);
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[Test]
public void TestHitLightingEnabled()
{
AddStep("hit lighting enabled", () => config.Set(OsuSetting.HitLighting, true));
AddStep("hit lighting enabled", () => config.SetValue(OsuSetting.HitLighting, true));
showResult(HitResult.Great);

View File

@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Tests
AddSliderStep("circle size", 0f, 10f, 0f, val =>
{
config.Set(OsuSetting.AutoCursorSize, true);
config.SetValue(OsuSetting.AutoCursorSize, true);
gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = val;
Scheduler.AddOnce(recreate);
});
@ -64,21 +64,21 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase(10, 1.5f)]
public void TestSizing(int circleSize, float userScale)
{
AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale));
AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, userScale));
AddStep($"adjust cs to {circleSize}", () => gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSize);
AddStep("turn on autosizing", () => config.Set(OsuSetting.AutoCursorSize, true));
AddStep("turn on autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, true));
AddStep("load content", loadContent);
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize) * userScale);
AddStep("set user scale to 1", () => config.Set(OsuSetting.GameplayCursorSize, 1f));
AddStep("set user scale to 1", () => config.SetValue(OsuSetting.GameplayCursorSize, 1f));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize));
AddStep("turn off autosizing", () => config.Set(OsuSetting.AutoCursorSize, false));
AddStep("turn off autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, false));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == 1);
AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale));
AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, userScale));
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == userScale);
}

View File

@ -42,10 +42,10 @@ namespace osu.Game.Rulesets.Osu.Tests
{
AddStep("enable user provider", () => testUserSkin.Enabled = true);
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
AddStep("enable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, true));
checkNextHitObject("beatmap");
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
AddStep("disable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, false));
checkNextHitObject("user");
AddStep("disable user provider", () => testUserSkin.Enabled = false);
@ -57,20 +57,20 @@ namespace osu.Game.Rulesets.Osu.Tests
{
AddStep("enable user provider", () => testUserSkin.Enabled = true);
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
AddStep("enable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, true));
AddStep("enable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, true));
checkNextHitObject("beatmap");
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
AddStep("enable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, true));
AddStep("disable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, false));
checkNextHitObject("beatmap");
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
AddStep("disable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, false));
AddStep("enable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, true));
checkNextHitObject("user");
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
AddStep("disable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, false));
AddStep("disable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, false));
checkNextHitObject("user");
AddStep("disable user provider", () => testUserSkin.Enabled = false);
@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null;
public Sample GetSample(ISampleInfo sampleInfo) => null;
public ISample GetSample(ISampleInfo sampleInfo) => null;
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => default;
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => null;

View File

@ -17,10 +17,10 @@ namespace osu.Game.Rulesets.Osu.Configuration
protected override void InitialiseDefaults()
{
base.InitialiseDefaults();
Set(OsuRulesetSetting.SnakingInSliders, true);
Set(OsuRulesetSetting.SnakingOutSliders, true);
Set(OsuRulesetSetting.ShowCursorTrail, true);
Set(OsuRulesetSetting.PlayfieldBorderStyle, PlayfieldBorderStyle.None);
SetDefault(OsuRulesetSetting.SnakingInSliders, true);
SetDefault(OsuRulesetSetting.SnakingOutSliders, true);
SetDefault(OsuRulesetSetting.ShowCursorTrail, true);
SetDefault(OsuRulesetSetting.PlayfieldBorderStyle, PlayfieldBorderStyle.None);
}
}

View File

@ -7,11 +7,13 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
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.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit;
using osuTK;
@ -23,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
/// <summary>
/// A visualisation of a single <see cref="PathControlPoint"/> in a <see cref="Slider"/>.
/// </summary>
public class PathControlPointPiece : BlueprintPiece<Slider>
public class PathControlPointPiece : BlueprintPiece<Slider>, IHasTooltip
{
public Action<PathControlPointPiece, MouseButtonEvent> RequestSelection;
@ -195,7 +197,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
markerRing.Alpha = IsSelected.Value ? 1 : 0;
Color4 colour = ControlPoint.Type.Value != null ? colours.Red : colours.Yellow;
Color4 colour = getColourFromNodeType();
if (IsHovered || IsSelected.Value)
colour = colour.Lighten(1);
@ -203,5 +205,28 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
marker.Colour = colour;
marker.Scale = new Vector2(slider.Scale);
}
private Color4 getColourFromNodeType()
{
if (!(ControlPoint.Type.Value is PathType pathType))
return colours.Yellow;
switch (pathType)
{
case PathType.Catmull:
return colours.Seafoam;
case PathType.Bezier:
return colours.Pink;
case PathType.PerfectCurve:
return colours.PurpleDark;
default:
return colours.Red;
}
}
public string TooltipText => ControlPoint.Type.Value.ToString() ?? string.Empty;
}
}

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -28,6 +29,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
protected SliderBodyPiece BodyPiece { get; private set; }
protected SliderCircleSelectionBlueprint HeadBlueprint { get; private set; }
protected SliderCircleSelectionBlueprint TailBlueprint { get; private set; }
[CanBeNull]
protected PathControlPointVisualiser ControlPointVisualiser { get; private set; }
private readonly DrawableSlider slider;
@ -114,6 +117,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
// throw away frame buffers on deselection.
ControlPointVisualiser?.Expire();
ControlPointVisualiser = null;
BodyPiece.RecyclePath();
}

View File

@ -164,28 +164,29 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
ApproachCircle.Expire(true);
}
protected override void UpdateStartTimeStateTransforms()
{
base.UpdateStartTimeStateTransforms();
ApproachCircle.FadeOut(50);
}
protected override void UpdateHitStateTransforms(ArmedState state)
{
Debug.Assert(HitObject.HitWindows != null);
// todo: temporary / arbitrary, used for lifetime optimisation.
this.Delay(800).FadeOut();
switch (state)
{
case ArmedState.Idle:
this.Delay(HitObject.TimePreempt).FadeOut(500);
HitArea.HitAction = null;
break;
case ArmedState.Miss:
ApproachCircle.FadeOut(50);
this.FadeOut(100);
break;
case ArmedState.Hit:
ApproachCircle.FadeOut(50);
// todo: temporary / arbitrary
this.Delay(800).FadeOut();
break;
}
Expire();

View File

@ -33,12 +33,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public SpinnerSpmCounter SpmCounter { get; private set; }
private Container<DrawableSpinnerTick> ticks;
private SpinnerBonusDisplay bonusDisplay;
private PausableSkinnableSound spinningSample;
private Bindable<bool> isSpinning;
private bool spinnerFrequencyModulate;
/// <summary>
/// The amount of bonus score gained from spinning after the required number of spins, for display purposes.
/// </summary>
public IBindable<double> GainedBonus => gainedBonus;
private readonly Bindable<double> gainedBonus = new Bindable<double>();
private const double fade_out_duration = 160;
public DrawableSpinner()
: this(null)
{
@ -65,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SpinnerBody), _ => new DefaultSpinnerDisc()),
new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SpinnerBody), _ => new DefaultSpinner()),
RotationTracker = new SpinnerRotationTracker(this)
}
},
@ -76,12 +84,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Y = 120,
Alpha = 0
},
bonusDisplay = new SpinnerBonusDisplay
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Y = -120,
},
spinningSample = new PausableSkinnableSound
{
Volume = { Value = 0 },
@ -131,12 +133,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (tracking.NewValue)
{
if (!spinningSample.IsPlaying)
spinningSample?.Play();
spinningSample?.VolumeTo(1, 300);
spinningSample.Play();
spinningSample.VolumeTo(1, 300);
}
else
{
spinningSample?.VolumeTo(0, 300).OnComplete(_ => spinningSample.Stop());
spinningSample.VolumeTo(0, fade_out_duration);
}
}
@ -173,7 +176,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
base.UpdateHitStateTransforms(state);
this.FadeOut(160).Expire();
this.FadeOut(fade_out_duration).OnComplete(_ =>
{
// looping sample should be stopped here as it is safer than running in the OnComplete
// of the volume transition above.
spinningSample.Stop();
});
Expire();
// skin change does a rewind of transforms, which will stop the spinning sound from playing if it's currently in playback.
isSpinning?.TriggerChange();
@ -288,6 +298,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private void fadeInCounter() => SpmCounter.FadeIn(HitObject.TimeFadeIn);
private static readonly int score_per_tick = new SpinnerBonusTick.OsuSpinnerBonusTickJudgement().MaxNumericResult;
private int wholeSpins;
private void updateBonusScore()
@ -312,8 +324,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (tick != null)
{
tick.TriggerResult(true);
if (tick is DrawableSpinnerBonusTick)
bonusDisplay.SetBonusCount(spins - HitObject.SpinsRequired);
gainedBonus.Value = score_per_tick * (spins - HitObject.SpinsRequired);
}
wholeSpins++;

View File

@ -18,6 +18,6 @@ namespace osu.Game.Rulesets.Osu
SliderFollowCircle,
SliderBall,
SliderBody,
SpinnerBody
SpinnerBody,
}
}

View File

@ -1,5 +1,18 @@
{
"Mappings": [{
"StartTime": 114993,
"Objects": [{
"StartTime": 114993,
"EndTime": 114993,
"X": 493,
"Y": 92
}, {
"StartTime": 115290,
"EndTime": 115290,
"X": 451.659241,
"Y": 267.188
}]
}, {
"StartTime": 118858.0,
"Objects": [{
"StartTime": 118858.0,

View File

@ -9,7 +9,9 @@ SliderMultiplier:1.87
SliderTickRate:1
[TimingPoints]
49051,230.769230769231,4,2,1,15,1,0
114000,346.820809248555,4,2,1,71,1,0
118000,230.769230769231,4,2,1,15,1,0
[HitObjects]
493,92,114993,2,0,P|472:181|442:308,1,180,12|0,0:0|0:0,0:0:0:0:
219,215,118858,2,0,P|224:170|244:-10,1,187,8|2,0:0|0:0,0:0:0:0:

View File

@ -0,0 +1,68 @@
// 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.Globalization;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Skinning.Default
{
public class DefaultSpinner : CompositeDrawable
{
private DrawableSpinner drawableSpinner;
private OsuSpriteText bonusCounter;
public DefaultSpinner()
{
RelativeSizeAxes = Axes.Both;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
}
[BackgroundDependencyLoader]
private void load(DrawableHitObject drawableHitObject)
{
drawableSpinner = (DrawableSpinner)drawableHitObject;
AddRangeInternal(new Drawable[]
{
new DefaultSpinnerDisc
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
bonusCounter = new OsuSpriteText
{
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Numeric.With(size: 24),
Y = -120,
}
});
}
private IBindable<double> gainedBonus;
protected override void LoadComplete()
{
base.LoadComplete();
gainedBonus = drawableSpinner.GainedBonus.GetBoundCopy();
gainedBonus.BindValueChanged(bonus =>
{
bonusCounter.Text = bonus.NewValue.ToString(NumberFormatInfo.InvariantInfo);
bonusCounter.FadeOutFromOne(1500);
bonusCounter.ScaleTo(1.5f).Then().ScaleTo(1f, 1000, Easing.OutQuint);
});
}
}
}

View File

@ -40,14 +40,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
public DefaultSpinnerDisc()
{
RelativeSizeAxes = Axes.Both;
// we are slightly bigger than our parent, to clip the top and bottom of the circle
// this should probably be revisited when scaled spinners are a thing.
Scale = new Vector2(initial_scale);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
}
[BackgroundDependencyLoader]

View File

@ -74,10 +74,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
private void updateState(DrawableHitObject drawableObject, ArmedState state)
{
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime, true))
{
using (BeginAbsoluteSequence(drawableObject.StateUpdateTime))
glow.FadeOut(400);
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
{
switch (state)
{
case ArmedState.Hit:

View File

@ -1,47 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Skinning.Default
{
/// <summary>
/// Shows incremental bonus score achieved for a spinner.
/// </summary>
public class SpinnerBonusDisplay : CompositeDrawable
{
private static readonly int score_per_tick = new SpinnerBonusTick().CreateJudgement().MaxNumericResult;
private readonly OsuSpriteText bonusCounter;
public SpinnerBonusDisplay()
{
AutoSizeAxes = Axes.Both;
InternalChild = bonusCounter = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Numeric.With(size: 24),
Alpha = 0,
};
}
private int displayedCount;
public void SetBonusCount(int count)
{
if (displayedCount == count)
return;
displayedCount = count;
bonusCounter.Text = $"{score_per_tick * count}";
bonusCounter.FadeOutFromOne(1500);
bonusCounter.ScaleTo(1.5f).Then().ScaleTo(1f, 1000, Easing.OutQuint);
}
}
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Globalization;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -32,6 +33,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
private Sprite spin;
private Sprite clear;
private LegacySpriteText bonusCounter;
[BackgroundDependencyLoader]
private void load(DrawableHitObject drawableHitObject, ISkinSource source)
{
@ -45,36 +48,67 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
DrawableSpinner = (DrawableSpinner)drawableHitObject;
AddRangeInternal(new[]
Container overlayContainer;
AddInternal(overlayContainer = new Container
{
spin = new Sprite
Depth = float.MinValue,
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Depth = float.MinValue,
Texture = source.GetTexture("spinner-spin"),
Scale = new Vector2(SPRITE_SCALE),
Y = SPINNER_TOP_OFFSET + 335,
},
clear = new Sprite
{
Alpha = 0,
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Depth = float.MinValue,
Texture = source.GetTexture("spinner-clear"),
Scale = new Vector2(SPRITE_SCALE),
Y = SPINNER_TOP_OFFSET + 115,
},
spin = new Sprite
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-spin"),
Scale = new Vector2(SPRITE_SCALE),
Y = SPINNER_TOP_OFFSET + 335,
},
clear = new Sprite
{
Alpha = 0,
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Texture = source.GetTexture("spinner-clear"),
Scale = new Vector2(SPRITE_SCALE),
Y = SPINNER_TOP_OFFSET + 115,
},
}
});
bonusCounter = (source.GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreText)) as LegacySpriteText)?.With(c =>
{
c.Alpha = 0f;
c.Anchor = Anchor.TopCentre;
c.Origin = Anchor.Centre;
c.Font = c.Font.With(fixedWidth: false);
c.Scale = new Vector2(SPRITE_SCALE);
c.Y = SPINNER_TOP_OFFSET + 299;
});
if (bonusCounter != null)
overlayContainer.Add(bonusCounter);
}
private IBindable<double> gainedBonus;
private readonly Bindable<bool> completed = new Bindable<bool>();
protected override void LoadComplete()
{
base.LoadComplete();
if (bonusCounter != null)
{
gainedBonus = DrawableSpinner.GainedBonus.GetBoundCopy();
gainedBonus.BindValueChanged(bonus =>
{
bonusCounter.Text = bonus.NewValue.ToString(NumberFormatInfo.InvariantInfo);
bonusCounter.FadeOutFromOne(800, Easing.Out);
bonusCounter.ScaleTo(SPRITE_SCALE * 2f).Then().ScaleTo(SPRITE_SCALE * 1.28f, 800, Easing.Out);
});
}
completed.BindValueChanged(onCompletedChanged, true);
DrawableSpinner.ApplyCustomUpdateState += UpdateStateTransforms;

View File

@ -2,8 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
@ -13,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
[TestFixture]
public class TestSceneHitExplosion : TaikoSkinnableTestScene
{
protected override double TimePerAction => 100;
[Test]
public void TestNormalHit()
{
@ -21,11 +27,14 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
AddStep("Miss", () => SetContents(() => getContentFor(createHit(HitResult.Miss))));
}
[Test]
public void TestStrongHit([Values(false, true)] bool hitBoth)
[TestCase(HitResult.Great)]
[TestCase(HitResult.Ok)]
public void TestStrongHit(HitResult type)
{
AddStep("Great", () => SetContents(() => getContentFor(createStrongHit(HitResult.Great, hitBoth))));
AddStep("Good", () => SetContents(() => getContentFor(createStrongHit(HitResult.Ok, hitBoth))));
AddStep("create hit", () => SetContents(() => getContentFor(createStrongHit(type))));
AddStep("visualise second hit",
() => this.ChildrenOfType<HitExplosion>()
.ForEach(e => e.VisualiseSecondHit(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement()))));
}
private Drawable getContentFor(DrawableTestHit hit)
@ -38,17 +47,17 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
// the hit needs to be added to hierarchy in order for nested objects to be created correctly.
// setting zero alpha is supposed to prevent the test from looking broken.
hit.With(h => h.Alpha = 0),
new HitExplosion(hit, hit.Type)
new HitExplosion(hit.Type)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
}.With(explosion => explosion.Apply(hit))
}
};
}
private DrawableTestHit createHit(HitResult type) => new DrawableTestHit(new Hit { StartTime = Time.Current }, type);
private DrawableTestHit createStrongHit(HitResult type, bool hitBoth) => new DrawableTestStrongHit(Time.Current, type, hitBoth);
private DrawableTestHit createStrongHit(HitResult type) => new DrawableTestStrongHit(Time.Current, type);
}
}

View File

@ -11,7 +11,6 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
@ -108,12 +107,12 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Ok : HitResult.Great;
Hit hit = new Hit();
Hit hit = new Hit { StartTime = DrawableRuleset.Playfield.Time.Current };
var h = new DrawableTestHit(hit, kiai: kiai) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
DrawableRuleset.Playfield.Add(h);
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(hit, new TaikoJudgement()) { Type = hitResult });
}
private void addStrongHitJudgement(bool kiai)
@ -122,6 +121,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
Hit hit = new Hit
{
StartTime = DrawableRuleset.Playfield.Time.Current,
IsStrong = true,
Samples = createSamples(strong: true)
};
@ -129,8 +129,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
DrawableRuleset.Playfield.Add(h);
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h.NestedHitObjects.Single(), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great });
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(hit, new TaikoJudgement()) { Type = hitResult });
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h.NestedHitObjects.Single(), new JudgementResult(hit.NestedHitObjects.Single(), new TaikoStrongJudgement()) { Type = HitResult.Great });
}
private void addMissJudgement()

View File

@ -1,22 +1,22 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects.Drawables;
using osu.Game.Rulesets.Taiko.UI;
namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
{
public class LegacyHitExplosion : CompositeDrawable
public class LegacyHitExplosion : CompositeDrawable, IAnimatableHitExplosion
{
private readonly Drawable sprite;
private readonly Drawable strongSprite;
private DrawableStrongNestedHit nestedStrongHit;
private bool switchedToStrongSprite;
[CanBeNull]
private readonly Drawable strongSprite;
/// <summary>
/// Creates a new legacy hit explosion.
@ -27,14 +27,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
/// </remarks>
/// <param name="sprite">The normal legacy explosion sprite.</param>
/// <param name="strongSprite">The strong legacy explosion sprite.</param>
public LegacyHitExplosion(Drawable sprite, Drawable strongSprite = null)
public LegacyHitExplosion(Drawable sprite, [CanBeNull] Drawable strongSprite = null)
{
this.sprite = sprite;
this.strongSprite = strongSprite;
}
[BackgroundDependencyLoader]
private void load(DrawableHitObject judgedObject)
private void load()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
@ -56,45 +56,30 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
s.Origin = Anchor.Centre;
}));
}
if (judgedObject is DrawableHit hit)
nestedStrongHit = hit.NestedHitObjects.SingleOrDefault() as DrawableStrongNestedHit;
}
protected override void LoadComplete()
public void Animate(DrawableHitObject drawableHitObject)
{
base.LoadComplete();
const double animation_time = 120;
(sprite as IFramedAnimation)?.GotoFrame(0);
(strongSprite as IFramedAnimation)?.GotoFrame(0);
this.FadeInFromZero(animation_time).Then().FadeOut(animation_time * 1.5);
this.ScaleTo(0.6f)
.Then().ScaleTo(1.1f, animation_time * 0.8)
.Then().ScaleTo(0.9f, animation_time * 0.4)
.Then().ScaleTo(1f, animation_time * 0.2);
Expire(true);
}
protected override void Update()
public void AnimateSecondHit()
{
base.Update();
if (strongSprite == null)
return;
if (shouldSwitchToStrongSprite() && !switchedToStrongSprite)
{
sprite.FadeOut(50, Easing.OutQuint);
strongSprite.FadeIn(50, Easing.OutQuint);
switchedToStrongSprite = true;
}
}
private bool shouldSwitchToStrongSprite()
{
if (nestedStrongHit == null || strongSprite == null)
return false;
return nestedStrongHit.IsHit;
sprite.FadeOut(50, Easing.OutQuint);
strongSprite.FadeIn(50, Easing.OutQuint);
}
}
}

View File

@ -152,7 +152,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}");
}
public override Sample GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
public override ISample GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => Source.GetConfig<TLookup, TValue>(lookup);

View File

@ -1,6 +1,7 @@
// 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 JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -13,19 +14,23 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.UI
{
internal class DefaultHitExplosion : CircularContainer
internal class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion
{
private readonly DrawableHitObject judgedObject;
private readonly HitResult result;
public DefaultHitExplosion(DrawableHitObject judgedObject, HitResult result)
[CanBeNull]
private Box body;
[Resolved]
private OsuColour colours { get; set; }
public DefaultHitExplosion(HitResult result)
{
this.judgedObject = judgedObject;
this.result = result;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
RelativeSizeAxes = Axes.Both;
@ -40,26 +45,36 @@ namespace osu.Game.Rulesets.Taiko.UI
if (!result.IsHit())
return;
bool isRim = (judgedObject.HitObject as Hit)?.Type == HitType.Rim;
InternalChildren = new[]
{
new Box
body = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = isRim ? colours.BlueDarker : colours.PinkDarker,
}
};
updateColour();
}
protected override void LoadComplete()
private void updateColour([CanBeNull] DrawableHitObject judgedObject = null)
{
base.LoadComplete();
if (body == null)
return;
bool isRim = (judgedObject?.HitObject as Hit)?.Type == HitType.Rim;
body.Colour = isRim ? colours.BlueDarker : colours.PinkDarker;
}
public void Animate(DrawableHitObject drawableHitObject)
{
updateColour(drawableHitObject);
this.ScaleTo(3f, 1000, Easing.OutQuint);
this.FadeOut(500);
}
Expire(true);
public void AnimateSecondHit()
{
}
}
}

View File

@ -2,10 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using JetBrains.Annotations;
using osuTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Objects;
@ -16,31 +18,37 @@ namespace osu.Game.Rulesets.Taiko.UI
/// <summary>
/// A circle explodes from the hit target to indicate a hitobject has been hit.
/// </summary>
internal class HitExplosion : CircularContainer
internal class HitExplosion : PoolableDrawable
{
public override bool RemoveWhenNotAlive => true;
[Cached(typeof(DrawableHitObject))]
public readonly DrawableHitObject JudgedObject;
public override bool RemoveCompletedTransforms => false;
private readonly HitResult result;
private double? secondHitTime;
[CanBeNull]
public DrawableHitObject JudgedObject;
private SkinnableDrawable skinnable;
public override double LifetimeStart => skinnable.Drawable.LifetimeStart;
public override double LifetimeEnd => skinnable.Drawable.LifetimeEnd;
public HitExplosion(DrawableHitObject judgedObject, HitResult result)
/// <summary>
/// This constructor only exists to meet the <c>new()</c> type constraint of <see cref="DrawablePool{T}"/>.
/// </summary>
public HitExplosion()
: this(HitResult.Great)
{
}
public HitExplosion(HitResult result)
{
JudgedObject = judgedObject;
this.result = result;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE);
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
}
@ -48,7 +56,47 @@ namespace osu.Game.Rulesets.Taiko.UI
[BackgroundDependencyLoader]
private void load()
{
Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(JudgedObject, result));
InternalChild = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(result));
skinnable.OnSkinChanged += runAnimation;
}
public void Apply([CanBeNull] DrawableHitObject drawableHitObject)
{
JudgedObject = drawableHitObject;
secondHitTime = null;
}
protected override void PrepareForUse()
{
base.PrepareForUse();
runAnimation();
}
private void runAnimation()
{
if (JudgedObject?.Result == null)
return;
double resultTime = JudgedObject.Result.TimeAbsolute;
LifetimeStart = resultTime;
ApplyTransformsAt(double.MinValue, true);
ClearTransforms(true);
using (BeginAbsoluteSequence(resultTime))
(skinnable.Drawable as IAnimatableHitExplosion)?.Animate(JudgedObject);
if (secondHitTime != null)
{
using (BeginAbsoluteSequence(secondHitTime.Value))
{
this.ResizeTo(new Vector2(TaikoStrongableHitObject.DEFAULT_STRONG_SIZE), 50);
(skinnable.Drawable as IAnimatableHitExplosion)?.AnimateSecondHit();
}
}
LifetimeEnd = skinnable.Drawable.LatestTransformEndTime;
}
private static TaikoSkinComponents getComponentName(HitResult result)
@ -68,12 +116,10 @@ namespace osu.Game.Rulesets.Taiko.UI
throw new ArgumentOutOfRangeException(nameof(result), $"Invalid result type: {result}");
}
/// <summary>
/// Transforms this hit explosion to visualise a secondary hit.
/// </summary>
public void VisualiseSecondHit()
public void VisualiseSecondHit(JudgementResult judgementResult)
{
this.ResizeTo(new Vector2(TaikoStrongableHitObject.DEFAULT_STRONG_SIZE), 50);
secondHitTime = judgementResult.TimeAbsolute;
runAnimation();
}
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Pooling;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.UI
{
/// <summary>
/// Pool for hit explosions of a specific type.
/// </summary>
internal class HitExplosionPool : DrawablePool<HitExplosion>
{
private readonly HitResult hitResult;
public HitExplosionPool(HitResult hitResult)
: base(15)
{
this.hitResult = hitResult;
}
protected override HitExplosion CreateNewDrawable() => new HitExplosion(hitResult);
}
}

View File

@ -0,0 +1,23 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Taiko.UI
{
/// <summary>
/// A skinnable element of a hit explosion that supports playing an animation from the current point in time.
/// </summary>
public interface IAnimatableHitExplosion
{
/// <summary>
/// Shows the hit explosion for the supplied <paramref name="drawableHitObject"/>.
/// </summary>
void Animate(DrawableHitObject drawableHitObject);
/// <summary>
/// Transforms the hit explosion to visualise a secondary hit.
/// </summary>
void AnimateSecondHit();
}
}

View File

@ -42,6 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private SkinnableDrawable mascot;
private readonly IDictionary<HitResult, DrawablePool<DrawableTaikoJudgement>> judgementPools = new Dictionary<HitResult, DrawablePool<DrawableTaikoJudgement>>();
private readonly IDictionary<HitResult, HitExplosionPool> explosionPools = new Dictionary<HitResult, HitExplosionPool>();
private ProxyContainer topLevelHitContainer;
private Container rightArea;
@ -166,10 +167,15 @@ namespace osu.Game.Rulesets.Taiko.UI
RegisterPool<SwellTick, DrawableSwellTick>(100);
var hitWindows = new TaikoHitWindows();
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => hitWindows.IsHitResultAllowed(r)))
{
judgementPools.Add(result, new DrawablePool<DrawableTaikoJudgement>(15));
explosionPools.Add(result, new HitExplosionPool(result));
}
AddRangeInternal(judgementPools.Values);
AddRangeInternal(explosionPools.Values);
}
protected override void LoadComplete()
@ -281,7 +287,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{
case TaikoStrongJudgement _:
if (result.IsHit)
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit();
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit(result);
break;
case TaikoDrumRollTickJudgement _:
@ -315,7 +321,8 @@ namespace osu.Game.Rulesets.Taiko.UI
private void addExplosion(DrawableHitObject drawableObject, HitResult result, HitType type)
{
hitExplosionContainer.Add(new HitExplosion(drawableObject, result));
hitExplosionContainer.Add(explosionPools[result]
.Get(explosion => explosion.Apply(drawableObject)));
if (drawableObject.HitObject.Kiai)
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
}

View File

@ -121,7 +121,7 @@ namespace osu.Game.Tests.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
{

View File

@ -36,7 +36,7 @@ namespace osu.Game.Tests.Gameplay
public void TestRetrieveTopLevelSample()
{
ISkin skin = null;
Sample channel = null;
ISample channel = null;
AddStep("create skin", () => skin = new TestSkin("test-sample", this));
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample")));
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Gameplay
public void TestRetrieveSampleInSubFolder()
{
ISkin skin = null;
Sample channel = null;
ISample channel = null;
AddStep("create skin", () => skin = new TestSkin("folder/test-sample", this));
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample")));

View File

@ -88,7 +88,7 @@ namespace osu.Game.Tests.Input
=> AddStep($"make window {mode}", () => frameworkConfigManager.GetBindable<WindowMode>(FrameworkSetting.WindowMode).Value = mode);
private void setGameSideModeTo(OsuConfineMouseMode mode)
=> AddStep($"set {mode} game-side", () => Game.LocalConfig.Set(OsuSetting.ConfineMouseMode, mode));
=> AddStep($"set {mode} game-side", () => Game.LocalConfig.SetValue(OsuSetting.ConfineMouseMode, mode));
private void setLocalUserPlayingTo(bool playing)
=> AddStep($"local user {(playing ? "playing" : "not playing")}", () => Game.LocalUserPlaying.Value = playing);

View File

@ -47,7 +47,7 @@ namespace osu.Game.Tests.NonVisual
using (var host = new CustomTestHeadlessGameHost())
{
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
storageConfig.Set(StorageConfig.FullPath, customPath);
storageConfig.SetValue(StorageConfig.FullPath, customPath);
try
{
@ -73,7 +73,7 @@ namespace osu.Game.Tests.NonVisual
using (var host = new CustomTestHeadlessGameHost())
{
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
storageConfig.Set(StorageConfig.FullPath, customPath);
storageConfig.SetValue(StorageConfig.FullPath, customPath);
try
{

View File

@ -59,7 +59,7 @@ namespace osu.Game.Tests.NonVisual.Skinning
}
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
}

View File

@ -23,8 +23,10 @@ namespace osu.Game.Tests.Online
{
case CommentVoteRequest cRequest:
cRequest.TriggerSuccess(new CommentBundle());
break;
return true;
}
return false;
});
CommentVoteRequest request = null;
@ -108,8 +110,10 @@ namespace osu.Game.Tests.Online
{
case LeaveChannelRequest cRequest:
cRequest.TriggerSuccess();
break;
return true;
}
return false;
});
}
}

View File

@ -0,0 +1,2 @@
[General]
Version: 2

View File

@ -113,6 +113,31 @@ namespace osu.Game.Tests.Skins.IO
}
}
[Test]
public async Task TestImportUpperCasedOskArchive()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest)))
{
try
{
var osu = LoadOsuIntoHost(host);
var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1"), "skin1.OsK"));
Assert.That(imported.Name, Is.EqualTo("name 1"));
Assert.That(imported.Creator, Is.EqualTo("author 1"));
var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1"), "skin1.oSK"));
Assert.That(imported2.Hash, Is.EqualTo(imported.Hash));
}
finally
{
host.Exit();
}
}
}
private MemoryStream createOsk(string name, string author)
{
var zipStream = new MemoryStream();

View File

@ -91,6 +91,15 @@ namespace osu.Game.Tests.Skins
Assert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion);
}
[Test]
public void TestStripWhitespace()
{
var decoder = new LegacySkinDecoder();
using (var resStream = TestResources.OpenResource("skin-with-space.ini"))
using (var stream = new LineBufferedReader(resStream))
Assert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion);
}
[Test]
public void TestDecodeLatestVersion()
{

View File

@ -219,7 +219,7 @@ namespace osu.Game.Tests.Skins
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT);
public Sample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
}

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Background
public void SetUp() => Schedule(() =>
{
// reset API response in statics to avoid test crosstalk.
statics.Set<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
statics.SetValue<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
textureStore.PerformedLookups.Clear();
dummyAPI.SetState(APIState.Online);
@ -135,18 +135,20 @@ namespace osu.Game.Tests.Visual.Background
dummyAPI.HandleRequest = request =>
{
if (dummyAPI.State.Value != APIState.Online || !(request is GetSeasonalBackgroundsRequest backgroundsRequest))
return;
return false;
backgroundsRequest.TriggerSuccess(new APISeasonalBackgrounds
{
Backgrounds = seasonal_background_urls.Select(url => new APISeasonalBackground { Url = url }).ToList(),
EndDate = endDate
});
return true;
};
});
private void setSeasonalBackgroundMode(SeasonalBackgroundMode mode)
=> AddStep($"set seasonal mode to {mode}", () => config.Set(OsuSetting.SeasonalBackgroundMode, mode));
=> AddStep($"set seasonal mode to {mode}", () => config.SetValue(OsuSetting.SeasonalBackgroundMode, mode));
private void createLoader()
=> AddStep("create loader", () =>

View File

@ -0,0 +1,70 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Tests.Beatmaps;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editing
{
public class TestSceneBlueprintSelection : EditorTestScene
{
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
private BlueprintContainer blueprintContainer
=> Editor.ChildrenOfType<BlueprintContainer>().First();
[Test]
public void TestSelectedObjectHasPriorityWhenOverlapping()
{
var firstSlider = new Slider
{
Path = new SliderPath(new[]
{
new PathControlPoint(new Vector2()),
new PathControlPoint(new Vector2(150, -50)),
new PathControlPoint(new Vector2(300, 0))
}),
Position = new Vector2(0, 100)
};
var secondSlider = new Slider
{
Path = new SliderPath(new[]
{
new PathControlPoint(new Vector2()),
new PathControlPoint(new Vector2(-50, 50)),
new PathControlPoint(new Vector2(-100, 100))
}),
Position = new Vector2(200, 0)
};
AddStep("add overlapping sliders", () =>
{
EditorBeatmap.Add(firstSlider);
EditorBeatmap.Add(secondSlider);
});
AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.Add(firstSlider));
AddStep("move mouse to common point", () =>
{
var pos = blueprintContainer.ChildrenOfType<PathControlPointPiece>().ElementAt(1).ScreenSpaceDrawQuad.Centre;
InputManager.MoveMouseTo(pos);
});
AddStep("right click", () => InputManager.Click(MouseButton.Right));
AddAssert("selection is unchanged", () => EditorBeatmap.SelectedHitObjects.Single() == firstSlider);
}
}
}

View File

@ -0,0 +1,81 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Edit.Components;
using osuTK;
namespace osu.Game.Tests.Visual.Editing
{
[TestFixture]
public class TestSceneEditorClock : EditorClockTestScene
{
public TestSceneEditorClock()
{
Add(new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new TimeInfoContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 100)
},
new PlaybackControl
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(200, 100)
}
}
});
}
[BackgroundDependencyLoader]
private void load()
{
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
// ensure that music controller does not change this beatmap due to it
// completing naturally as part of the test.
Beatmap.Disabled = true;
}
[Test]
public void TestStopAtTrackEnd()
{
AddStep("reset clock", () => Clock.Seek(0));
AddStep("start clock", Clock.Start);
AddAssert("clock running", () => Clock.IsRunning);
AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250));
AddUntilStep("clock stops", () => !Clock.IsRunning);
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
AddStep("start clock again", Clock.Start);
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
}
[Test]
public void TestWrapWhenStoppedAtTrackEnd()
{
AddStep("reset clock", () => Clock.Seek(0));
AddStep("stop clock", Clock.Stop);
AddAssert("clock stopped", () => !Clock.IsRunning);
AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength));
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
AddStep("start clock again", Clock.Start);
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
}
}
}

View File

@ -110,8 +110,6 @@ namespace osu.Game.Tests.Visual.Editing
[Resolved]
private EditorClock editorClock { get; set; }
private bool started;
public StartStopButton()
{
BackgroundColour = Color4.SlateGray;
@ -123,18 +121,17 @@ namespace osu.Game.Tests.Visual.Editing
private void onClick()
{
if (started)
{
if (editorClock.IsRunning)
editorClock.Stop();
Text = "Start";
}
else
{
editorClock.Start();
Text = "Stop";
}
}
started = !started;
protected override void Update()
{
base.Update();
Text = editorClock.IsRunning ? "Stop" : "Start";
}
}
}

View File

@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay
});
AddStep("show health", () => showHealth.Value = true);
AddStep("enable layer", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddStep("enable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddUntilStep("layer is visible", () => layer.IsPresent);
}
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[Test]
public void TestLayerDisabledViaConfig()
{
AddStep("disable layer", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddStep("disable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
AddUntilStep("layer is not visible", () => !layer.IsPresent);
}
@ -81,19 +81,19 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
AddStep("don't show health", () => showHealth.Value = false);
AddStep("disable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddStep("disable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddUntilStep("layer fade is invisible", () => !layer.IsPresent);
AddStep("don't show health", () => showHealth.Value = false);
AddStep("enable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddUntilStep("layer fade is invisible", () => !layer.IsPresent);
AddStep("show health", () => showHealth.Value = true);
AddStep("disable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddStep("disable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
AddUntilStep("layer fade is invisible", () => !layer.IsPresent);
AddStep("show health", () => showHealth.Value = true);
AddStep("enable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
AddUntilStep("layer fade is visible", () => layer.IsPresent);
}
}

View File

@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
AddStep("set hud to never show", () => config.Set(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft));
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
AddStep("set original config value", () => config.Set(OsuSetting.HUDVisibilityMode, originalConfigValue));
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
}
[Test]
@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("set keycounter visible false", () =>
{
config.Set<bool>(OsuSetting.KeyOverlay, false);
config.SetValue(OsuSetting.KeyOverlay, false);
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
});
@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
AddStep("return value", () => config.Set<bool>(OsuSetting.KeyOverlay, keyCounterVisibleValue));
AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
}
private void createNew(Action<HUDOverlay> action = null)

View File

@ -298,7 +298,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
}
@ -309,7 +309,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
}
@ -321,7 +321,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();

View File

@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public Drawable GetDrawableComponent(ISkinComponent component) => source?.GetDrawableComponent(component);
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT);
public Sample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo);
public ISample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo);
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => source?.GetConfig<TLookup, TValue>(lookup);
public void TriggerSourceChanged()

View File

@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
config.Set(OsuSetting.ShowStoryboard, true);
config.SetValue(OsuSetting.ShowStoryboard, true);
storyboard = new Storyboard();
var backgroundLayer = storyboard.GetLayer("Background");

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
@ -62,10 +61,6 @@ namespace osu.Game.Tests.Visual.Navigation
RecycleLocalStorage();
// see MouseSettings
var frameworkConfig = host.Dependencies.Get<FrameworkConfigManager>();
frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity).Disabled = false;
CreateGame();
});
@ -82,7 +77,7 @@ namespace osu.Game.Tests.Visual.Navigation
// todo: this can be removed once we can run audio tracks without a device present
// see https://github.com/ppy/osu/issues/1302
Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
Game.LocalConfig.SetValue(OsuSetting.IntroSequence, IntroSequence.Circles);
Add(Game);
}
@ -136,7 +131,7 @@ namespace osu.Game.Tests.Visual.Navigation
base.LoadComplete();
API.Login("Rhythm Champion", "osu!");
Dependencies.Get<SessionStatics>().Set(Static.MutedAudioNotificationShownOnce, true);
Dependencies.Get<SessionStatics>().SetValue(Static.MutedAudioNotificationShownOnce, true);
}
}

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Navigation
public void TestPerformAtSongSelectFromPlayerLoader()
{
PushAndConfirm(() => new PlaySongSelect());
PushAndConfirm(() => new PlayerLoader(() => new Player()));
PushAndConfirm(() => new PlayerLoader(() => new SoloPlayer()));
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) }));
AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Navigation
public void TestPerformAtMenuFromPlayerLoader()
{
PushAndConfirm(() => new PlaySongSelect());
PushAndConfirm(() => new PlayerLoader(() => new Player()));
PushAndConfirm(() => new PlayerLoader(() => new SoloPlayer()));
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is MainMenu);

View File

@ -229,6 +229,35 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("settings displayed", () => Game.Settings.State.Value == Visibility.Visible);
}
[Test]
public void TestToolbarHiddenByUser()
{
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
AddStep("Hide toolbar", () =>
{
InputManager.PressKey(Key.ControlLeft);
InputManager.Key(Key.T);
InputManager.ReleaseKey(Key.ControlLeft);
});
pushEscape();
AddStep("Enter menu", () => InputManager.Key(Key.Enter));
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
AddStep("Enter song select", () =>
{
InputManager.Key(Key.Enter);
InputManager.Key(Key.Enter);
});
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
}
private void pushEscape() =>
AddStep("Press escape", () => InputManager.Key(Key.Escape));

View File

@ -15,8 +15,8 @@ namespace osu.Game.Tests.Visual.Navigation
using (var config = new OsuConfigManager(LocalStorage))
{
config.Set(OsuSetting.Version, "2020.101.0");
config.Set(OsuSetting.DisplayStarsMaximum, 10.0);
config.SetValue(OsuSetting.Version, "2020.101.0");
config.SetValue(OsuSetting.DisplayStarsMaximum, 10.0);
}
}
@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
AddAssert("config has migrated value", () => Precision.AlmostEquals(Game.LocalConfig.Get<double>(OsuSetting.DisplayStarsMaximum), 10.1));
AddStep("set value again", () => Game.LocalConfig.Set<double>(OsuSetting.DisplayStarsMaximum, 10));
AddStep("set value again", () => Game.LocalConfig.SetValue(OsuSetting.DisplayStarsMaximum, 10.0));
AddStep("force save config", () => Game.LocalConfig.Save());

View File

@ -30,13 +30,14 @@ namespace osu.Game.Tests.Visual.Online
((DummyAPIAccess)API).HandleRequest = req =>
{
if (req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)
if (!(req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)) return false;
searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse
{
searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse
{
BeatmapSets = setsForResponse,
});
}
BeatmapSets = setsForResponse,
});
return true;
};
}

View File

@ -63,13 +63,15 @@ namespace osu.Game.Tests.Visual.Online
Builds = builds.Values.ToList()
};
changelogRequest.TriggerSuccess(changelogResponse);
break;
return true;
case GetChangelogBuildRequest buildRequest:
if (requestedBuild != null)
buildRequest.TriggerSuccess(requestedBuild);
break;
return true;
}
return false;
};
Child = changelog = new TestChangelogOverlay();

View File

@ -11,6 +11,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Chat;
using osu.Game.Overlays;
using osu.Game.Overlays.Chat.Selection;
@ -64,6 +66,24 @@ namespace osu.Game.Tests.Visual.Online
});
}
[SetUpSteps]
public void SetUpSteps()
{
AddStep("register request handling", () =>
{
((DummyAPIAccess)API).HandleRequest = req =>
{
switch (req)
{
case JoinChannelRequest _:
return true;
}
return false;
};
});
}
[Test]
public void TestHideOverlay()
{

View File

@ -85,9 +85,10 @@ namespace osu.Game.Tests.Visual.Online
dummyAPI.HandleRequest = request =>
{
if (!(request is GetCommentsRequest getCommentsRequest))
return;
return false;
getCommentsRequest.TriggerSuccess(commentBundle);
return true;
};
});

View File

@ -33,9 +33,10 @@ namespace osu.Game.Tests.Visual.Online
dummyAPI.HandleRequest = request =>
{
if (!(request is GetNewsRequest getNewsRequest))
return;
return false;
getNewsRequest.TriggerSuccess(r);
return true;
};
});

View File

@ -170,6 +170,17 @@ namespace osu.Game.Tests.Visual.Playlists
private void bindHandler(bool delayed = false, ScoreInfo userScore = null, bool failRequests = false) => ((DummyAPIAccess)API).HandleRequest = request =>
{
// pre-check for requests we should be handling (as they are scheduled below).
switch (request)
{
case ShowPlaylistUserScoreRequest _:
case IndexPlaylistScoresRequest _:
break;
default:
return false;
}
requestComplete = false;
double delay = delayed ? 3000 : 0;
@ -196,6 +207,8 @@ namespace osu.Game.Tests.Visual.Playlists
break;
}
}, delay);
return true;
};
private void triggerSuccess<T>(APIRequest<T> req, T result)

View File

@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Ranking
}));
AddAssert("mapped by text not present", () =>
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Current.Value, "mapped", "by")));
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by")));
}
private void showPanel(ScoreInfo score) => Child = new ExpandedPanelMiddleContentContainer(score);

View File

@ -0,0 +1,73 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Platform;
using osu.Framework.Utils;
using osu.Game.Overlays;
using osu.Game.Overlays.Settings.Sections.Input;
using osuTK;
namespace osu.Game.Tests.Visual.Settings
{
[TestFixture]
public class TestSceneTabletSettings : OsuTestScene
{
[BackgroundDependencyLoader]
private void load(GameHost host)
{
var tabletHandler = new TestTabletHandler();
AddRange(new Drawable[]
{
new TabletSettings(tabletHandler)
{
RelativeSizeAxes = Axes.None,
Width = SettingsPanel.WIDTH,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
}
});
AddStep("Test with wide tablet", () => tabletHandler.SetTabletSize(new Vector2(160, 100)));
AddStep("Test with square tablet", () => tabletHandler.SetTabletSize(new Vector2(300, 300)));
AddStep("Test with tall tablet", () => tabletHandler.SetTabletSize(new Vector2(100, 300)));
AddStep("Test with very tall tablet", () => tabletHandler.SetTabletSize(new Vector2(100, 700)));
AddStep("Test no tablet present", () => tabletHandler.SetTabletSize(Vector2.Zero));
}
public class TestTabletHandler : ITabletHandler
{
public Bindable<Vector2> AreaOffset { get; } = new Bindable<Vector2>();
public Bindable<Vector2> AreaSize { get; } = new Bindable<Vector2>();
public IBindable<TabletInfo> Tablet => tablet;
private readonly Bindable<TabletInfo> tablet = new Bindable<TabletInfo>();
public BindableBool Enabled { get; } = new BindableBool(true);
public void SetTabletSize(Vector2 size)
{
tablet.Value = size != Vector2.Zero ? new TabletInfo($"test tablet T-{RNG.Next(999):000}", size) : null;
AreaSize.Default = new Vector2(size.X, size.Y);
// if it's clear the user has not configured the area, take the full area from the tablet that was just found.
if (AreaSize.Value == Vector2.Zero)
AreaSize.SetDefault();
AreaOffset.Default = new Vector2(size.X / 2, size.Y / 2);
// likewise with the position, use the centre point if it has not been configured.
// it's safe to assume no user would set their centre point to 0,0 for now.
if (AreaOffset.Value == Vector2.Zero)
AreaOffset.SetDefault();
}
}
}
}

View File

@ -32,8 +32,10 @@ namespace osu.Game.Tests.Visual.SongSelect
{
case GetUserRequest userRequest:
userRequest.TriggerSuccess(getUser(userRequest.Ruleset.ID));
break;
return true;
}
return false;
};
});

View File

@ -207,14 +207,14 @@ namespace osu.Game.Tests.Visual.SongSelect
addRulesetImportStep(0);
addRulesetImportStep(0);
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, false));
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
createSongSelect();
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
AddStep("return", () => songSelect.MakeCurrent());
AddUntilStep("wait for current", () => songSelect.IsCurrentScreen());
@ -297,13 +297,13 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
AddStep(@"Sort by Artist", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Artist));
AddStep(@"Sort by Title", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Title));
AddStep(@"Sort by Author", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Author));
AddStep(@"Sort by DateAdded", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.DateAdded));
AddStep(@"Sort by BPM", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.BPM));
AddStep(@"Sort by Length", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Length));
AddStep(@"Sort by Difficulty", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Difficulty));
AddStep(@"Sort by Artist", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Artist));
AddStep(@"Sort by Title", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Title));
AddStep(@"Sort by Author", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Author));
AddStep(@"Sort by DateAdded", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.DateAdded));
AddStep(@"Sort by BPM", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.BPM));
AddStep(@"Sort by Length", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Length));
AddStep(@"Sort by Difficulty", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Difficulty));
}
[Test]
@ -470,7 +470,7 @@ namespace osu.Game.Tests.Visual.SongSelect
changeRuleset(0);
// used for filter check below
AddStep("allow convert display", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
AddStep("allow convert display", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
@ -648,7 +648,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
int changeCount = 0;
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, false));
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
AddStep("bind beatmap changed", () =>
{
Beatmap.ValueChanged += onChange;
@ -686,7 +686,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("selection changed only fired twice", () => changeCount == 2);
AddStep("unbind beatmap changed", () => Beatmap.ValueChanged -= onChange);
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
// ReSharper disable once AccessToModifiedClosure
void onChange(ValueChangedEvent<WorkingBeatmap> valueChangedEvent) => changeCount++;

View File

@ -92,10 +92,10 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestExplicitConfig()
{
AddStep("configure explicit content to allowed", () => localConfig.Set(OsuSetting.ShowOnlineExplicitContent, true));
AddStep("configure explicit content to allowed", () => localConfig.SetValue(OsuSetting.ShowOnlineExplicitContent, true));
AddAssert("explicit control set to show", () => control.ExplicitContent.Value == SearchExplicit.Show);
AddStep("configure explicit content to disallowed", () => localConfig.Set(OsuSetting.ShowOnlineExplicitContent, false));
AddStep("configure explicit content to disallowed", () => localConfig.SetValue(OsuSetting.ShowOnlineExplicitContent, false));
AddAssert("explicit control set to hide", () => control.ExplicitContent.Value == SearchExplicit.Hide);
}

View File

@ -44,22 +44,22 @@ namespace osu.Game.Tests.Visual.UserInterface
protected override void InitialiseDefaults()
{
Set(TestConfigSetting.ToggleSettingNoKeybind, false);
Set(TestConfigSetting.EnumSettingNoKeybind, EnumSetting.Setting1);
Set(TestConfigSetting.ToggleSettingWithKeybind, false);
Set(TestConfigSetting.EnumSettingWithKeybind, EnumSetting.Setting1);
SetDefault(TestConfigSetting.ToggleSettingNoKeybind, false);
SetDefault(TestConfigSetting.EnumSettingNoKeybind, EnumSetting.Setting1);
SetDefault(TestConfigSetting.ToggleSettingWithKeybind, false);
SetDefault(TestConfigSetting.EnumSettingWithKeybind, EnumSetting.Setting1);
base.InitialiseDefaults();
}
public void ToggleSetting(TestConfigSetting setting) => Set(setting, !Get<bool>(setting));
public void ToggleSetting(TestConfigSetting setting) => SetValue(setting, !Get<bool>(setting));
public void IncrementEnumSetting(TestConfigSetting setting)
{
var nextValue = Get<EnumSetting>(setting) + 1;
if (nextValue > EnumSetting.Setting4)
nextValue = EnumSetting.Setting1;
Set(setting, nextValue);
SetValue(setting, nextValue);
}
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings

View File

@ -50,7 +50,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
storage.DeleteDirectory(string.Empty);
using (var storageConfig = new TournamentStorageManager(storage))
storageConfig.Set(StorageConfig.CurrentTournament, custom_tournament);
storageConfig.SetValue(StorageConfig.CurrentTournament, custom_tournament);
try
{

View File

@ -70,7 +70,7 @@ namespace osu.Game.Tournament.IO
moveFileIfExists("drawings.ini", destination);
ChangeTargetStorage(newStorage);
storageConfig.Set(StorageConfig.CurrentTournament, default_tournament);
storageConfig.SetValue(StorageConfig.CurrentTournament, default_tournament);
storageConfig.Save();
}

View File

@ -12,8 +12,8 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
protected override void InitialiseDefaults()
{
Set(DrawingsConfig.Groups, 8, 1, 8);
Set(DrawingsConfig.TeamsPerGroup, 8, 1, 8);
SetDefault(DrawingsConfig.Groups, 8, 1, 8);
SetDefault(DrawingsConfig.TeamsPerGroup, 8, 1, 8);
}
public DrawingsConfigManager(Storage storage)

View File

@ -2,18 +2,21 @@
// See the LICENCE file in the repository root for full licence text.
using System.Drawing;
using osu.Framework.Extensions.Color4Extensions;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Colour;
using osu.Game.Graphics.Cursor;
using osu.Game.Tournament.Models;
using osu.Framework.Input.Handlers.Mouse;
using osu.Framework.Platform;
using osu.Game.Graphics;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.Models;
using osuTK;
using osuTK.Graphics;
@ -36,7 +39,7 @@ namespace osu.Game.Tournament
private LoadingSpinner loadingSpinner;
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager frameworkConfig)
private void load(FrameworkConfigManager frameworkConfig, GameHost host)
{
windowSize = frameworkConfig.GetBindable<Size>(FrameworkSetting.WindowedSize);
windowMode = frameworkConfig.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
@ -48,6 +51,13 @@ namespace osu.Game.Tournament
Margin = new MarginPadding(40),
});
// in order to have the OS mouse cursor visible, relative mode needs to be disabled.
// can potentially be removed when https://github.com/ppy/osu-framework/issues/4309 is resolved.
var mouseHandler = host.AvailableInputHandlers.OfType<MouseHandler>().FirstOrDefault();
if (mouseHandler != null)
mouseHandler.UseRelativeMode.Value = false;
loadingSpinner.Show();
BracketLoadTask.ContinueWith(_ => LoadComponentsAsync(new[]

View File

@ -17,12 +17,12 @@ namespace osu.Game.Beatmaps
public abstract class BeatmapConverter<T> : IBeatmapConverter
where T : HitObject
{
private event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
private event Action<HitObject, IEnumerable<HitObject>> objectConverted;
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
{
add => ObjectConverted += value;
remove => ObjectConverted -= value;
add => objectConverted += value;
remove => objectConverted -= value;
}
public IBeatmap Beatmap { get; }
@ -92,10 +92,10 @@ namespace osu.Game.Beatmaps
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
if (ObjectConverted != null)
if (objectConverted != null)
{
converted = converted.ToList();
ObjectConverted.Invoke(obj, converted);
objectConverted.Invoke(obj, converted);
}
foreach (var c in converted)

View File

@ -113,8 +113,6 @@ namespace osu.Game.Beatmaps
{
var metadata = new BeatmapMetadata
{
Artist = "artist",
Title = "title",
Author = user,
};
@ -128,7 +126,6 @@ namespace osu.Game.Beatmaps
BaseDifficulty = new BeatmapDifficulty(),
Ruleset = ruleset,
Metadata = metadata,
Version = "difficulty"
}
}
};

Some files were not shown because too many files have changed in this diff Show More