1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 13:15:08 +08:00

Merge branch 'master' into ruleset-switch-sounds

This commit is contained in:
Dean Herbert 2021-04-23 10:50:41 +09:00 committed by GitHub
commit a9a24bd481
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 182 additions and 26 deletions

View File

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

View File

@ -324,6 +324,33 @@ namespace osu.Game.Rulesets.Mania.Tests
assertTailJudgement(HitResult.Ok);
}
[Test]
public void TestZeroLength()
{
var beatmap = new Beatmap<ManiaHitObject>
{
HitObjects =
{
new HoldNote
{
StartTime = 1000,
Duration = 0,
Column = 0,
},
},
BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo },
};
performTest(new List<ReplayFrame>
{
new ManiaReplayFrame(beatmap.HitObjects[0].StartTime, ManiaAction.Key1),
new ManiaReplayFrame(beatmap.HitObjects[0].GetEndTime() + 1),
}, beatmap);
AddAssert("hold note hit", () => judgementResults.Where(j => beatmap.HitObjects[0].NestedHitObjects.Contains(j.HitObject))
.All(j => j.Type.IsHit()));
}
private void assertHeadJudgement(HitResult result)
=> AddAssert($"head judged as {result}", () => judgementResults.First(j => j.HitObject is Note).Type == result);

View File

@ -221,7 +221,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
// As the note is being held, adjust the size of the sizing container. This has two effects:
// 1. The contained masking container will mask the body and ticks.
// 2. The head note will move along with the new "head position" in the container.
if (Head.IsHit && releaseTime == null)
if (Head.IsHit && releaseTime == null && DrawHeight > 0)
{
// How far past the hit target this hold note is. Always a positive value.
float yOffset = Math.Max(0, Direction.Value == ScrollingDirection.Up ? -Y : Y);

View File

@ -3,8 +3,11 @@
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
@ -27,8 +30,16 @@ namespace osu.Game.Rulesets.Osu.Edit
private class OsuEditPlayfield : OsuPlayfield
{
private Bindable<bool> hitAnimations;
protected override GameplayCursorContainer CreateCursor() => null;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
hitAnimations = config.GetBindable<bool>(OsuSetting.EditorHitAnimations);
}
protected override void OnNewDrawableHitObject(DrawableHitObject d)
{
d.ApplyCustomUpdateState += updateState;
@ -42,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Edit
private void updateState(DrawableHitObject hitObject, ArmedState state)
{
if (state == ArmedState.Idle)
if (state == ArmedState.Idle || hitAnimations.Value)
return;
// adjust the visuals of certain object types to make them stay on screen for longer than usual.
@ -58,8 +69,17 @@ namespace osu.Game.Rulesets.Osu.Edit
case DrawableHitCircle circle: // also handles slider heads
circle.ApproachCircle
.FadeOutFromOne(editor_hit_object_fade_out_extension)
.FadeOutFromOne(editor_hit_object_fade_out_extension * 4)
.Expire();
circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint);
var circlePieceDrawable = circle.CirclePiece.Drawable;
// clear any explode animation logic.
circlePieceDrawable.ApplyTransformsAt(circle.HitStateUpdateTime, true);
circlePieceDrawable.ClearTransformsAfter(circle.HitStateUpdateTime, true);
break;
}
@ -71,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Edit
hitObject.RemoveTransform(existing);
using (hitObject.BeginAbsoluteSequence(existing.StartTime))
using (hitObject.BeginAbsoluteSequence(hitObject.HitStateUpdateTime))
hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire();
}
}

View File

