Merge remote-tracking branch 'upstream/master' into flashlight-dim

This commit is contained in:
David Zhao
2019-05-07 12:04:58 +09:00
196 changed files with 2679 additions and 1463 deletions

View File

@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Difficulty
/// <summary>
/// Creates the <see cref="Skill"/>s to calculate the difficulty of an <see cref="IBeatmap"/>.
/// </summary>
/// <param name="beatmap">The <see cref="IBeatmap"/> whose difficulty will be calculated.</param
/// <param name="beatmap">The <see cref="IBeatmap"/> whose difficulty will be calculated.</param>
/// <returns>The <see cref="Skill"/>s.</returns>
protected abstract Skill[] CreateSkills(IBeatmap beatmap);
}

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.Objects;
using osu.Game.Screens.Edit.Compose;
using osuTK;
@ -108,7 +109,8 @@ namespace osu.Game.Rulesets.Edit
}
/// <summary>
/// Invokes <see cref="HitObject.ApplyDefaults"/>, refreshing <see cref="HitObject.NestedHitObjects"/> and parameters for the <see cref="HitObject"/>.
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,BeatmapDifficulty)"/>,
/// refreshing <see cref="Objects.HitObject.NestedHitObjects"/> and parameters for the <see cref="HitObject"/>.
/// </summary>
protected void ApplyDefaultsToHitObject() => HitObject.ApplyDefaults(beatmap.Value.Beatmap.ControlPointInfo, beatmap.Value.Beatmap.BeatmapInfo.BaseDifficulty);

View File

@ -68,9 +68,11 @@ namespace osu.Game.Rulesets.Edit
get => state;
set
{
if (state == value) return;
if (state == value)
return;
state = value;
switch (state)
{
case SelectionState.Selected:
@ -82,6 +84,8 @@ namespace osu.Game.Rulesets.Edit
Deselected?.Invoke(this);
break;
}
StateChanged?.Invoke(state);
}
}

View File

