[渐进]逐步回退、备份测试

This commit is contained in:
LA
2025-12-06 17:18:07 +08:00
parent 5ee8fcc4dd
commit 7eed0ac007
42 changed files with 554 additions and 250 deletions

View File

@@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2025.1121.1" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2025.1205.1" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.

View File

@@ -4,8 +4,8 @@
<OutputType>WinExe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>A free-to-win rhythm game. Rhythm is just a *click* away!</Description>
<AssemblyName>osu!</AssemblyName>
<AssemblyTitle>osu!(lazer)</AssemblyTitle>
<AssemblyName>Ez2osu!</AssemblyName>
<AssemblyTitle>osu!(Ez2lazer)</AssemblyTitle>
<Title>Ez2lazer!</Title>
<Product>osu!(Ez2lazer)</Product>
<ApplicationIcon>lazer.ico</ApplicationIcon>

View File

@@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private double placementStartTime;
private double placementEndTime;
protected override bool IsValidForPlacement => Precision.DefinitelyBigger(HitObject.Duration, 0);
protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(HitObject.Duration, 0));
public BananaShowerPlacementBlueprint()
{

View File

@@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
private InputManager inputManager = null!;
protected override bool IsValidForPlacement => Precision.DefinitelyBigger(HitObject.Duration, 0);
protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(HitObject.Duration, 0));
public JuiceStreamPlacementBlueprint()
{

View File

@@ -5,6 +5,7 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Testing;
using osu.Game.Rulesets.Edit;
@@ -16,6 +17,7 @@ using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Screens.Edit;
using osu.Game.Tests.Visual;
using osuTK.Input;
@@ -36,21 +38,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
[Test]
public void TestPlaceBeforeCurrentTimeDownwards()
{
AddStep("seek to 200", () => HitObjectContainer.Dependencies.Get<EditorClock>().Seek(200));
AddStep("move mouse before current time", () =>
{
var column = this.ChildrenOfType<Column>().Single();
InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(-100));
});
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddAssert("note start time < 0", () => getNote().StartTime < 0);
}
[Test]
public void TestPlaceAfterCurrentTimeDownwards()
{
AddStep("move mouse after current time", () =>
{
var column = this.ChildrenOfType<Column>().Single();
InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(100));
@@ -58,7 +47,22 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddAssert("note start time > 0", () => getNote().StartTime > 0);
AddAssert("note start time < 200", () => getNote().StartTime < 200);
}
[Test]
public void TestPlaceAfterCurrentTimeDownwards()
{
AddStep("seek to 200", () => HitObjectContainer.Dependencies.Get<EditorClock>().Seek(200));
AddStep("move mouse after current time", () =>
{
var column = this.ChildrenOfType<Column>().Single();
InputManager.MoveMouseTo(column.ScreenSpacePositionAtTime(300));
});
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddAssert("note start time > 200", () => getNote().StartTime > 200);
}
private Note getNote() => this.ChildrenOfType<DrawableNote>().FirstOrDefault()?.HitObject;

View File

@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
[Resolved]
private IScrollingInfo scrollingInfo { get; set; } = null!;
protected override bool IsValidForPlacement => Precision.DefinitelyBigger(HitObject.Duration, 0);
protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(HitObject.Duration, 0));
public HoldNotePlacementBlueprint()
: base(new HoldNote())

View File

@@ -56,7 +56,8 @@ namespace osu.Game.Rulesets.Mania.Edit
};
public override string ConvertSelectionToString()
=> string.Join(',', EditorBeatmap.SelectedHitObjects.Cast<ManiaHitObject>().OrderBy(h => h.StartTime).Select(h => $"{h.StartTime}|{h.Column}"));
=> string.Join(',', EditorBeatmap.SelectedHitObjects.Cast<ManiaHitObject>().OrderBy(h => h.StartTime)
.Select(h => FormattableString.Invariant($"{Math.Round(h.StartTime)}|{h.Column}")));
// 123|0,456|1,789|2 ...
private static readonly Regex selection_regex = new Regex(@"^\d+\|\d+(,\d+\|\d+)*$", RegexOptions.Compiled);
@@ -75,10 +76,10 @@ namespace osu.Game.Rulesets.Mania.Edit
if (split.Length != 2)
continue;
if (!double.TryParse(split[0], out double time) || !int.TryParse(split[1], out int column))
if (!int.TryParse(split[0], out int time) || !int.TryParse(split[1], out int column))
continue;
ManiaHitObject? current = remainingHitObjects.FirstOrDefault(h => h.StartTime == time && h.Column == column);
ManiaHitObject? current = remainingHitObjects.FirstOrDefault(h => Precision.AlmostEquals(h.StartTime, time, 0.5) && h.Column == column);
if (current == null)
continue;

View File

