1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 05:02:55 +08:00

Merge branch 'master' into fix-switching-ruleset-unpauses-beatmap

This commit is contained in:
Dan Balasescu 2019-09-02 15:24:01 +09:00 committed by GitHub
commit daa2007b41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 236 additions and 67 deletions

View File

@ -0,0 +1,74 @@
// 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 System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests
{
public class TestSceneSwellJudgements : PlayerTestScene
{
protected new TestPlayer Player => (TestPlayer)base.Player;
public TestSceneSwellJudgements()
: base(new TaikoRuleset())
{
}
[Test]
public void TestZeroTickTimeOffsets()
{
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted);
AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0));
}
protected override bool Autoplay => true;
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap<TaikoHitObject>
{
BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
HitObjects =
{
new Swell
{
StartTime = 1000,
Duration = 1000,
}
}
};
return beatmap;
}
protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer();
protected class TestPlayer : Player
{
public readonly List<JudgementResult> Results = new List<JudgementResult>();
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
public TestPlayer()
: base(false, false)
{
}
[BackgroundDependencyLoader]
private void load()
{
ScoreProcessor.NewJudgement += r => Results.Add(r);
}
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@ -14,7 +15,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
}
public void TriggerResult(HitResult type) => ApplyResult(r => r.Type = type);
protected override void UpdateInitialTransforms() => this.FadeOut();
public void TriggerResult(HitResult type)
{
HitObject.StartTime = Time.Current;
ApplyResult(r => r.Type = type);
}
protected override void CheckForResult(bool userTriggered, double timeOffset)
{

View File

@ -176,6 +176,8 @@ namespace osu.Game.Tests.Visual.Online
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" },
Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" },
},
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = new List<BeatmapInfo>

View File

@ -75,6 +75,28 @@ namespace osu.Game.Beatmaps
/// The availability of this beatmap set.
/// </summary>
public BeatmapSetOnlineAvailability Availability { get; set; }
/// <summary>
/// The song genre of this beatmap set.
/// </summary>
public BeatmapSetOnlineGenre Genre { get; set; }
/// <summary>
/// The song language of this beatmap set.
/// </summary>
public BeatmapSetOnlineLanguage Language { get; set; }
}
public class BeatmapSetOnlineGenre
{
public int Id { get; set; }
public string Name { get; set; }
}
public class BeatmapSetOnlineLanguage
{
public int Id { get; set; }
public string Name { get; set; }
}
public class BeatmapSetOnlineCovers

View File

@ -69,6 +69,12 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"availability")]
private BeatmapSetOnlineAvailability availability { get; set; }
[JsonProperty(@"genre")]
private BeatmapSetOnlineGenre genre { get; set; }
[JsonProperty(@"language")]
private BeatmapSetOnlineLanguage language { get; set; }
[JsonProperty(@"beatmaps")]
private IEnumerable<APIBeatmap> beatmaps { get; set; }
@ -95,6 +101,8 @@ namespace osu.Game.Online.API.Requests.Responses
LastUpdated = lastUpdated,
Availability = availability,
HasFavourited = hasFavourited,
Genre = genre,
Language = language
},
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
};

View File

@ -36,7 +36,7 @@ namespace osu.Game.Overlays.BeatmapSet
public Info()
{
MetadataSection source, tags;
MetadataSection source, tags, genre, language;
RelativeSizeAxes = Axes.X;
Height = 220;
Masking = true;
@ -83,11 +83,12 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
LayoutDuration = transition_duration,
Direction = FillDirection.Full,
Children = new[]
{
source = new MetadataSection("Source"),
genre = new MetadataSection("Genre") { Width = 0.5f },
language = new MetadataSection("Language") { Width = 0.5f },
tags = new MetadataSection("Tags"),
},
},
@ -119,6 +120,8 @@ namespace osu.Game.Overlays.BeatmapSet
{
source.Text = b.NewValue?.Metadata.Source ?? string.Empty;
tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty;
genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? string.Empty;
language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? string.Empty;
};
}
@ -139,7 +142,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
if (string.IsNullOrEmpty(value))
{
this.FadeOut(transition_duration);
Hide();
return;
}
@ -149,12 +152,6 @@ namespace osu.Game.Overlays.BeatmapSet
}
}
public Color4 TextColour
{
get => textFlow.Colour;
set => textFlow.Colour = value;
}
public MetadataSection(string title)
{
RelativeSizeAxes = Axes.X;

View File

@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat.Selection
private Color4 topicColour;
private Color4 hoverColour;
public IEnumerable<string> FilterTerms => new[] { channel.Name };
public IEnumerable<string> FilterTerms => new[] { channel.Name, channel.Topic };
public bool MatchingFilter
{

View File

@ -296,7 +296,11 @@ namespace osu.Game.Overlays.Profile.Header.Components
this.MoveTo(pos, 200, Easing.OutQuint);
}
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
protected override void PopIn()
{
instantMove |= !IsPresent;
this.FadeIn(200, Easing.OutQuint);
}
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Threading;
using osu.Game.Audio;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
@ -278,6 +279,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
UpdateResult(false);
}
/// <summary>
/// Schedules an <see cref="Action"/> to this <see cref="DrawableHitObject"/>.
/// </summary>
/// <remarks>
/// Only provided temporarily until hitobject pooling is implemented.
/// </remarks>
protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action);
private double? lifetimeStart;
public override double LifetimeStart