@ -2,14 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mods
{
/// <summary>
/// Interface for a <see cref="Mod"/> that applies changes to a <see cref="BeatmapConverter{TObject}"/>.
/// </summary>
/// <typeparam name="TObject">The type of converted <see cref="HitObject"/>.</typeparam>
public interface IApplicableToBeatmapConverter : IApplicableMod
{
/// <summary>

View File

@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mods
public interface IApplicableToHitObject : IApplicableMod
{
/// <summary>
/// Applies this <see cref="IApplicableToHitObject{TObject}"/> to a <see cref="HitObject"/>.
/// Applies this <see cref="IApplicableToHitObject"/> to a <see cref="HitObject"/>.
/// </summary>
/// <param name="hitObject">The <see cref="HitObject"/> to apply to.</param>
void ApplyToHitObject(HitObject hitObject);

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mods
{
@ -10,6 +11,14 @@ namespace osu.Game.Rulesets.Mods
/// </summary>
public interface IApplicableToScoreProcessor : IApplicableMod
{
/// <summary>
/// Provide a <see cref="ScoreProcessor"/> to a mod. Called once on initialisation of a play instance.
/// </summary>
void ApplyToScoreProcessor(ScoreProcessor scoreProcessor);
/// <summary>
/// Called every time a rank calculation is requested. Allows mods to adjust the final rank.
/// </summary>
ScoreRank AdjustRank(ScoreRank rank, double accuracy);
}
}

View File

@ -1,11 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using Newtonsoft.Json;
namespace osu.Game.Rulesets.Mods
{
public interface IMod
public interface IMod : IEquatable<IMod>
{
/// <summary>
/// The shortened name of this mod.

View File

@ -70,5 +70,7 @@ namespace osu.Game.Rulesets.Mods
/// Creates a copy of this <see cref="Mod"/> initialised to a default state.
/// </summary>
public virtual Mod CreateCopy() => (Mod)Activator.CreateInstance(GetType());
public bool Equals(IMod other) => GetType() == other?.GetType();
}
}

View File

@ -16,6 +16,7 @@ using osu.Game.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osuTK;
using osuTK.Graphics;
@ -46,6 +47,8 @@ namespace osu.Game.Rulesets.Mods
Combo.BindTo(scoreProcessor.Combo);
}
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
public virtual void ApplyToDrawableRuleset(DrawableRuleset<T> drawableRuleset)
{
var flashlight = CreateFlashlight();
@ -64,25 +67,12 @@ namespace osu.Game.Rulesets.Mods
internal BindableInt Combo;
private IShader shader;
protected override DrawNode CreateDrawNode() => new FlashlightDrawNode();
protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(this);
public override bool RemoveCompletedTransforms => false;
public List<BreakPeriod> Breaks;
protected override void ApplyDrawNode(DrawNode node)
{
base.ApplyDrawNode(node);
var flashNode = (FlashlightDrawNode)node;
flashNode.Shader = shader;
flashNode.ScreenSpaceDrawQuad = ScreenSpaceDrawQuad;
flashNode.FlashlightPosition = Vector2Extensions.Transform(FlashlightPosition, DrawInfo.Matrix);
flashNode.FlashlightSize = FlashlightSize * DrawInfo.Matrix.ExtractScale().Xy;
flashNode.FlashlightDim = FlashlightDim;
}
[BackgroundDependencyLoader]
private void load(ShaderManager shaderManager)
{
@ -152,29 +142,47 @@ namespace osu.Game.Rulesets.Mods
Invalidate(Invalidation.DrawNode);
}
}
}
private class FlashlightDrawNode : DrawNode
{
public IShader Shader;
public Quad ScreenSpaceDrawQuad;
public Vector2 FlashlightPosition;
public Vector2 FlashlightSize;
public float FlashlightDim;
public override void Draw(Action<TexturedVertex2D> vertexAction)
private class FlashlightDrawNode : DrawNode
{
base.Draw(vertexAction);
protected new Flashlight Source => (Flashlight)base.Source;
Shader.Bind();
private IShader shader;
private Quad screenSpaceDrawQuad;
private Vector2 flashlightPosition;
private Vector2 flashlightSize;
private float flashlightDim;
Shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref FlashlightPosition);
Shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref FlashlightSize);
Shader.GetUniform<float>("flashlightDim").UpdateValue(ref FlashlightDim);
public FlashlightDrawNode(Flashlight source)
: base(source)
{
}
Texture.WhitePixel.DrawQuad(ScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
public override void ApplyState()
{
base.ApplyState();
Shader.Unbind();
shader = Source.shader;
screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad;
flashlightPosition = Vector2Extensions.Transform(Source.FlashlightPosition, DrawInfo.Matrix);
flashlightSize = Source.FlashlightSize * DrawInfo.Matrix.ExtractScale().Xy;
flashlightDim = Source.FlashlightDim;
}
public override void Draw(Action<TexturedVertex2D> vertexAction)
{
base.Draw(vertexAction);
shader.Bind();
shader.GetUniform<Vector2>("flashlightPos").UpdateValue(ref flashlightPosition);
shader.GetUniform<Vector2>("flashlightSize").UpdateValue(ref flashlightSize);
shader.GetUniform<float>("flashlightDim").UpdateValue(ref FlashlightDim);
Texture.WhitePixel.DrawQuad(screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction);
shader.Unbind();
}
}
}
}

View File

@ -8,10 +8,12 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mods
{
public abstract class ModHidden : Mod, IReadFromConfig, IApplicableToDrawableHitObjects
public abstract class ModHidden : Mod, IReadFromConfig, IApplicableToDrawableHitObjects, IApplicableToScoreProcessor
{
public override string Name => "Hidden";
public override string Acronym => "HD";
@ -32,6 +34,25 @@ namespace osu.Game.Rulesets.Mods
d.ApplyCustomUpdateState += ApplyHiddenState;
}
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
{
// Default value of ScoreProcessor's Rank in Hidden Mod should be SS+
scoreProcessor.Rank.Value = ScoreRank.XH;
}
public ScoreRank AdjustRank(ScoreRank rank, double accuracy)
{
switch (rank)
{
case ScoreRank.X:
return ScoreRank.XH;
case ScoreRank.S:
return ScoreRank.SH;
default:
return rank;
}
}
protected virtual void ApplyHiddenState(DrawableHitObject hitObject, ArmedState state)
{
}

View File

@ -5,6 +5,7 @@ using System;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Rulesets.Mods
{
@ -24,6 +25,8 @@ namespace osu.Game.Rulesets.Mods
scoreProcessor.FailConditions += FailCondition;
}
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
protected virtual bool FailCondition(ScoreProcessor scoreProcessor) => scoreProcessor.Combo.Value == 0;
}
}