@@ -67,30 +67,32 @@ namespace osu.Game.Rulesets.Mania
public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new ManiaHealthProcessor(drainStartTime);
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap)
{
var hitMode = GlobalConfigStore.Config?.Get<EzMUGHitMode>(OsuSetting.HitMode) ?? EzMUGHitMode.Lazer;
ManiaBeatmapConverter.CurrentHitMode = hitMode;
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
if (hitMode == EzMUGHitMode.O2Jam)
{
double bpm = beatmap.BeatmapInfo.BPM;
if (bpm == 0) bpm = 200;
O2HitModeExtension.NowBeatmapBPM = bpm;
double coolRange = 7500.0 / bpm;
double goodRange = 22500.0 / bpm;
double badRange = 31250.0 / bpm;
var hw = new ManiaHitWindows();
hw.SetSpecialDifficultyRange(coolRange, coolRange, goodRange, goodRange, badRange, badRange);
}
// else
// {
// var hw = new ManiaHitWindows();
// hw.ResetRange();
// }
return new ManiaBeatmapConverter(beatmap, this);
}
// public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap)
// {
// var hitMode = GlobalConfigStore.Config?.Get<EzMUGHitMode>(OsuSetting.HitMode) ?? EzMUGHitMode.Lazer;
// ManiaBeatmapConverter.CurrentHitMode = hitMode;
//
// if (hitMode == EzMUGHitMode.O2Jam)
// {
// double bpm = beatmap.BeatmapInfo.BPM;
// if (bpm == 0) bpm = 200;
// O2HitModeExtension.NowBeatmapBPM = bpm;
// double coolRange = 7500.0 / bpm;
// double goodRange = 22500.0 / bpm;
// double badRange = 31250.0 / bpm;
// var hw = new ManiaHitWindows();
// hw.SetSpecialDifficultyRange(coolRange, coolRange, goodRange, goodRange, badRange, badRange);
// }
// else
// {
// var hw = new ManiaHitWindows();
// hw.ResetRange();
// }
//
// return new ManiaBeatmapConverter(beatmap, this);
// }
public override PerformanceCalculator CreatePerformanceCalculator() => new ManiaPerformanceCalculator();
@@ -356,33 +358,33 @@ namespace osu.Game.Rulesets.Mania
return new Mod[]
{
new ManiaModAdjust(),
new ManiaModChangeSpeedByAccuracy(),
// new ManiaModCleaner(),
new ManiaModDeleteSpace(),
new ManiaModDoublePlay(),
new ManiaModDuplicate(),
new ManiaModGracer(),
new ManiaModJackAdjust(),
new ManiaModJudgmentsAdjust(),
new ManiaModJudgmentsProportion(),
new ManiaModLN(),
new ManiaModLNDoubleDistribution(),
new ManiaModLNJudgementAdjust(),
new ManiaModLNLongShortAddition(),
new ManiaModLNSimplify(),
new ManiaModLNTransformer(),
new ManiaModMalodyStyleLN(),
new ManiaModNewJudgement(),
new ManiaModNoteAdjust(),
new ManiaModNtoM(),
new ManiaModNtoMAnother(),
new ManiaModO2Health(),
new ManiaModO2Judgement(),
// new ManiaModPlayfieldTransformation(), //加载有问题
new ManiaModReleaseAdjust(),
new ManiaModRemedy(),
new StarRatingRebirth(),
new StarRatingRebirthNoTask(),
// new ManiaModChangeSpeedByAccuracy(),
// // new ManiaModCleaner(),
// new ManiaModDeleteSpace(),
// new ManiaModDoublePlay(),
// new ManiaModDuplicate(),
// new ManiaModGracer(),
// new ManiaModJackAdjust(),
// new ManiaModJudgmentsAdjust(),
// new ManiaModJudgmentsProportion(),
// new ManiaModLN(),
// new ManiaModLNDoubleDistribution(),
// new ManiaModLNJudgementAdjust(),
// new ManiaModLNLongShortAddition(),
// new ManiaModLNSimplify(),
// new ManiaModLNTransformer(),
// new ManiaModMalodyStyleLN(),
// // new ManiaModNewJudgement(),
// new ManiaModNoteAdjust(),
// new ManiaModNtoM(),
// new ManiaModNtoMAnother(),
// new ManiaModO2Health(),
// new ManiaModO2Judgement(),
// // new ManiaModPlayfieldTransformation(), //加载有问题
// new ManiaModReleaseAdjust(),
// new ManiaModRemedy(),
// new StarRatingRebirth(),
// new StarRatingRebirthNoTask(),
};
case ModType.Fun:
@@ -472,6 +474,8 @@ namespace osu.Game.Rulesets.Mania
HitResult.Good,
HitResult.Ok,
HitResult.Meh,
HitResult.IgnoreHit,
HitResult.IgnoreMiss,
// HitResult.SmallBonus is used for awarding perfect bonus score but is not included here as
// it would be a bit redundant to show this to the user.

View File