View File

@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Scoring
/// <summary>
/// Whether all <see cref="Judgement"/>s have been processed.
/// </summary>
protected virtual bool HasCompleted => false;
public virtual bool HasCompleted => false;
/// <summary>
/// Whether this ScoreProcessor has already triggered the failed state.
@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Scoring
private const double combo_portion = 0.7;
private const double max_score = 1000000;
protected sealed override bool HasCompleted => JudgedHits == MaxHits;
public sealed override bool HasCompleted => JudgedHits == MaxHits;
protected int MaxHits { get; private set; }
protected int JudgedHits { get; private set; }

View File

@ -215,10 +215,6 @@ namespace osu.Game.Rulesets.UI
continueResume();
}
public ResumeOverlay ResumeOverlay { get; private set; }
protected virtual ResumeOverlay CreateResumeOverlay() => null;
/// <summary>
/// Creates and adds the visual representation of a <see cref="TObject"/> to this <see cref="DrawableRuleset{TObject}"/>.
/// </summary>
@ -389,6 +385,13 @@ namespace osu.Game.Rulesets.UI
/// </summary>
public abstract GameplayCursorContainer Cursor { get; }
/// <summary>
/// An optional overlay used when resuming gameplay from a paused state.
/// </summary>
public ResumeOverlay ResumeOverlay { get; protected set; }
protected virtual ResumeOverlay CreateResumeOverlay() => null;
/// <summary>
/// Sets a replay to be used, overriding local input.
/// </summary>

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Caching;
@ -50,8 +51,13 @@ namespace osu.Game.Rulesets.UI.Scrolling
public override bool Remove(DrawableHitObject hitObject)
{
var result = base.Remove(hitObject);
if (result)
{
initialStateCache.Invalidate();
hitObjectInitialStateCache.Remove(hitObject);
}
return result;
}
@ -86,13 +92,34 @@ namespace osu.Game.Rulesets.UI.Scrolling
scrollingInfo.Algorithm.Reset();
foreach (var obj in Objects)
{
computeLifetimeStartRecursive(obj);
computeInitialStateRecursive(obj);
}
initialStateCache.Validate();
}
}
private void computeInitialStateRecursive(DrawableHitObject hitObject)
private void computeLifetimeStartRecursive(DrawableHitObject hitObject)
{
hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value);
foreach (var obj in hitObject.NestedHitObjects)
computeLifetimeStartRecursive(obj);
}
private readonly Dictionary<DrawableHitObject, Cached> hitObjectInitialStateCache = new Dictionary<DrawableHitObject, Cached>();
// Cant use AddOnce() since the delegate is re-constructed every invocation
private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() =>
{
if (!hitObjectInitialStateCache.TryGetValue(hitObject, out var cached))
cached = hitObjectInitialStateCache[hitObject] = new Cached();
if (cached.IsValid)
return;
double endTime = hitObject.HitObject.StartTime;
if (hitObject.HitObject is IHasEndTime e)
@ -113,7 +140,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
}
}
hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value);
hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime, timeRange.Value, scrollLength);
foreach (var obj in hitObject.NestedHitObjects)
@ -123,7 +149,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
// Nested hitobjects don't need to scroll, but they do need accurate positions
updatePosition(obj, hitObject.HitObject.StartTime);
}
}
cached.Validate();
});
protected override void UpdateAfterChildrenLife()
{

View File

@ -4,6 +4,9 @@
using System;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit
{
@ -35,5 +38,41 @@ namespace osu.Game.Screens.Edit
protected override int DefaultMinValue => VALID_DIVISORS.First();
protected override int DefaultMaxValue => VALID_DIVISORS.Last();
protected override int DefaultPrecision => 1;
/// <summary>
/// Retrieves the appropriate colour for a beat divisor.
/// </summary>
/// <param name="beatDivisor">The beat divisor.</param>
/// <param name="colours">The set of colours.</param>
/// <returns>The applicable colour from <paramref name="colours"/> for <paramref name="beatDivisor"/>.</returns>
public static ColourInfo GetColourFor(int beatDivisor, OsuColour colours)
{
switch (beatDivisor)
{
case 2:
return colours.BlueLight;
case 4:
return colours.Blue;
case 8:
return colours.BlueDarker;
case 16:
return colours.PurpleDark;
case 3:
return colours.YellowLight;
case 6:
return colours.Yellow;
case 12:
return colours.YellowDarker;
default:
return Color4.White;
}
}
}
}