@ -182,6 +182,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
// todo: temporary / arbitrary, used for lifetime optimisation.
this.Delay(800).FadeOut();
(CirclePiece.Drawable as IMainCirclePiece)?.Animate(state);
switch (state)
{
case ArmedState.Idle:

View File

@ -0,0 +1,17 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables;
namespace osu.Game.Rulesets.Osu.Skinning.Default
{
public interface IMainCirclePiece
{
/// <summary>
/// Begins animating this <see cref="IMainCirclePiece"/>.
/// </summary>
/// <param name="state">The <see cref="ArmedState"/> of the related <see cref="DrawableHitCircle"/>.</param>
void Animate(ArmedState state);
}
}

View File

@ -13,7 +13,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Skinning.Default
{
public class MainCirclePiece : CompositeDrawable
public class MainCirclePiece : CompositeDrawable, IMainCirclePiece
{
private readonly CirclePiece circle;
private readonly RingPiece ring;
@ -67,12 +67,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
}, true);
indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true);
drawableObject.ApplyCustomUpdateState += updateState;
updateState(drawableObject, drawableObject.State.Value);
}
private void updateState(DrawableHitObject drawableObject, ArmedState state)
public void Animate(ArmedState state)
{
using (BeginAbsoluteSequence(drawableObject.StateUpdateTime))
glow.FadeOut(400);

View File

@ -12,6 +12,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
@ -19,7 +20,7 @@ using static osu.Game.Skinning.LegacySkinConfiguration;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{
public class LegacyMainCirclePiece : CompositeDrawable
public class LegacyMainCirclePiece : CompositeDrawable, IMainCirclePiece
{
private readonly string priorityLookup;
private readonly bool hasNumber;
@ -138,12 +139,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
accentColour.BindValueChanged(colour => hitCircleSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
if (hasNumber)
indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true);
drawableObject.ApplyCustomUpdateState += updateState;
updateState(drawableObject, drawableObject.State.Value);
}
private void updateState(DrawableHitObject drawableObject, ArmedState state)
public void Animate(ArmedState state)
{
const double legacy_fade_duration = 240;

View File

@ -42,6 +42,28 @@ namespace osu.Game.Tests.Visual.Editing
});
}
[Test]
public void TestNudgeSelection()
{
HitCircle[] addedObjects = null;
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
{
new HitCircle { StartTime = 100 },
new HitCircle { StartTime = 200, Position = new Vector2(50) },
new HitCircle { StartTime = 300, Position = new Vector2(100) },
new HitCircle { StartTime = 400, Position = new Vector2(150) },
}));
AddStep("select objects", () => EditorBeatmap.SelectedHitObjects.AddRange(addedObjects));
AddStep("nudge forwards", () => InputManager.Key(Key.K));
AddAssert("objects moved forwards in time", () => addedObjects[0].StartTime > 100);
AddStep("nudge backwards", () => InputManager.Key(Key.J));
AddAssert("objects reverted to original position", () => addedObjects[0].StartTime == 100);
}
[Test]
public void TestBasicSelect()
{

View File

@ -143,6 +143,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f);
SetDefault(OsuSetting.EditorHitAnimations, false);
}
public OsuConfigManager(Storage storage)
@ -266,6 +267,7 @@ namespace osu.Game.Configuration
GameplayDisableWinKey,
SeasonalBackgroundMode,
EditorWaveformOpacity,
EditorHitAnimations,
DiscordRichPresence,
AutomaticallyDownloadWhenSpectating,
ShowOnlineExplicitContent,

View File

@ -71,6 +71,8 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.F3 }, GlobalAction.EditorTimingMode),
new KeyBinding(new[] { InputKey.F4 }, GlobalAction.EditorSetupMode),
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.A }, GlobalAction.EditorVerifyMode),
new KeyBinding(new[] { InputKey.J }, GlobalAction.EditorNudgeLeft),
new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight),
};
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
@ -251,5 +253,11 @@ namespace osu.Game.Input.Bindings
[Description("Verify mode")]
EditorVerifyMode,
[Description("Nudge selection left")]
EditorNudgeLeft,
[Description("Nudge selection right")]
EditorNudgeRight
}
}

View File