@@ -4,18 +4,13 @@
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public partial class Ez2AcDrawableLNTail : DrawableHoldNoteTail
{
// public override bool DisplayResult => false;
// public override bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
// {
// return UpdateResult(true);
// }
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (HoldNote.IsHolding.Value && timeOffset >= 0)

View File

@@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
NodeSamples = hold.NodeSamples;
}
protected override HitWindows CreateHitWindows() => new EzCustomHitWindows();
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
AddNested(Head = new Ez2AcLNHead
@@ -55,14 +57,26 @@ namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
public class Ez2AcLNHead : HeadNote
{
// public override Judgement CreateJudgement() => new Ez2AcJudgement();
public override Judgement CreateJudgement() => new Ez2AcHeadJudgement();
protected override HitWindows CreateHitWindows() => new EzCustomHitWindows();
private class Ez2AcHeadJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.Perfect;
public override HitResult MinResult => HitResult.IgnoreMiss;
}
}
public class Ez2AcLNTail : TailNote
{
// public override Judgement CreateJudgement() => new Ez2AcJudgement();
public override Judgement CreateJudgement() => new Ez2AcTailJudgement();
protected override HitWindows CreateHitWindows() => new EzCustomHitWindows();
private class Ez2AcTailJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.Perfect;
public override HitResult MinResult => HitResult.ComboBreak;
}
}
public class Ez2AcNote : Note
@@ -74,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
Samples = note.Samples;
}
// public override Judgement CreateJudgement() => new Ez2AcJudgement();
public override Judgement CreateJudgement() => new Ez2AcJudgement();
protected override HitWindows CreateHitWindows() => new EzCustomHitWindows();
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
@@ -82,8 +96,11 @@ namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
}
}
public class Ez2AcJudgement : Judgement
public class Ez2AcJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.Perfect;
public override HitResult MinResult => HitResult.Pool;
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)

View File

@@ -126,6 +126,8 @@ namespace osu.Game.Rulesets.Mania.Scoring
case HitResult.Meh:
// case HitResult.Pool:
case HitResult.Miss:
case HitResult.IgnoreHit:
case HitResult.IgnoreMiss:
return true;
}

View File

@@ -13,7 +13,7 @@ using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens;
using osuTK;
using EzLocalTextureFactory = osu.Game.LAsEzExtensions.EzLocalTextureFactory;
using osu.Game.LAsEzExtensions;
namespace osu.Game.Rulesets.Mania.Skinning.EzStylePro
{

View File

@@ -17,7 +17,7 @@ using osu.Game.Rulesets.Mania.UI;
using osu.Game.Screens;
using osu.Game.Screens.Play;
using osuTK;
using EzLocalTextureFactory = osu.Game.LAsEzExtensions.EzLocalTextureFactory;
using osu.Game.LAsEzExtensions;
namespace osu.Game.Rulesets.Mania.Skinning.EzStylePro
{

View File

@@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Screens;
using osuTK;
using EzLocalTextureFactory = osu.Game.LAsEzExtensions.EzLocalTextureFactory;
using osu.Game.LAsEzExtensions;
namespace osu.Game.Rulesets.Mania.Skinning.EzStylePro
{

View File

@@ -11,7 +11,7 @@ using osu.Game.Rulesets.Mania.UI;
using osu.Game.Screens;
using osu.Game.Skinning;
using osuTK;
using EzLocalTextureFactory = osu.Game.LAsEzExtensions.EzLocalTextureFactory;
using osu.Game.LAsEzExtensions;
namespace osu.Game.Rulesets.Mania.Skinning.EzStylePro
{

View File

@@ -10,7 +10,6 @@ using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Framework.Platform;
@@ -164,13 +163,13 @@ namespace osu.Game.Rulesets.Mania.UI
base.LoadComplete();
// Configure pools based on hit mode
foreach (var stage in Playfield.Stages)
{
foreach (var column in stage.Columns)
{
configurePools(column, ManiaBeatmapConverter.CurrentHitMode);
}
}
// foreach (var stage in Playfield.Stages)
// {
// foreach (var column in stage.Columns)
// {
// configurePools(column, ManiaBeatmapConverter.CurrentHitMode);
// }
// }
// 启动独立的异步任务预加载EzPro皮肤中会用到的贴图
Schedule(() =>
@@ -306,26 +305,12 @@ namespace osu.Game.Rulesets.Mania.UI
currentSkin.SourceChanged -= onSkinChange;
}
public bool SupportsBackgroundBlurMasking => true;
public RectangleF? GetPlayfieldBounds()
{
try
{
return Playfield.ScreenSpaceDrawQuad.AABBFloat;
}
catch
{
return null;
}
}
private void configurePools(Column column, EzMUGHitMode hitMode)
{
switch (hitMode)
{
case EzMUGHitMode.EZ2AC:
// column.RegisterPool<Ez2AcNote, DrawableNote>(10, 50);
column.RegisterPool<Ez2AcNote, DrawableNote>(10, 50);
column.RegisterPool<Ez2AcLNHead, DrawableHoldNoteHead>(10, 50);
column.RegisterPool<NoMissLNBody, DrawableHoldNoteBody>(10, 50);
column.RegisterPool<Ez2AcLNTail, Ez2AcDrawableLNTail>(10, 50);

View File

@@ -10,7 +10,6 @@ using System.Collections.Generic;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Logging;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects;

View File

@@ -90,23 +90,6 @@ namespace osu.Game.Rulesets.Mania.UI
InternalChildren = new Drawable[]
{
// TODO: 需要修改framework着色器-容器实现真正效果。动态根据实际的游戏中BackgroundScreen背景或故事版绘制局部虚化效果
// // 注意,如果是真正的毛玻璃效果,此处就不应该在此处试图获取外部的背景内容,因为存在循环依赖问题。
// acrylicEffect = new FrostedGlassContainer
// {
// Name = "Acrylic backdrop effect",
// Anchor = Anchor.Centre,
// Origin = Anchor.Centre,
// RelativeSizeAxes = Axes.Both, //使用Both即可实现局部遮罩因为此处父容器就是局部面板
// BlurRotation = 50f,
// Depth = 1, // 在背景层
// Child = new Box
// {
// RelativeSizeAxes = Axes.Both,
// Colour = Colour4.Red,
// Alpha = 0.01f,
// }
// },
dimBox = new Box //通过叠加覆盖实现暗化效果
{
RelativeSizeAxes = Axes.Both,
@@ -207,19 +190,12 @@ namespace osu.Game.Rulesets.Mania.UI
onSkinChanged();
columnDim = ezSkinSettings.GetBindable<double>(EzSkinSetting.ColumnDim);
// columnBlur = ezSkinSettings.GetBindable<double>(EzSkinSetting.ColumnBlur);
// 应用暗化效果
columnDim.BindValueChanged(v =>
{
dimBox.Alpha = (float)v.NewValue;
}, true);
// // 应用虚化效果
// columnBlur.BindValueChanged(v =>
// {
// acrylicEffect.BlurRotation = (float)v.NewValue;
// }, true);
}
private void onSkinChanged()

View File

@@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.UI;
@@ -22,7 +23,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
[TestFixture]
public partial class TestSceneSliderDrawing : TestSceneOsuEditor
{
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new TestBeatmap(ruleset, false);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint());
return beatmap;
}
[Test]
public void TestTouchInputPlaceHitCircleDirectly()

View File

@@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private readonly IncrementalBSplineBuilder bSplineBuilder = new IncrementalBSplineBuilder { Degree = 4 };
protected override bool IsValidForPlacement => HitObject.Path.HasValidLengthForPlacement;
protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || HitObject.Path.HasValidLengthForPlacement);
public SliderPlacementBlueprint()
: base(new Slider())

View File

@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
[Resolved]
private TaikoHitObjectComposer? composer { get; set; }
protected override bool IsValidForPlacement => Precision.DefinitelyBigger(spanPlacementObject.Duration, 0);
protected override bool IsValidForPlacement => base.IsValidForPlacement && (PlacementActive == PlacementState.Waiting || Precision.DefinitelyBigger(spanPlacementObject.Duration, 0));
public TaikoSpanPlacementBlueprint(HitObject hitObject)
: base(hitObject)

View File

@@ -134,7 +134,7 @@ namespace osu.Game.Tests.Visual.Editing
double lastStarRating = 0;
double lastLength = 0;
AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 600 }));
AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 600 }));
AddStep("Change to placement mode", () => InputManager.Key(Key.Number2));
AddStep("Move to playfield", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre));
AddStep("Place single hitcircle", () => InputManager.Click(MouseButton.Left));