View File

@ -188,6 +188,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
private Marker marker;
[Resolved]
private OsuColour colours { get; set; }
private readonly BindableBeatDivisor beatDivisor;
private readonly int[] availableDivisors;
@ -204,11 +207,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
foreach (var t in availableDivisors)
{
AddInternal(new Tick(t)
AddInternal(new Tick
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopCentre,
RelativePositionAxes = Axes.X,
Colour = BindableBeatDivisor.GetColourFor(t, colours),
X = getMappedPosition(t)
});
}
@ -284,11 +288,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
private class Tick : CompositeDrawable
{
private readonly int divisor;
public Tick(int divisor)
public Tick()
{
this.divisor = divisor;
Size = new Vector2(2.5f, 10);
InternalChild = new Box { RelativeSizeAxes = Axes.Both };
@ -296,42 +297,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
CornerRadius = 0.5f;
Masking = true;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = getColourForDivisor(divisor, colours);
}
private ColourInfo getColourForDivisor(int divisor, OsuColour colours)
{
switch (divisor)
{
case 2:
return colours.BlueLight;
case 4:
return colours.Blue;
case 8:
return colours.BlueDarker;
case 16:
return colours.PurpleDark;
case 3:
return colours.YellowLight;
case 6:
return colours.Yellow;
case 12:
return colours.YellowDarker;
default:
return Color4.White;
}
}
}
private class Marker : CompositeDrawable

View File

@ -77,7 +77,7 @@ namespace osu.Game.Screens.Menu
Scheduler.AddDelayed(delegate
{
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu.
// Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu.
if (menuMusic.Value)
{
track.Restart();

View File

@ -47,7 +47,7 @@ namespace osu.Game.Screens.Menu
private const float visualiser_rounds = 5;
/// <summary>
/// How much should each bar go down each milisecond (based on a full bar).
/// How much should each bar go down each millisecond (based on a full bar).
/// </summary>
private const float decay_per_milisecond = 0.0024f;
@ -161,7 +161,7 @@ namespace osu.Game.Screens.Menu
private IShader shader;
private Texture texture;
//Asuming the logo is a circle, we don't need a second dimension.
//Assuming the logo is a circle, we don't need a second dimension.
private float size;
private Color4 colour;

View File

@ -229,7 +229,7 @@ namespace osu.Game.Screens.Menu
}
/// <summary>
/// Schedule a new extenral animation. Handled queueing and finishing previous animations in a sane way.
/// Schedule a new external animation. Handled queueing and finishing previous animations in a sane way.
/// </summary>
/// <param name="action">The animation to be performed</param>
/// <param name="waitForPrevious">If true, the new animation is delayed until all previous transforms finish. If false, existing transformed are cleared.</param>

View File

@ -178,6 +178,7 @@ namespace osu.Game.Screens.Play
},
// display the cursor above some HUD elements.
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(),
HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value)
{
HoldToQuit =

View File

@ -3,6 +3,7 @@
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Rulesets;
@ -40,6 +41,8 @@ namespace osu.Game.Tests.Visual
protected virtual bool AllowFail => false;
protected virtual bool Autoplay => false;
private void loadPlayer()
{
var beatmap = CreateBeatmap(ruleset.RulesetInfo);
@ -49,6 +52,13 @@ namespace osu.Game.Tests.Visual
if (!AllowFail)
Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) };
if (Autoplay)
{
var mod = ruleset.GetAutoplayMod();
if (mod != null)
Mods.Value = Mods.Value.Concat(mod.Yield()).ToArray();
}
Player = CreatePlayer(ruleset);
LoadScreen(Player);
}