@ -519,7 +519,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
// Apply the start time at the newly snapped-to position
double offset = result.Time.Value - movementBlueprints.First().HitObject.StartTime;
Beatmap.PerformOnSelection(obj => obj.StartTime += offset);
if (offset != 0)
Beatmap.PerformOnSelection(obj => obj.StartTime += offset);
}
return true;

View File

@ -12,9 +12,11 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
@ -237,10 +239,48 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
}
}
internal class TimelineSelectionHandler : SelectionHandler
internal class TimelineSelectionHandler : SelectionHandler, IKeyBindingHandler<GlobalAction>
{
// for now we always allow movement. snapping is provided by the Timeline's "distance" snap implementation
public override bool HandleMovement(MoveSelectionEvent moveEvent) => true;
public bool OnPressed(GlobalAction action)
{
switch (action)
{
case GlobalAction.EditorNudgeLeft:
nudgeSelection(-1);
return true;
case GlobalAction.EditorNudgeRight:
nudgeSelection(1);
return true;
}
return false;
}
public void OnReleased(GlobalAction action)
{
}
/// <summary>
/// Nudge the current selection by the specified multiple of beat divisor lengths,
/// based on the timing at the first object in the selection.
/// </summary>
/// <param name="amount">The direction and count of beat divisor lengths to adjust.</param>
private void nudgeSelection(int amount)
{
var selected = EditorBeatmap.SelectedHitObjects;
if (selected.Count == 0)
return;
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(selected.First().StartTime);
double adjustment = timingPoint.BeatLength / EditorBeatmap.BeatDivisor * amount;
EditorBeatmap.PerformOnSelection(h => h.StartTime += adjustment);
}
}
private class TimelineDragBox : DragBox

View File

@ -224,9 +224,10 @@ namespace osu.Game.Screens.Edit
},
new MenuItem("View")
{
Items = new[]
Items = new MenuItem[]
{
new WaveformOpacityMenu(config)
new WaveformOpacityMenuItem(config.GetBindable<float>(OsuSetting.EditorWaveformOpacity)),
new HitAnimationsMenuItem(config.GetBindable<bool>(OsuSetting.EditorHitAnimations))
}
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Edit
{
internal class HitAnimationsMenuItem : ToggleMenuItem
{
[UsedImplicitly]
private readonly Bindable<bool> hitAnimations;
public HitAnimationsMenuItem(Bindable<bool> hitAnimations)
: base("Hit animations")
{
State.BindTo(this.hitAnimations = hitAnimations);
}
}
}

View File

@ -4,18 +4,17 @@
using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Edit
{
internal class WaveformOpacityMenu : MenuItem
internal class WaveformOpacityMenuItem : MenuItem
{
private readonly Bindable<float> waveformOpacity;
private readonly Dictionary<float, ToggleMenuItem> menuItemLookup = new Dictionary<float, ToggleMenuItem>();
public WaveformOpacityMenu(OsuConfigManager config)
public WaveformOpacityMenuItem(Bindable<float> waveformOpacity)
: base("Waveform opacity")
{
Items = new[]
@ -26,7 +25,7 @@ namespace osu.Game.Screens.Edit
createMenuItem(1f),
};
waveformOpacity = config.GetBindable<float>(OsuSetting.EditorWaveformOpacity);
this.waveformOpacity = waveformOpacity;
waveformOpacity.BindValueChanged(opacity =>
{
foreach (var kvp in menuItemLookup)

View File

@ -29,7 +29,8 @@
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.NETCore.Targets" Version="3.1.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2021.422.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.422.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.412.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
<PackageReference Include="Sentry" Version="3.2.0" />
<PackageReference Include="SharpCompress" Version="0.28.1" />

View File

@ -70,7 +70,7 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.422.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.422.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.422.0" />
</ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -93,7 +93,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2021.422.0" />
<PackageReference Include="ppy.osu.Framework" Version="2021.422.1" />
<PackageReference Include="SharpCompress" Version="0.28.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />