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:
commit
a9a24bd481
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
17
osu.Game.Rulesets.Osu/Skinning/Default/IMainCirclePiece.cs
Normal file
17
osu.Game.Rulesets.Osu/Skinning/Default/IMainCirclePiece.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
osu.Game/Screens/Edit/HitAnimationsMenuItem.cs
Normal file
21
osu.Game/Screens/Edit/HitAnimationsMenuItem.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
@ -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" />
|
||||
|
@ -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" />
|
||||
|
Loading…
Reference in New Issue
Block a user