View File

@@ -7,6 +7,7 @@ using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets;
@@ -27,7 +28,12 @@ namespace osu.Game.Tests.Visual.Editing
{
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new TestBeatmap(ruleset, false);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint());
return beatmap;
}
private GlobalActionContainer globalActionContainer => this.ChildrenOfType<GlobalActionContainer>().Single();

View File

@@ -10,6 +10,7 @@ using NUnit.Framework;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
@@ -27,7 +28,12 @@ namespace osu.Game.Tests.Visual.Editing
{
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new TestBeatmap(ruleset, false);
beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 });
return beatmap;
}
private TimelineBlueprintContainer blueprintContainer
=> Editor.ChildrenOfType<TimelineBlueprintContainer>().First();
@@ -80,7 +86,7 @@ namespace osu.Game.Tests.Visual.Editing
{
InputManager.Key(Key.Number1);
blueprint = this.ChildrenOfType<TimelineHitObjectBlueprint>().First();
InputManager.MoveMouseTo(blueprint);
InputManager.MoveMouseTo(blueprint, new Vector2(-1, 0));
InputManager.Click(MouseButton.Left);
});

View File

@@ -235,6 +235,22 @@ namespace osu.Game.Tests.Visual.Matchmaking
});
}
[Test]
public void TestRollAnimationFinalRandom()
{
AddStep("play animation", () =>
{
(long[] candidateItems, _) = pickRandomItems(5);
candidateItems = candidateItems.Append(-1).ToArray();
long finalItem = items.First(i => !candidateItems.Contains(i.ID)).ID;
grid.RollAndDisplayFinalBeatmap(candidateItems, -1, finalItem);
});
AddWaitStep("wait for animation", 10);
}
private (long[] candidateItems, long finalItem) pickRandomItems(int count)
{
long[] candidateItems = items.Select(it => it.ID).ToArray();

View File

@@ -1,9 +1,11 @@
// 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.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Osu;
@@ -33,6 +35,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
Children = new Drawable[]
{
new MultiplayerSkipOverlay(120000)
{
RequestSkip = () => MultiplayerClient.VoteToSkipIntro().WaitSafely(),
}
},
};
@@ -47,26 +52,83 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
for (int i = 0; i < 4; i++)
{
int i2 = i;
int userId = i;
AddStep($"join user {i2}", () =>
AddStep($"join user {userId}", () =>
{
MultiplayerClient.AddUser(new APIUser
{
Id = i2,
Username = $"User {i2}"
Id = userId,
Username = $"User {userId}"
});
MultiplayerClient.ChangeUserState(i2, MultiplayerUserState.Playing);
MultiplayerClient.ChangeUserState(userId, MultiplayerUserState.Playing);
});
}
AddStep("local user votes", () => MultiplayerClient.VoteToSkipIntro().WaitSafely());
AddStep("user 0 votes", () => MultiplayerClient.UserVoteToSkipIntro(0).WaitSafely());
AddStep("local user votes", () => this.ChildrenOfType<MultiplayerSkipOverlay.Button>().Single().TriggerClick());
AddStep("user 1 votes", () => MultiplayerClient.UserVoteToSkipIntro(1).WaitSafely());
}
[Test]
public void TestLeavingBeforeLocalVote()
{
for (int i = 0; i < 4; i++)
{
int i2 = i;
AddStep($"user {i2} votes", () => MultiplayerClient.UserVoteToSkipIntro(i2).WaitSafely());
int userId = i;
AddStep($"join user {userId}", () =>
{
MultiplayerClient.AddUser(new APIUser
{
Id = userId,
Username = $"User {userId}"
});
MultiplayerClient.ChangeUserState(userId, MultiplayerUserState.Playing);
});
}
AddStep("user 0 votes", () => MultiplayerClient.UserVoteToSkipIntro(0).WaitSafely());
AddStep("user 1 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 1 }));
AddStep("user 2 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 2 }));
AddStep("user 3 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 3 }));
AddStep("user 0 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 0 }));
}
[Test]
public void TestLeavingAfterLocalVote()
{
for (int i = 0; i < 4; i++)
{
int userId = i;
AddStep($"join user {userId}", () =>
{
MultiplayerClient.AddUser(new APIUser
{
Id = userId,
Username = $"User {userId}"
});
MultiplayerClient.ChangeUserState(userId, MultiplayerUserState.Playing);
});
}
AddStep("local user votes", () => this.ChildrenOfType<MultiplayerSkipOverlay.Button>().Single().TriggerClick());
AddStep("user 0 votes", () => MultiplayerClient.UserVoteToSkipIntro(0).WaitSafely());
AddStep("user 1 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 1 }));
AddStep("user 2 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 2 }));
AddStep("user 3 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 3 }));
AddStep("user 0 leaves", () => MultiplayerClient.RemoveUser(new APIUser { Id = 0 }));
}
public partial class TestMultiplayerSkipOverlay : MultiplayerSkipOverlay
{
public TestMultiplayerSkipOverlay()
: base(120000)
{
}
}
}

View File

@@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Settings
scrollToAndStartBinding("Increase volume");
AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft));
AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft));
checkBinding("Increase volume", "LShift");
checkBinding("Increase volume", "Shift");
}
[Test]
@@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Settings
AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft));
AddStep("press k", () => InputManager.Key(Key.K));
AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft));
checkBinding("Increase volume", "LShift-K");
checkBinding("Increase volume", "Shift-K");
}
[Test]

View File

@@ -5,6 +5,7 @@ using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -139,9 +140,14 @@ namespace osu.Game.Overlays.Settings.Sections.Input
/// </summary>
/// <param name="fullState">A <see cref="KeyCombination"/> generated from the full input state.</param>
/// <param name="triggerKey">The key which triggered this update, and should be used as the binding.</param>
public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey) =>
// TODO: Distinct() can be removed after https://github.com/ppy/osu-framework/pull/6130 is merged.
UpdateKeyCombination(new KeyCombination(fullState.Keys.Where(KeyCombination.IsModifierKey).Append(triggerKey).Distinct().ToArray()));
public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey)
{
var combination = fullState.Keys.Where(KeyCombination.IsModifierKey)
.Append(triggerKey)
.Select(k => k.GetVirtualKey() ?? k)
.ToArray();
UpdateKeyCombination(new KeyCombination(combination));
}
public void UpdateKeyCombination(KeyCombination newCombination)
{

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Audio;
using osu.Game.Beatmaps;
@@ -47,6 +48,8 @@ namespace osu.Game.Rulesets.Edit
private HitObject? getPreviousHitObject() => beatmap.HitObjects.TakeWhile(h => h.StartTime <= startTimeBindable.Value).LastOrDefault();
protected override bool IsValidForPlacement => HitObject.StartTime >= beatmap.ControlPointInfo.TimingPoints[0].Time;
[Resolved]
private IPlacementHandler placementHandler { get; set; } = null!;
@@ -87,6 +90,13 @@ namespace osu.Game.Rulesets.Edit
placementHandler.HidePlacement();
}
protected override void Update()
{
base.Update();
Colour = IsValidForPlacement ? Colour4.White : Colour4.Red;
}
/// <summary>
/// Updates the time and position of this <see cref="PlacementBlueprint"/>.
/// </summary>

View File

@@ -64,20 +64,15 @@ namespace osu.Game.Screens
{
this.FadeOut();
this.FadeIn(TRANSITION_LENGTH, Easing.InOutQuart);
if (!DisableParallax)
{
this.MoveToX(x_movement_amount);
this.MoveToX(0, TRANSITION_LENGTH, Easing.InOutQuart);
}
}
base.OnEntering(e);
}
public override void OnSuspending(ScreenTransitionEvent e)
{
if (!DisableParallax)
this.MoveToX(-x_movement_amount, TRANSITION_LENGTH, Easing.InOutQuart);
base.OnSuspending(e);
}
@@ -87,7 +82,6 @@ namespace osu.Game.Screens
if (IsLoaded)
{
this.FadeOut(TRANSITION_LENGTH, Easing.OutExpo);
if (!DisableParallax)
this.MoveToX(x_movement_amount, TRANSITION_LENGTH, Easing.OutExpo);
}
@@ -96,7 +90,7 @@ namespace osu.Game.Screens
public override void OnResuming(ScreenTransitionEvent e)
{
if (IsLoaded && !DisableParallax)
if (IsLoaded)
this.MoveToX(0, TRANSITION_LENGTH, Easing.OutExpo);
base.OnResuming(e);
}