View File

@ -7,6 +7,7 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Game.Audio;
using osu.Game.Graphics;
@ -58,7 +59,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
public bool AllJudged => Judged && NestedHitObjects.All(h => h.AllJudged);
/// <summary>
/// Whether this <see cref="DrawableHitObject"/> has been hit. This occurs if <see cref="Result.IsHit"/> is <see cref="true"/>.
/// Whether this <see cref="DrawableHitObject"/> has been hit. This occurs if <see cref="Result"/> is hit.
/// Note: This does NOT include nested hitobjects.
/// </summary>
public bool IsHit => Result?.IsHit ?? false;
@ -223,7 +224,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
}
/// <summary>
/// Will called at least once after the <see cref="LifetimeEnd"/> of this <see cref="DrawableHitObject"/> has been passed.
/// Will called at least once after the <see cref="Drawable.LifetimeEnd"/> of this <see cref="DrawableHitObject"/> has been passed.
/// </summary>
internal void OnLifetimeEnd()
{

View File

@ -53,8 +53,6 @@ namespace osu.Game.Rulesets.Objects
[JsonIgnore]
public bool Kiai { get; private set; }
private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY;
/// <summary>
/// The hit windows for this <see cref="HitObject"/>.
/// </summary>
@ -115,7 +113,7 @@ namespace osu.Game.Rulesets.Objects
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
/// This can be null to indicate that the <see cref="HitObject"/> has no <see cref="HitWindows"/>.
/// <para>
/// This will only be invoked if <see cref="HitWindows"/> hasn't been set externally (e.g. from a <see cref="BeatmapConverter"/>.
/// This will only be invoked if <see cref="HitWindows"/> hasn't been set externally (e.g. from a <see cref="BeatmapConverter{T}"/>.
/// </para>
/// </summary>
protected virtual HitWindows CreateHitWindows() => new HitWindows();

View File

@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.Objects
/// <summary>
/// Given a time offset, whether the <see cref="HitObject"/> can ever be hit in the future with a non-<see cref="HitResult.Miss"/> result.
/// This happens if <paramref name="timeOffset"/> is less than what is required for a <see cref="SuccessfulHitWindow"/> result.
/// This happens if <paramref name="timeOffset"/> is less than what is required for <see cref="LowestSuccessfulHitResult"/>.
/// </summary>
/// <param name="timeOffset">The time offset.</param>
/// <returns>Whether the <see cref="HitObject"/> can be hit at any point in the future from this time offset.</returns>

View File

@ -277,12 +277,5 @@ namespace osu.Game.Rulesets.Objects
return ControlPoints.SequenceEqual(other.ControlPoints) && ExpectedDistance.Equals(other.ExpectedDistance) && Type == other.Type;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is SliderPath other && Equals(other);
}
}
}

View File

@ -53,6 +53,7 @@ namespace osu.Game.Rulesets
/// Attempt to create a hit renderer for a beatmap
/// </summary>
/// <param name="beatmap">The beatmap to create the hit renderer for.</param>
/// <param name="mods">The <see cref="Mod"/>s to apply.</param>
/// <exception cref="BeatmapInvalidForRulesetException">Unable to successfully load the beatmap to be usable with this ruleset.</exception>
/// <returns></returns>
public abstract DrawableRuleset CreateDrawableRulesetWith(WorkingBeatmap beatmap, IReadOnlyList<Mod> mods);

View File

