mirror of
https://github.com/osukey/osukey.git
synced 2025-05-17 03:27:21 +09:00
Merge branch 'master' into extended-statistics-without-replay
This commit is contained in:
commit
df9d99f5aa
@ -51,7 +51,7 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.202.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.128.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.128.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 1.5f,
|
MaxValue = 1.5f,
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
public override Type[] IncompatibleMods => new[] { typeof(ModHidden) };
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 3f,
|
MaxValue = 3f,
|
||||||
|
27
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAimAssist.cs
Normal file
27
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAimAssist.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// 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.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
|
{
|
||||||
|
public class TestSceneOsuModAimAssist : OsuModTestScene
|
||||||
|
{
|
||||||
|
[TestCase(0.1f)]
|
||||||
|
[TestCase(0.5f)]
|
||||||
|
[TestCase(1)]
|
||||||
|
public void TestAimAssist(float strength)
|
||||||
|
{
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAimAssist
|
||||||
|
{
|
||||||
|
AssistStrength = { Value = strength },
|
||||||
|
},
|
||||||
|
PassCondition = () => true,
|
||||||
|
Autoplay = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
Normal file
154
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
|
{
|
||||||
|
public class TestSceneOsuModAlternate : OsuModTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestInputAtIntro() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 1,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(200), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(200)),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInputAlternating() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 4,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Position = new Vector2(200, 100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1500,
|
||||||
|
Position = new Vector2(300, 100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 2000,
|
||||||
|
Position = new Vector2(400, 100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(100)),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(200, 100), OsuAction.RightButton),
|
||||||
|
new OsuReplayFrame(1001, new Vector2(200, 100)),
|
||||||
|
new OsuReplayFrame(1500, new Vector2(300, 100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(1501, new Vector2(300, 100)),
|
||||||
|
new OsuReplayFrame(2000, new Vector2(400, 100), OsuAction.RightButton),
|
||||||
|
new OsuReplayFrame(2001, new Vector2(400, 100)),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInputSingular() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 1,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 1000,
|
||||||
|
Position = new Vector2(200, 100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(100)),
|
||||||
|
new OsuReplayFrame(1000, new Vector2(200, 100), OsuAction.LeftButton),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInputSingularWithBreak() => CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mod = new OsuModAlternate(),
|
||||||
|
PassCondition = () => Player.ScoreProcessor.Combo.Value == 2,
|
||||||
|
Autoplay = false,
|
||||||
|
Beatmap = new Beatmap
|
||||||
|
{
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(500, 2250),
|
||||||
|
},
|
||||||
|
HitObjects = new List<HitObject>
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 2500,
|
||||||
|
Position = new Vector2(100),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ReplayFrames = new List<ReplayFrame>
|
||||||
|
{
|
||||||
|
new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(501, new Vector2(100)),
|
||||||
|
new OsuReplayFrame(2500, new Vector2(100), OsuAction.LeftButton),
|
||||||
|
new OsuReplayFrame(2501, new Vector2(100)),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
83
osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs
Normal file
83
osu.Game.Rulesets.Osu/Mods/OsuModAimAssist.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
|
{
|
||||||
|
internal class OsuModAimAssist : Mod, IUpdatableByPlayfield, IApplicableToDrawableRuleset<OsuHitObject>
|
||||||
|
{
|
||||||
|
public override string Name => "Aim Assist";
|
||||||
|
public override string Acronym => "AA";
|
||||||
|
public override IconUsage? Icon => FontAwesome.Solid.MousePointer;
|
||||||
|
public override ModType Type => ModType.Fun;
|
||||||
|
public override string Description => "No need to chase the circle – the circle chases you!";
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay) };
|
||||||
|
|
||||||
|
private IFrameStableClock gameplayClock;
|
||||||
|
|
||||||
|
[SettingSource("Assist strength", "How much this mod will assist you.", 0)]
|
||||||
|
public BindableFloat AssistStrength { get; } = new BindableFloat(0.5f)
|
||||||
|
{
|
||||||
|
Precision = 0.05f,
|
||||||
|
MinValue = 0.05f,
|
||||||
|
MaxValue = 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
|
{
|
||||||
|
gameplayClock = drawableRuleset.FrameStableClock;
|
||||||
|
|
||||||
|
// Hide judgment displays and follow points as they won't make any sense.
|
||||||
|
// Judgements can potentially be turned on in a future where they display at a position relative to their drawable counterpart.
|
||||||
|
drawableRuleset.Playfield.DisplayJudgements.Value = false;
|
||||||
|
(drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(Playfield playfield)
|
||||||
|
{
|
||||||
|
var cursorPos = playfield.Cursor.ActiveCursor.DrawPosition;
|
||||||
|
|
||||||
|
foreach (var drawable in playfield.HitObjectContainer.AliveObjects)
|
||||||
|
{
|
||||||
|
switch (drawable)
|
||||||
|
{
|
||||||
|
case DrawableHitCircle circle:
|
||||||
|
easeTo(circle, cursorPos);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DrawableSlider slider:
|
||||||
|
|
||||||
|
if (!slider.HeadCircle.Result.HasResult)
|
||||||
|
easeTo(slider, cursorPos);
|
||||||
|
else
|
||||||
|
easeTo(slider, cursorPos - slider.Ball.DrawPosition);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void easeTo(DrawableHitObject hitObject, Vector2 destination)
|
||||||
|
{
|
||||||
|
double dampLength = Interpolation.Lerp(3000, 40, AssistStrength.Value);
|
||||||
|
|
||||||
|
float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime);
|
||||||
|
float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime);
|
||||||
|
|
||||||
|
hitObject.Position = new Vector2(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs
Normal file
106
osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
|
{
|
||||||
|
public class OsuModAlternate : Mod, IApplicableToDrawableRuleset<OsuHitObject>, IApplicableToPlayer
|
||||||
|
{
|
||||||
|
public override string Name => @"Alternate";
|
||||||
|
public override string Acronym => @"AL";
|
||||||
|
public override string Description => @"Don't use the same key twice in a row!";
|
||||||
|
public override double ScoreMultiplier => 1.0;
|
||||||
|
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay) };
|
||||||
|
public override ModType Type => ModType.Conversion;
|
||||||
|
public override IconUsage? Icon => FontAwesome.Solid.Keyboard;
|
||||||
|
|
||||||
|
private double firstObjectValidJudgementTime;
|
||||||
|
private IBindable<bool> isBreakTime;
|
||||||
|
private const double flash_duration = 1000;
|
||||||
|
private OsuAction? lastActionPressed;
|
||||||
|
private DrawableRuleset<OsuHitObject> ruleset;
|
||||||
|
|
||||||
|
private IFrameStableClock gameplayClock;
|
||||||
|
|
||||||
|
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
|
||||||
|
{
|
||||||
|
ruleset = drawableRuleset;
|
||||||
|
drawableRuleset.KeyBindingInputManager.Add(new InputInterceptor(this));
|
||||||
|
|
||||||
|
var firstHitObject = ruleset.Objects.FirstOrDefault();
|
||||||
|
firstObjectValidJudgementTime = (firstHitObject?.StartTime ?? 0) - (firstHitObject?.HitWindows.WindowFor(HitResult.Meh) ?? 0);
|
||||||
|
|
||||||
|
gameplayClock = drawableRuleset.FrameStableClock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyToPlayer(Player player)
|
||||||
|
{
|
||||||
|
isBreakTime = player.IsBreakTime.GetBoundCopy();
|
||||||
|
isBreakTime.ValueChanged += e =>
|
||||||
|
{
|
||||||
|
if (e.NewValue)
|
||||||
|
lastActionPressed = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkCorrectAction(OsuAction action)
|
||||||
|
{
|
||||||
|
if (isBreakTime.Value)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (gameplayClock.CurrentTime < firstObjectValidJudgementTime)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case OsuAction.LeftButton:
|
||||||
|
case OsuAction.RightButton:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Any action which is not left or right button should be ignored.
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastActionPressed != action)
|
||||||
|
{
|
||||||
|
// User alternated correctly.
|
||||||
|
lastActionPressed = action;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleset.Cursor.FlashColour(Colour4.Red, flash_duration, Easing.OutQuint);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InputInterceptor : Component, IKeyBindingHandler<OsuAction>
|
||||||
|
{
|
||||||
|
private readonly OsuModAlternate mod;
|
||||||
|
|
||||||
|
public InputInterceptor(OsuModAlternate mod)
|
||||||
|
{
|
||||||
|
this.mod = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
|
||||||
|
// if the pressed action is incorrect, block it from reaching gameplay.
|
||||||
|
=> !mod.checkCorrectAction(e.Action);
|
||||||
|
|
||||||
|
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override ModType Type => ModType.Automation;
|
public override ModType Type => ModType.Automation;
|
||||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModAimAssist) };
|
||||||
|
|
||||||
public bool PerformFail() => false;
|
public bool PerformFail() => false;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModAutoplay : ModAutoplay
|
public class OsuModAutoplay : ModAutoplay
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAimAssist), typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
|
||||||
|
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
{
|
{
|
||||||
public class OsuModCinema : ModCinema<OsuHitObject>
|
public class OsuModCinema : ModCinema<OsuHitObject>
|
||||||
{
|
{
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).Append(typeof(OsuModSpunOut)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAimAssist), typeof(OsuModAutopilot), typeof(OsuModSpunOut) }).ToArray();
|
||||||
|
|
||||||
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
public override Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList<Mod> mods) => new Score
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
};
|
};
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 2f,
|
MaxValue = 2f,
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override ModType Type => ModType.Fun;
|
public override ModType Type => ModType.Fun;
|
||||||
public override string Description => "Everything rotates. EVERYTHING.";
|
public override string Description => "Everything rotates. EVERYTHING.";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle), typeof(OsuModAimAssist) };
|
||||||
|
|
||||||
private float theta;
|
private float theta;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override ModType Type => ModType.Fun;
|
public override ModType Type => ModType.Fun;
|
||||||
public override string Description => "They just won't stay still...";
|
public override string Description => "They just won't stay still...";
|
||||||
public override double ScoreMultiplier => 1;
|
public override double ScoreMultiplier => 1;
|
||||||
public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform) };
|
public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModAimAssist) };
|
||||||
|
|
||||||
private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles
|
private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles
|
||||||
private const int wiggle_strength = 10; // Higher = stronger wiggles
|
private const int wiggle_strength = 10; // Higher = stronger wiggles
|
||||||
|
@ -169,6 +169,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new OsuModClassic(),
|
new OsuModClassic(),
|
||||||
new OsuModRandom(),
|
new OsuModRandom(),
|
||||||
new OsuModMirror(),
|
new OsuModMirror(),
|
||||||
|
new OsuModAlternate(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.Automation:
|
case ModType.Automation:
|
||||||
@ -193,6 +194,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
new OsuModApproachDifferent(),
|
new OsuModApproachDifferent(),
|
||||||
new OsuModMuted(),
|
new OsuModMuted(),
|
||||||
new OsuModNoScope(),
|
new OsuModNoScope(),
|
||||||
|
new OsuModAimAssist(),
|
||||||
};
|
};
|
||||||
|
|
||||||
case ModType.System:
|
case ModType.System:
|
||||||
|
@ -31,7 +31,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
private readonly ProxyContainer approachCircles;
|
private readonly ProxyContainer approachCircles;
|
||||||
private readonly ProxyContainer spinnerProxies;
|
private readonly ProxyContainer spinnerProxies;
|
||||||
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
private readonly JudgementContainer<DrawableOsuJudgement> judgementLayer;
|
||||||
private readonly FollowPointRenderer followPoints;
|
|
||||||
|
public FollowPointRenderer FollowPoints { get; }
|
||||||
|
|
||||||
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
public static readonly Vector2 BASE_SIZE = new Vector2(512, 384);
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
{
|
{
|
||||||
playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both },
|
playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both },
|
||||||
spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both },
|
spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both },
|
||||||
followPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both },
|
FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both },
|
||||||
judgementLayer = new JudgementContainer<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
|
judgementLayer = new JudgementContainer<DrawableOsuJudgement> { RelativeSizeAxes = Axes.Both },
|
||||||
HitObjectContainer,
|
HitObjectContainer,
|
||||||
judgementAboveHitObjectLayer = new Container { RelativeSizeAxes = Axes.Both },
|
judgementAboveHitObjectLayer = new Container { RelativeSizeAxes = Axes.Both },
|
||||||
@ -131,13 +132,13 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
protected override void OnHitObjectAdded(HitObject hitObject)
|
protected override void OnHitObjectAdded(HitObject hitObject)
|
||||||
{
|
{
|
||||||
base.OnHitObjectAdded(hitObject);
|
base.OnHitObjectAdded(hitObject);
|
||||||
followPoints.AddFollowPoints((OsuHitObject)hitObject);
|
FollowPoints.AddFollowPoints((OsuHitObject)hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHitObjectRemoved(HitObject hitObject)
|
protected override void OnHitObjectRemoved(HitObject hitObject)
|
||||||
{
|
{
|
||||||
base.OnHitObjectRemoved(hitObject);
|
base.OnHitObjectRemoved(hitObject);
|
||||||
followPoints.RemoveFollowPoints((OsuHitObject)hitObject);
|
FollowPoints.RemoveFollowPoints((OsuHitObject)hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
private void onNewResult(DrawableHitObject judgedObject, JudgementResult result)
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public override double ScoreMultiplier => 1.12;
|
public override double ScoreMultiplier => 1.12;
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public override BindableNumber<float> SizeMultiplier { get; } = new BindableNumber<float>
|
public override BindableFloat SizeMultiplier { get; } = new BindableFloat
|
||||||
{
|
{
|
||||||
MinValue = 0.5f,
|
MinValue = 0.5f,
|
||||||
MaxValue = 1.5f,
|
MaxValue = 1.5f,
|
||||||
|
@ -15,8 +15,12 @@ using osu.Game.Online.Multiplayer;
|
|||||||
using osu.Game.Online.Rooms;
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Rulesets.Taiko.Mods;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Multiplayer.Participants;
|
||||||
using osu.Game.Tests.Beatmaps;
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osu.Game.Tests.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
@ -77,6 +81,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("wait for join", () => RoomJoined);
|
AddUntilStep("wait for join", () => RoomJoined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestTaikoOnlyMod()
|
||||||
|
{
|
||||||
|
AddStep("add playlist item", () =>
|
||||||
|
{
|
||||||
|
SelectedRoom.Value.Playlist.Add(new PlaylistItem
|
||||||
|
{
|
||||||
|
Beatmap = { Value = new TestBeatmap(new TaikoRuleset().RulesetInfo).BeatmapInfo },
|
||||||
|
Ruleset = { Value = new TaikoRuleset().RulesetInfo },
|
||||||
|
AllowedMods = { new TaikoModSwap() }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
ClickButtonWhenEnabled<MultiplayerMatchSettingsOverlay.CreateOrUpdateButton>();
|
||||||
|
|
||||||
|
AddUntilStep("wait for join", () => RoomJoined);
|
||||||
|
|
||||||
|
AddStep("select swap mod", () => Client.ChangeUserMods(API.LocalUser.Value.OnlineID, new[] { new TaikoModSwap() }));
|
||||||
|
AddUntilStep("participant panel has mod", () => this.ChildrenOfType<ParticipantPanel>().Any(p => p.ChildrenOfType<ModIcon>().Any(m => m.Mod is TaikoModSwap)));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSettingValidity()
|
public void TestSettingValidity()
|
||||||
{
|
{
|
||||||
|
@ -128,6 +128,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
AddStep("choose clear all scores", () => InputManager.Key(Key.Number4));
|
AddStep("choose clear all scores", () => InputManager.Key(Key.Number4));
|
||||||
|
|
||||||
|
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
||||||
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
||||||
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
||||||
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
||||||
@ -172,6 +173,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for dialog display", () => Game.Dependencies.Get<DialogOverlay>().IsLoaded);
|
||||||
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
AddUntilStep("wait for dialog", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog != null);
|
||||||
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
AddStep("confirm deletion", () => InputManager.Key(Key.Number1));
|
||||||
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
AddUntilStep("wait for dialog dismissed", () => Game.Dependencies.Get<DialogOverlay>().CurrentDialog == null);
|
||||||
|
@ -601,7 +601,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
BeatmapSetInfo testMixed = null;
|
BeatmapSetInfo testMixed = null;
|
||||||
|
|
||||||
createCarousel();
|
createCarousel(new List<BeatmapSetInfo>());
|
||||||
|
|
||||||
AddStep("add mixed ruleset beatmapset", () =>
|
AddStep("add mixed ruleset beatmapset", () =>
|
||||||
{
|
{
|
||||||
@ -765,22 +765,22 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
createCarousel(c =>
|
if (beatmapSets == null)
|
||||||
|
{
|
||||||
|
beatmapSets = new List<BeatmapSetInfo>();
|
||||||
|
|
||||||
|
for (int i = 1; i <= (count ?? set_count); i++)
|
||||||
|
{
|
||||||
|
beatmapSets.Add(randomDifficulties
|
||||||
|
? TestResources.CreateTestBeatmapSetInfo()
|
||||||
|
: TestResources.CreateTestBeatmapSetInfo(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createCarousel(beatmapSets, c =>
|
||||||
{
|
{
|
||||||
carouselAdjust?.Invoke(c);
|
carouselAdjust?.Invoke(c);
|
||||||
|
|
||||||
if (beatmapSets == null)
|
|
||||||
{
|
|
||||||
beatmapSets = new List<BeatmapSetInfo>();
|
|
||||||
|
|
||||||
for (int i = 1; i <= (count ?? set_count); i++)
|
|
||||||
{
|
|
||||||
beatmapSets.Add(randomDifficulties
|
|
||||||
? TestResources.CreateTestBeatmapSetInfo()
|
|
||||||
: TestResources.CreateTestBeatmapSetInfo(3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
carousel.Filter(initialCriteria?.Invoke() ?? new FilterCriteria());
|
carousel.Filter(initialCriteria?.Invoke() ?? new FilterCriteria());
|
||||||
carousel.BeatmapSetsChanged = () => changed = true;
|
carousel.BeatmapSetsChanged = () => changed = true;
|
||||||
carousel.BeatmapSets = beatmapSets;
|
carousel.BeatmapSets = beatmapSets;
|
||||||
@ -789,7 +789,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddUntilStep("Wait for load", () => changed);
|
AddUntilStep("Wait for load", () => changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createCarousel(Action<BeatmapCarousel> carouselAdjust = null, Container target = null)
|
private void createCarousel(List<BeatmapSetInfo> beatmapSets, Action<BeatmapCarousel> carouselAdjust = null, Container target = null)
|
||||||
{
|
{
|
||||||
AddStep("Create carousel", () =>
|
AddStep("Create carousel", () =>
|
||||||
{
|
{
|
||||||
@ -803,6 +803,8 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
|
|
||||||
carouselAdjust?.Invoke(carousel);
|
carouselAdjust?.Invoke(carousel);
|
||||||
|
|
||||||
|
carousel.BeatmapSets = beatmapSets;
|
||||||
|
|
||||||
(target ?? this).Child = carousel;
|
(target ?? this).Child = carousel;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,24 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[]
|
||||||
|
{
|
||||||
|
new OsuModHidden(),
|
||||||
|
new OsuModHardRock(),
|
||||||
|
new OsuModFlashlight
|
||||||
|
{
|
||||||
|
FollowDelay = { Value = 200 },
|
||||||
|
SizeMultiplier = { Value = 5 },
|
||||||
|
},
|
||||||
|
new OsuModDifficultyAdjust
|
||||||
|
{
|
||||||
|
CircleSize = { Value = 11 },
|
||||||
|
ApproachRate = { Value = 10 },
|
||||||
|
OverallDifficulty = { Value = 10 },
|
||||||
|
DrainRate = { Value = 10 },
|
||||||
|
ExtendedLimits = { Value = true }
|
||||||
|
}
|
||||||
|
},
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
User = new APIUser
|
User = new APIUser
|
||||||
@ -217,7 +234,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
User = new APIUser
|
User = new APIUser
|
||||||
@ -237,7 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -258,7 +275,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -279,7 +296,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 1,
|
Accuracy = 1,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -300,7 +317,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.9826,
|
Accuracy = 0.9826,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -321,7 +338,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.9654,
|
Accuracy = 0.9654,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -342,7 +359,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.6025,
|
Accuracy = 0.6025,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -363,7 +380,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.5140,
|
Accuracy = 0.5140,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
@ -384,7 +401,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
Accuracy = 0.4222,
|
Accuracy = 0.4222,
|
||||||
MaxCombo = 244,
|
MaxCombo = 244,
|
||||||
TotalScore = 1707827,
|
TotalScore = 1707827,
|
||||||
//Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||||
BeatmapInfo = beatmapInfo,
|
BeatmapInfo = beatmapInfo,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
{
|
{
|
||||||
background = new Box
|
background = new Box
|
||||||
{
|
{
|
||||||
|
Alpha = 0.9f,
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
|
@ -10,6 +10,8 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using System;
|
using System;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
@ -30,13 +32,17 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
private DragRotationState dragRotationState;
|
private DragRotationState dragRotationState;
|
||||||
private Vector2 positionMouseDown;
|
private Vector2 positionMouseDown;
|
||||||
|
|
||||||
|
private Sample tapSample;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager)
|
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager, AudioManager audio)
|
||||||
{
|
{
|
||||||
cursorRotate = config.GetBindable<bool>(OsuSetting.CursorRotation);
|
cursorRotate = config.GetBindable<bool>(OsuSetting.CursorRotation);
|
||||||
|
|
||||||
if (screenshotManager != null)
|
if (screenshotManager != null)
|
||||||
screenshotCursorVisibility.BindTo(screenshotManager.CursorVisibility);
|
screenshotCursorVisibility.BindTo(screenshotManager.CursorVisibility);
|
||||||
|
|
||||||
|
tapSample = audio.Samples.Get(@"UI/cursor-tap");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
@ -87,6 +93,8 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
dragRotationState = DragRotationState.DragStarted;
|
dragRotationState = DragRotationState.DragStarted;
|
||||||
positionMouseDown = e.MousePosition;
|
positionMouseDown = e.MousePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playTapSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseDown(e);
|
return base.OnMouseDown(e);
|
||||||
@ -104,6 +112,9 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf);
|
activeCursor.RotateTo(0, 600 * (1 + Math.Abs(activeCursor.Rotation / 720)), Easing.OutElasticHalf);
|
||||||
dragRotationState = DragRotationState.NotDragging;
|
dragRotationState = DragRotationState.NotDragging;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (State.Value == Visibility.Visible)
|
||||||
|
playTapSample(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnMouseUp(e);
|
base.OnMouseUp(e);
|
||||||
@ -121,6 +132,18 @@ namespace osu.Game.Graphics.Cursor
|
|||||||
activeCursor.ScaleTo(0.6f, 250, Easing.In);
|
activeCursor.ScaleTo(0.6f, 250, Easing.In);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void playTapSample(double baseFrequency = 1f)
|
||||||
|
{
|
||||||
|
const float random_range = 0.02f;
|
||||||
|
SampleChannel channel = tapSample.GetChannel();
|
||||||
|
|
||||||
|
// Scale to [-0.75, 0.75] so that the sample isn't fully panned left or right (sounds weird)
|
||||||
|
channel.Balance.Value = ((activeCursor.X / DrawWidth) * 2 - 1) * 0.75;
|
||||||
|
channel.Frequency.Value = baseFrequency - (random_range / 2f) + RNG.NextDouble(random_range);
|
||||||
|
|
||||||
|
channel.Play();
|
||||||
|
}
|
||||||
|
|
||||||
public class Cursor : Container
|
public class Cursor : Container
|
||||||
{
|
{
|
||||||
private Container cursorContainer;
|
private Container cursorContainer;
|
||||||
|
@ -399,7 +399,10 @@ namespace osu.Game.Online.API
|
|||||||
lock (queue)
|
lock (queue)
|
||||||
{
|
{
|
||||||
if (state.Value == APIState.Offline)
|
if (state.Value == APIState.Offline)
|
||||||
|
{
|
||||||
|
request.Fail(new WebException(@"User not logged in"));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
queue.Enqueue(request);
|
queue.Enqueue(request);
|
||||||
}
|
}
|
||||||
@ -416,7 +419,7 @@ namespace osu.Game.Online.API
|
|||||||
if (failOldRequests)
|
if (failOldRequests)
|
||||||
{
|
{
|
||||||
foreach (var req in oldQueueRequests)
|
foreach (var req in oldQueueRequests)
|
||||||
req.Fail(new WebException(@"Disconnected from server"));
|
req.Fail(new WebException($@"Request failed from flush operation (state {state.Value})"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ using osu.Game.Utils;
|
|||||||
|
|
||||||
namespace osu.Game.Online.Leaderboards
|
namespace osu.Game.Online.Leaderboards
|
||||||
{
|
{
|
||||||
public class LeaderboardScore : OsuClickableContainer, IHasContextMenu
|
public class LeaderboardScore : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip<ScoreInfo>
|
||||||
{
|
{
|
||||||
public const float HEIGHT = 60;
|
public const float HEIGHT = 60;
|
||||||
|
|
||||||
@ -70,6 +70,9 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private Storage storage { get; set; }
|
private Storage storage { get; set; }
|
||||||
|
|
||||||
|
public ITooltip<ScoreInfo> GetCustomTooltip() => new LeaderboardScoreTooltip();
|
||||||
|
public virtual ScoreInfo TooltipContent => Score;
|
||||||
|
|
||||||
public LeaderboardScore(ScoreInfo score, int? rank, bool isOnlineScope = true)
|
public LeaderboardScore(ScoreInfo score, int? rank, bool isOnlineScope = true)
|
||||||
{
|
{
|
||||||
Score = score;
|
Score = score;
|
||||||
@ -183,7 +186,6 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Spacing = new Vector2(10f, 0f),
|
|
||||||
Margin = new MarginPadding { Left = edge_margin },
|
Margin = new MarginPadding { Left = edge_margin },
|
||||||
Children = statisticsLabels
|
Children = statisticsLabels
|
||||||
},
|
},
|
||||||
@ -228,7 +230,6 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
Origin = Anchor.BottomRight,
|
Origin = Anchor.BottomRight,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Spacing = new Vector2(1),
|
|
||||||
ChildrenEnumerable = Score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) })
|
ChildrenEnumerable = Score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -313,6 +314,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
|
Padding = new MarginPadding { Right = 10 },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
|
219
osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs
Normal file
219
osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
// 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.Shapes;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osuTK;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace osu.Game.Online.Leaderboards
|
||||||
|
{
|
||||||
|
public class LeaderboardScoreTooltip : VisibilityContainer, ITooltip<ScoreInfo>
|
||||||
|
{
|
||||||
|
private OsuSpriteText timestampLabel = null!;
|
||||||
|
private FillFlowContainer<HitResultCell> topScoreStatistics = null!;
|
||||||
|
private FillFlowContainer<HitResultCell> bottomScoreStatistics = null!;
|
||||||
|
private FillFlowContainer<ModCell> modStatistics = null!;
|
||||||
|
|
||||||
|
public LeaderboardScoreTooltip()
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
AutoSizeDuration = 200;
|
||||||
|
AutoSizeEasing = Easing.OutQuint;
|
||||||
|
|
||||||
|
Masking = true;
|
||||||
|
CornerRadius = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0.9f,
|
||||||
|
Colour = colours.Gray3,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(5),
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
// Info row
|
||||||
|
timestampLabel = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
},
|
||||||
|
// Mods row
|
||||||
|
modStatistics = new FillFlowContainer<ModCell>
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(5, 0),
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
// Actual stats rows
|
||||||
|
topScoreStatistics = new FillFlowContainer<HitResultCell>
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
},
|
||||||
|
bottomScoreStatistics = new FillFlowContainer<HitResultCell>
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScoreInfo? displayedScore;
|
||||||
|
|
||||||
|
public void SetContent(ScoreInfo score)
|
||||||
|
{
|
||||||
|
if (displayedScore?.Equals(score) == true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
displayedScore = score;
|
||||||
|
|
||||||
|
timestampLabel.Text = $"Played on {score.Date.ToLocalTime():d MMMM yyyy HH:mm}";
|
||||||
|
|
||||||
|
modStatistics.Clear();
|
||||||
|
topScoreStatistics.Clear();
|
||||||
|
bottomScoreStatistics.Clear();
|
||||||
|
|
||||||
|
foreach (var mod in score.Mods)
|
||||||
|
{
|
||||||
|
modStatistics.Add(new ModCell(mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var result in score.GetStatisticsForDisplay())
|
||||||
|
{
|
||||||
|
if (result.Result > HitResult.Perfect)
|
||||||
|
bottomScoreStatistics.Add(new HitResultCell(result));
|
||||||
|
else
|
||||||
|
topScoreStatistics.Add(new HitResultCell(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn() => this.FadeIn(20, Easing.OutQuint);
|
||||||
|
protected override void PopOut() => this.FadeOut(80, Easing.OutQuint);
|
||||||
|
|
||||||
|
public void Move(Vector2 pos) => Position = pos;
|
||||||
|
|
||||||
|
private class HitResultCell : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly string displayName;
|
||||||
|
private readonly HitResult result;
|
||||||
|
private readonly int count;
|
||||||
|
|
||||||
|
public HitResultCell(HitResultDisplayStatistic stat)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
displayName = stat.DisplayName;
|
||||||
|
result = stat.Result;
|
||||||
|
count = stat.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Height = 12,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(5f, 0f),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
Text = displayName.ToUpperInvariant(),
|
||||||
|
Colour = colours.ForHitResult(result),
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
Text = count.ToString(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ModCell : CompositeDrawable
|
||||||
|
{
|
||||||
|
private readonly Mod mod;
|
||||||
|
|
||||||
|
public ModCell(Mod mod)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
this.mod = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
FillFlowContainer container;
|
||||||
|
InternalChild = container = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Height = 15,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(2f, 0f),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new ModIcon(mod, showTooltip: false).With(icon =>
|
||||||
|
{
|
||||||
|
icon.Origin = Anchor.CentreLeft;
|
||||||
|
icon.Anchor = Anchor.CentreLeft;
|
||||||
|
icon.Scale = new Vector2(15f / icon.Height);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
string description = mod.SettingDescription;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(description))
|
||||||
|
{
|
||||||
|
container.Add(new OsuSpriteText
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
|
||||||
|
Text = mod.SettingDescription,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Margin = new MarginPadding { Top = 1 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -105,6 +105,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
ShowsDefaultIndicator = false,
|
ShowsDefaultIndicator = false,
|
||||||
Current = currentNumber,
|
Current = currentNumber,
|
||||||
|
KeyboardStep = 0.1f,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override string Description => "Restricted view area.";
|
public override string Description => "Restricted view area.";
|
||||||
|
|
||||||
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
[SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")]
|
||||||
public abstract BindableNumber<float> SizeMultiplier { get; }
|
public abstract BindableFloat SizeMultiplier { get; }
|
||||||
|
|
||||||
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
[SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")]
|
||||||
public abstract BindableBool ComboBasedSize { get; }
|
public abstract BindableBool ComboBasedSize { get; }
|
||||||
|
@ -149,6 +149,10 @@ namespace osu.Game.Rulesets
|
|||||||
var instanceInfo = (Activator.CreateInstance(resolvedType) as Ruleset)?.RulesetInfo
|
var instanceInfo = (Activator.CreateInstance(resolvedType) as Ruleset)?.RulesetInfo
|
||||||
?? throw new RulesetLoadException(@"Instantiation failure");
|
?? throw new RulesetLoadException(@"Instantiation failure");
|
||||||
|
|
||||||
|
// If a ruleset isn't up-to-date with the API, it could cause a crash at an arbitrary point of execution.
|
||||||
|
// To eagerly handle cases of missing implementations, enumerate all types here and mark as non-available on throw.
|
||||||
|
resolvedType.Assembly.GetTypes();
|
||||||
|
|
||||||
r.Name = instanceInfo.Name;
|
r.Name = instanceInfo.Name;
|
||||||
r.ShortName = instanceInfo.ShortName;
|
r.ShortName = instanceInfo.ShortName;
|
||||||
r.InstantiationInfo = instanceInfo.InstantiationInfo;
|
r.InstantiationInfo = instanceInfo.InstantiationInfo;
|
||||||
|
@ -14,6 +14,8 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
|
|||||||
{
|
{
|
||||||
private readonly APIUserScoreAggregate score;
|
private readonly APIUserScoreAggregate score;
|
||||||
|
|
||||||
|
public override ScoreInfo TooltipContent => null; // match aggregate scores can't show statistics that the custom tooltip displays.
|
||||||
|
|
||||||
public MatchLeaderboardScore(APIUserScoreAggregate score, int? rank, bool isOnlineScope = true)
|
public MatchLeaderboardScore(APIUserScoreAggregate score, int? rank, bool isOnlineScope = true)
|
||||||
: base(score.CreateScoreInfo(), rank, isOnlineScope)
|
: base(score.CreateScoreInfo(), rank, isOnlineScope)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
@ -18,6 +19,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
|
using osu.Game.Online.Rooms;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -184,8 +186,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
|
|||||||
|
|
||||||
const double fade_time = 50;
|
const double fade_time = 50;
|
||||||
|
|
||||||
// Todo: Should use the room's selected item to determine ruleset.
|
var currentItem = Playlist.GetCurrentItem();
|
||||||
var ruleset = rulesets.GetRuleset(0)?.CreateInstance();
|
Debug.Assert(currentItem != null);
|
||||||
|
|
||||||
|
var ruleset = rulesets.GetRuleset(currentItem.RulesetID)?.CreateInstance();
|
||||||
|
|
||||||
int? currentModeRank = ruleset != null ? User.User?.RulesetsStatistics?.GetValueOrDefault(ruleset.ShortName)?.GlobalRank : null;
|
int? currentModeRank = ruleset != null ? User.User?.RulesetsStatistics?.GetValueOrDefault(ruleset.ShortName)?.GlobalRank : null;
|
||||||
userRankText.Text = currentModeRank != null ? $"#{currentModeRank.Value:N0}" : string.Empty;
|
userRankText.Text = currentModeRank != null ? $"#{currentModeRank.Value:N0}" : string.Empty;
|
||||||
|
@ -17,6 +17,7 @@ using osu.Game.Input.Bindings;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -83,10 +84,7 @@ namespace osu.Game.Screens.Play
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
CreateFailingLayer(),
|
CreateFailingLayer(),
|
||||||
mainComponents = new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents)
|
mainComponents = new MainComponentsContainer(),
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
topRightElements = new FillFlowContainer
|
topRightElements = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
@ -325,5 +323,29 @@ namespace osu.Game.Screens.Play
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MainComponentsContainer : SkinnableTargetContainer
|
||||||
|
{
|
||||||
|
private Bindable<ScoringMode> scoringMode;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
|
public MainComponentsContainer()
|
||||||
|
: base(SkinnableTarget.MainHUDComponents)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
// When the scoring mode changes, relative positions of elements may change (see DefaultSkin.GetDrawableComponent).
|
||||||
|
// This is a best effort implementation for cases where users haven't customised layouts.
|
||||||
|
scoringMode = config.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode);
|
||||||
|
scoringMode.BindValueChanged(val => Reload());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Replays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
@ -50,18 +54,37 @@ namespace osu.Game.Tests.Visual
|
|||||||
return CreateModPlayer(ruleset);
|
return CreateModPlayer(ruleset);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual TestPlayer CreateModPlayer(Ruleset ruleset) => new ModTestPlayer(AllowFail);
|
protected virtual TestPlayer CreateModPlayer(Ruleset ruleset) => new ModTestPlayer(currentTestData, AllowFail);
|
||||||
|
|
||||||
protected class ModTestPlayer : TestPlayer
|
protected class ModTestPlayer : TestPlayer
|
||||||
{
|
{
|
||||||
private readonly bool allowFail;
|
private readonly bool allowFail;
|
||||||
|
private readonly ModTestData currentTestData;
|
||||||
|
|
||||||
protected override bool CheckModsAllowFailure() => allowFail;
|
protected override bool CheckModsAllowFailure() => allowFail;
|
||||||
|
|
||||||
public ModTestPlayer(bool allowFail)
|
public ModTestPlayer(ModTestData data, bool allowFail)
|
||||||
: base(false, false)
|
: base(false, false)
|
||||||
{
|
{
|
||||||
this.allowFail = allowFail;
|
this.allowFail = allowFail;
|
||||||
|
currentTestData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PrepareReplay()
|
||||||
|
{
|
||||||
|
if (currentTestData.Autoplay && currentTestData.ReplayFrames?.Count > 0)
|
||||||
|
throw new InvalidOperationException(@$"{nameof(ModTestData.Autoplay)} must be false when {nameof(ModTestData.ReplayFrames)} is specified.");
|
||||||
|
|
||||||
|
if (currentTestData.ReplayFrames != null)
|
||||||
|
{
|
||||||
|
DrawableRuleset?.SetReplayScore(new Score
|
||||||
|
{
|
||||||
|
Replay = new Replay { Frames = currentTestData.ReplayFrames },
|
||||||
|
ScoreInfo = new ScoreInfo { User = new APIUser { Username = @"Test" } },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
base.PrepareReplay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +95,12 @@ namespace osu.Game.Tests.Visual
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Autoplay = true;
|
public bool Autoplay = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The frames to use for replay. <see cref="Autoplay"/> must be set to false.
|
||||||
|
/// </summary>
|
||||||
|
[CanBeNull]
|
||||||
|
public List<ReplayFrame> ReplayFrames;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The beatmap for this test case.
|
/// The beatmap for this test case.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.8.0" />
|
<PackageReference Include="Realm" Version="10.8.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.128.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.128.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.202.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.13.0" />
|
<PackageReference Include="Sentry" Version="3.13.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.128.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.128.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.115.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.202.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user