View File

@@ -163,7 +163,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match.BeatmapSelect
this.Delay(ARRANGE_DELAY)
.Schedule(() => ArrangeItemsForRollAnimation())
.Delay(arrange_duration)
.Schedule(() => PlayRollAnimation(gameplayItemId, roll_duration))
.Schedule(() => PlayRollAnimation(candidateItemId, roll_duration))
.Delay(roll_duration + present_beatmap_delay)
.Schedule(() => PresentRolledBeatmap(candidateItemId, gameplayItemId));
}

View File

@@ -78,6 +78,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match
client.MatchRoomStateChanged += onRoomStateChanged;
client.UserJoined += onUserJoined;
client.UserLeft += onUserLeft;
client.UserKicked += onUserLeft;
if (client.Room != null)
{
@@ -207,6 +208,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match
client.MatchRoomStateChanged -= onRoomStateChanged;
client.UserJoined -= onUserJoined;
client.UserLeft -= onUserLeft;
client.UserKicked -= onUserLeft;
}
}

View File

@@ -4,15 +4,24 @@
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Play;
using osu.Game.Screens.Ranking;
using osuTK;
using osuTK.Graphics;
@@ -23,90 +32,49 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[Resolved]
private MultiplayerClient client { get; set; } = null!;
private Drawable votedIcon = null!;
private OsuSpriteText countText = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
private Button skipButton = null!;
public MultiplayerSkipOverlay(double startTime)
: base(startTime)
{
}
[BackgroundDependencyLoader]
private void load()
protected override OsuClickableContainer CreateButton() => skipButton = new Button
{
FadingContent.AddRange(
[
votedIcon = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Position = new Vector2(50, 0),
Size = new Vector2(20),
Alpha = 0,
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Green
},
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.5f),
Icon = FontAwesome.Solid.Check
}
}
},
countText = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
Position = new Vector2(0.75f, 0),
Font = OsuFont.Default.With(size: 36, weight: FontWeight.Bold)
}
]);
}
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
protected override void LoadComplete()
{
base.LoadComplete();
skipButton.Enabled.BindValueChanged(e =>
{
RemainingTimeBox.Colour = e.NewValue ? colours.Orange3 : Button.COLOUR_GRAY;
}, true);
client.UserLeft += onUserLeft;
client.UserStateChanged += onUserStateChanged;
client.UserVotedToSkipIntro += onUserVotedToSkipIntro;
updateText();
updateCount();
}
private void onUserLeft(MultiplayerRoomUser user)
{
Schedule(updateText);
}
private void onUserLeft(MultiplayerRoomUser user) => Schedule(updateCount);
private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state)
{
Schedule(updateText);
}
private void onUserStateChanged(MultiplayerRoomUser user, MultiplayerUserState state) => Schedule(updateCount);
private void onUserVotedToSkipIntro(int userId) => Schedule(() =>
{
updateText();
countText.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine);
if (userId == client.LocalUser?.UserID)
{
votedIcon.ScaleTo(1.5f).ScaleTo(1, 200, Easing.OutSine);
votedIcon.FadeInFromZero(100);
}
FadingContent.TriggerShow();
updateCount();
});
private void updateText()
private void updateCount()
{
if (client.Room == null || client.Room.Settings.AutoSkip)
return;
@@ -115,7 +83,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
int countSkipped = client.Room.Users.Count(u => u.State == MultiplayerUserState.Playing && u.VotedToSkipIntro);
int countRequired = countTotal / 2 + 1;
countText.Text = $"{Math.Min(countRequired, countSkipped)} / {countRequired}";
skipButton.SkippedCount.Value = Math.Min(countRequired, countSkipped);
skipButton.RequiredCount.Value = countRequired;
}
protected override void Dispose(bool isDisposing)
@@ -129,5 +98,218 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
client.UserVotedToSkipIntro -= onUserVotedToSkipIntro;
}
}
public partial class Button : OsuClickableContainer
{
private const float chevron_y = 0.4f;
private const float secondary_y = 0.7f;
public static readonly Color4 COLOUR_GRAY = OsuColour.Gray(0.4f);
private Box background = null!;
private Box box = null!;
private TrianglesV2 triangles = null!;
private OsuSpriteText countText = null!;
private OsuSpriteText skipText = null!;
private AspectContainer aspect = null!;
private FillFlowContainer chevrons = null!;
private Sample sampleConfirm = null!;
public readonly BindableInt SkippedCount = new BindableInt();
public readonly BindableInt RequiredCount = new BindableInt();
[Resolved]
private OsuColour colours { get; set; } = null!;
public Button()
{
RelativeSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
sampleConfirm = audio.Samples.Get(@"UI/submit-select");
Children = new Drawable[]
{
background = new Box
{
Alpha = 0.2f,
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
aspect = new AspectContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Height = 0.6f,
Masking = true,
CornerRadius = 15,
Children = new Drawable[]
{
box = new Box
{
RelativeSizeAxes = Axes.Both,
},
triangles = new TrianglesV2
{
RelativeSizeAxes = Axes.Both,
},
countText = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
RelativePositionAxes = Axes.Y,
Y = 0.35f,
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24),
Origin = Anchor.Centre,
},
chevrons = new FillFlowContainer
{
Anchor = Anchor.TopCentre,
RelativePositionAxes = Axes.Y,
AutoSizeAxes = Axes.Both,
Origin = Anchor.Centre,
Direction = FillDirection.Horizontal,
Children = new[]
{
new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronRight },
new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronRight },
new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.Solid.ChevronRight },
}
},
skipText = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
RelativePositionAxes = Axes.Y,
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12),
Origin = Anchor.Centre,
Text = @"SKIP",
Y = secondary_y,
},
}
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
SkippedCount.BindValueChanged(_ => updateCount());
RequiredCount.BindValueChanged(_ => updateCount(), true);
Enabled.BindValueChanged(_ => updateColours(), true);
FinishTransforms(true);
}
private void updateChevronsSpacing()
{
if (SkippedCount.Value > 0 && RequiredCount.Value > 1)
chevrons.TransformSpacingTo(new Vector2(-5f), 500, Easing.OutQuint);
else
chevrons.TransformSpacingTo(IsHovered ? new Vector2(5f) : new Vector2(0f), 500, Easing.OutQuint);
}
private void updateCount()
{
if (SkippedCount.Value > 0 && RequiredCount.Value > 1)
{
countText.FadeIn(300, Easing.OutQuint);
countText.Text = $"{SkippedCount.Value} / {RequiredCount.Value}";
chevrons.ScaleTo(0.5f, 300, Easing.OutQuint)
.MoveTo(new Vector2(-11, secondary_y), 300, Easing.OutQuint);
skipText.MoveToX(11f, 300, Easing.OutQuint);
}
else
{
countText.FadeOut(300, Easing.OutQuint);
chevrons.ScaleTo(1f, 300, Easing.OutQuint)
.MoveTo(new Vector2(0, chevron_y), 300, Easing.OutQuint);
skipText.MoveToX(0f, 300, Easing.OutQuint);
}
updateChevronsSpacing();
updateColours();
}
private void updateColours()
{
if (!Enabled.Value)
{
box.FadeColour(COLOUR_GRAY, 500, Easing.OutQuint);
triangles.FadeColour(ColourInfo.GradientVertical(COLOUR_GRAY.Lighten(0.2f), COLOUR_GRAY), 500, Easing.OutQuint);
}
else
{
box.FadeColour(IsHovered ? colours.Orange3.Lighten(0.2f) : colours.Orange3, 500, Easing.OutQuint);
triangles.FadeColour(ColourInfo.GradientVertical(colours.Orange3.Lighten(0.2f), colours.Orange3), 500, Easing.OutQuint);
}
}
protected override bool OnHover(HoverEvent e)
{
if (Enabled.Value)
{
updateChevronsSpacing();
updateColours();
background.FadeTo(0.4f, 500, Easing.OutQuint);
}
return true;
}
protected override void OnHoverLost(HoverLostEvent e)
{
updateChevronsSpacing();
updateColours();
background.FadeTo(0.2f, 500, Easing.OutQuint);
base.OnHoverLost(e);
}
protected override bool OnMouseDown(MouseDownEvent e)
{
if (Enabled.Value)
aspect.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseUpEvent e)
{
if (Enabled.Value)
aspect.ScaleTo(1, 1000, Easing.OutElastic);
base.OnMouseUp(e);
}
protected override bool OnClick(ClickEvent e)
{
if (!Enabled.Value)
return false;
sampleConfirm.Play();
box.FlashColour(Color4.White, 500, Easing.OutQuint);
aspect.ScaleTo(1.2f, 2000, Easing.OutQuint);
base.OnClick(e);
Enabled.Value = false;
return true;
}
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
countText.Scale = new Vector2(Math.Min(0.85f * aspect.DrawWidth / countText.DrawWidth, 1));
}
}
}
}