@ -10,6 +10,7 @@ using osu.Framework.Extensions;
using osu.Framework.Extensions.TypeExtensions;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
@ -60,6 +61,11 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
public readonly BindableInt Combo = new BindableInt();
/// <summary>
/// The current selected mods
/// </summary>
public readonly Bindable<IReadOnlyList<Mod>> Mods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
/// <summary>
/// Create a <see cref="HitWindows"/> for this processor.
/// </summary>
@ -98,7 +104,12 @@ namespace osu.Game.Rulesets.Scoring
protected ScoreProcessor()
{
Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
Accuracy.ValueChanged += delegate { Rank.Value = rankFrom(Accuracy.Value); };
Accuracy.ValueChanged += delegate
{
Rank.Value = rankFrom(Accuracy.Value);
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
Rank.Value = mod.AdjustRank(Rank.Value, Accuracy.Value);
};
}
private ScoreRank rankFrom(double acc)
@ -154,7 +165,6 @@ namespace osu.Game.Rulesets.Scoring
/// <summary>
/// Notifies subscribers of <see cref="NewJudgement"/> that a new judgement has occurred.
/// </summary>
/// <param name="judgement">The judgement to notify subscribers of.</param>
/// <param name="result">The judgement scoring result to notify subscribers of.</param>
protected void NotifyNewJudgement(JudgementResult result)
{
@ -283,7 +293,6 @@ namespace osu.Game.Rulesets.Scoring
/// <summary>
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
/// </summary>
/// <param name="judgement">The judgement to remove.</param>
/// <param name="result">The judgement scoring result.</param>
private void revertResult(JudgementResult result)
{
@ -340,7 +349,6 @@ namespace osu.Game.Rulesets.Scoring
/// <summary>
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
/// </summary>
/// <param name="judgement">The judgement to remove.</param>
/// <param name="result">The judgement scoring result.</param>
protected virtual void RevertResult(JudgementResult result)
{

View File

@ -93,6 +93,7 @@ namespace osu.Game.Rulesets.UI
/// </summary>
/// <param name="ruleset">The ruleset being represented.</param>
/// <param name="workingBeatmap">The beatmap to create the hit renderer for.</param>
/// <param name="mods">The <see cref="Mod"/>s to apply.</param>
protected DrawableRuleset(Ruleset ruleset, WorkingBeatmap workingBeatmap, IReadOnlyList<Mod> mods)
: base(ruleset)
{
@ -275,7 +276,8 @@ namespace osu.Game.Rulesets.UI
/// <summary>
/// Applies the active mods to this DrawableRuleset.
/// </summary>
/// <param name="mods"></param>
/// <param name="mods">The <see cref="Mod"/>s to apply.</param>
/// <param name="config">The <see cref="OsuConfigManager"/> to apply.</param>
private void applyRulesetMods(IReadOnlyList<Mod> mods, OsuConfigManager config)
{
if (mods == null)

View File

@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.UI
public class GameplayCursorContainer : CursorContainer
{
/// <summary>
/// Because Show/Hide are executed by a parent, <see cref="State"/> is updated immediately even if the cursor
/// Because Show/Hide are executed by a parent, <see cref="VisibilityContainer.State"/> is updated immediately even if the cursor
/// is in a non-updating state (via <see cref="FrameStabilityContainer"/> limitations).
///
/// This holds the true visibility value.

View File

@ -100,7 +100,6 @@ namespace osu.Game.Rulesets.UI
/// <summary>
/// Provide an optional cursor which is to be used for gameplay.
/// If providing a cursor, <see cref="CursorTargetContainer"/> must also point to a valid target container.
/// </summary>
/// <returns>The cursor, or null if a cursor is not rqeuired.</returns>
protected virtual GameplayCursorContainer CreateCursor() => null;

View File

@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
/// <param name="currentTime">The current time.</param>
/// <param name="timeRange">The amount of visible time.</param>
/// <param name="scrollLength">The absolute spatial length through <see cref="timeRange"/>.</param>
/// <returns>The time at which <see cref="PositionAt(t)"/> == <paramref name="position"/>.</returns>
/// <returns>The time at which <see cref="PositionAt(double,double,double,float)"/> == <paramref name="position"/>.</returns>
double TimeAt(float position, double currentTime, double timeRange, float scrollLength);
/// <summary>

View File

@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential;
/// <summary>
/// Whether the player can change <see cref="VisibleTimeRange"/>.
/// Whether the player can change <see cref="TimeRange"/>.
/// </summary>
protected virtual bool UserScrollSpeedAdjustment => true;