View File

@@ -46,6 +46,20 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter
foreach (var r in group)
results[r.result] = judgementCount;
}
// Add Pool for Mania
if (ruleset.Value.ShortName == "mania")
{
var poolCount = new JudgementCount
{
DisplayName = "Pool",
Types = new[] { HitResult.Pool },
ResultCount = new BindableInt()
};
counters.Add(poolCount);
results[HitResult.Pool] = poolCount;
}
}
protected override void LoadComplete()

View File

@@ -10,7 +10,9 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
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.Sprites;
@@ -19,6 +21,7 @@ using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Input.Bindings;
@@ -41,12 +44,18 @@ namespace osu.Game.Screens.Play
protected FadeContainer FadingContent { get; private set; }
private Button button;
private OsuClickableContainer button;
private ButtonContainer buttonContainer;
private Circle remainingTimeBox;
protected Circle RemainingTimeBox { get; private set; }
private double displayTime;
/// <summary>
/// Becomes <see langword="false"/> when the overlay starts fading out.
/// </summary>
private bool isClickable;
private bool skipQueued;
[Resolved]
@@ -83,17 +92,13 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
button = new Button
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
remainingTimeBox = new Circle
button = CreateButton(),
RemainingTimeBox = new Circle
{
Height = 5,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Colour = colours.Yellow,
Colour = colours.Orange3,
RelativeSizeAxes = Axes.X
}
}
@@ -101,6 +106,12 @@ namespace osu.Game.Screens.Play
};
}
protected virtual OsuClickableContainer CreateButton() => new Button
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};
private const double fade_time = 300;
private double fadeOutBeginTime => startTime - MasterGameplayClockContainer.MINIMUM_SKIP_TIME;
@@ -174,10 +185,13 @@ namespace osu.Game.Screens.Play
double progress = Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime));
remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1));
RemainingTimeBox.Width = (float)Interpolation.Lerp(RemainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1));
isClickable = progress > 0;
button.Enabled.Value = isClickable;
if (!isClickable)
button.Enabled.Value = false;
buttonContainer.State.Value = isClickable ? Visibility.Visible : Visibility.Hidden;
}
@@ -220,7 +234,7 @@ namespace osu.Game.Screens.Play
float progress = (float)(gameplayClock.CurrentTime - displayTime) / (float)(fadeOutBeginTime - displayTime);
float newWidth = 1 - Math.Clamp(progress, 0, 1);
remainingTimeBox.ResizeWidthTo(newWidth, timingPoint.BeatLength * 3.5, Easing.OutQuint);
RemainingTimeBox.ResizeWidthTo(newWidth, timingPoint.BeatLength * 3.5, Easing.OutQuint);
}
public partial class FadeContainer : Container, IStateful<Visibility>
@@ -328,8 +342,8 @@ namespace osu.Game.Screens.Play
[BackgroundDependencyLoader]
private void load(OsuColour colours, AudioManager audio)
{
colourNormal = colours.Yellow;
colourHover = colours.YellowDark;
colourNormal = colours.Orange3;
colourHover = colours.Orange3.Lighten(0.2f);
sampleConfirm = audio.Samples.Get(@"UI/submit-select");
@@ -356,6 +370,11 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both,
Colour = colourNormal,
},
new TrianglesV2
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(colourNormal.Lighten(0.2f), colourNormal)
},
flow = new FillFlowContainer
{
Anchor = Anchor.TopCentre,

View File

@@ -30,7 +30,6 @@ using osuTK;
namespace osu.Game.Screens.Play
{
[Cached(typeof(IPreviewTrackOwner))]
public partial class SoloSpectatorScreen : SpectatorScreen, IPreviewTrackOwner
{
[Resolved]

View File

@@ -33,8 +33,6 @@ namespace osu.Game.Screens.SelectV2
{
private const float corner_radius = 10;
public static WorkingBeatmap SelectedWorkingBeatmap = null!;
[Resolved]
private IBindable<WorkingBeatmap> working { get; set; } = null!;
@@ -183,11 +181,7 @@ namespace osu.Game.Screens.SelectV2
{
base.LoadComplete();
working.BindValueChanged(value =>
{
SelectedWorkingBeatmap = value.NewValue;
updateDisplay();
});
working.BindValueChanged(_ => updateDisplay());
ruleset.BindValueChanged(_ => updateDisplay());
onlineLookupResult.BindValueChanged(_ => updateDisplay());

View File

@@ -818,7 +818,8 @@ namespace osu.Game.Screens.SelectV2
// Probably needs more thought because this needs to be in every `ApplyToBackground` currently to restore sane defaults.
backgroundModeBeatmap.FadeColour(Color4.White, 250);
backgroundModeBeatmap.BlurAmount.Value = revealingBackground == null && configBackgroundBlur.Value ? 20 : 0f;
bool backgroundRevealActive = revealingBackground?.State == ScheduledDelegate.RunState.Running || revealingBackground?.State == ScheduledDelegate.RunState.Complete;
backgroundModeBeatmap.BlurAmount.Value = configBackgroundBlur.Value && !backgroundRevealActive ? 20 : 0f;
});
#endregion

View File

@@ -417,7 +417,7 @@ namespace osu.Game.Skinning.Components
applyEzStyleEffect(drawable, new Vector2(1f));
break;
// case HitResult.Pool:
case HitResult.Pool:
case HitResult.Miss:
// 中心小状态,放大后快速消失
applyEzStyleEffect(drawable, new Vector2(1f));

View File

@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
@@ -55,6 +56,7 @@ namespace osu.Game.Tests.Visual
var playable = Beatmap.Value.GetPlayableBeatmap(rulesetInfo);
playable.BeatmapInfo.Ruleset = rulesetInfo;
playable.Difficulty.CircleSize = 2;
playable.ControlPointInfo.Add(0, new TimingControlPoint());
return playable;
}

View File

@@ -36,6 +36,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="20.1.0" />
<!-- <PackageReference Include="ppy.osu.Framework" Version="2025.1205.1" />-->
<!-- <PackageReference Include="ppy.osu.Game.Resources" Version="2025.1125.0" />-->
<PackageReference Include="Sentry" Version="5.1.1" />
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
<PackageReference Include="SharpCompress" Version="0.39.0" />

View File

@@ -17,6 +17,6 @@
<MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2025.1121.1" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2025.1205.1" />
</ItemGroup>
</Project>