mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 16:32:54 +08:00
Merge remote-tracking branch 'origin/master' into mask-separation
# Conflicts: # osu.Game.Rulesets.Osu/Edit/Layers/Selection/Overlays/SliderMask.cs
This commit is contained in:
commit
5712a52817
@ -5,13 +5,11 @@ using System.Collections.Generic;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
{
|
{
|
||||||
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToRulesetContainer<ManiaHitObject>
|
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter, IApplicableToBeatmap<ManiaHitObject>
|
||||||
{
|
{
|
||||||
public override string Name => "Dual Stages";
|
public override string Name => "Dual Stages";
|
||||||
public override string ShortenedName => "DS";
|
public override string ShortenedName => "DS";
|
||||||
@ -34,22 +32,21 @@ namespace osu.Game.Rulesets.Mania.Mods
|
|||||||
mbc.TargetColumns *= 2;
|
mbc.TargetColumns *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
public void ApplyToBeatmap(Beatmap<ManiaHitObject> beatmap)
|
||||||
{
|
{
|
||||||
var mrc = (ManiaRulesetContainer)rulesetContainer;
|
|
||||||
|
|
||||||
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
|
||||||
if (isForCurrentRuleset)
|
if (isForCurrentRuleset)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var maniaBeatmap = (ManiaBeatmap)beatmap;
|
||||||
|
|
||||||
var newDefinitions = new List<StageDefinition>();
|
var newDefinitions = new List<StageDefinition>();
|
||||||
foreach (var existing in mrc.Beatmap.Stages)
|
foreach (var existing in maniaBeatmap.Stages)
|
||||||
{
|
{
|
||||||
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
||||||
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
mrc.Beatmap.Stages = newDefinitions;
|
maniaBeatmap.Stages = newDefinitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayfieldType PlayfieldType => PlayfieldType.Dual;
|
public PlayfieldType PlayfieldType => PlayfieldType.Dual;
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public readonly DrawableHitCircle HeadCircle;
|
public readonly DrawableHitCircle HeadCircle;
|
||||||
public readonly DrawableSliderTail TailCircle;
|
public readonly DrawableSliderTail TailCircle;
|
||||||
|
|
||||||
public readonly SliderBody Body;
|
public readonly SnakingSliderBody Body;
|
||||||
public readonly SliderBall Ball;
|
public readonly SliderBall Ball;
|
||||||
|
|
||||||
public DrawableSlider(Slider s)
|
public DrawableSlider(Slider s)
|
||||||
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
Body = new SliderBody(s)
|
Body = new SnakingSliderBody(s)
|
||||||
{
|
{
|
||||||
PathWidth = s.Scale * 64,
|
PathWidth = s.Scale * 64,
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="SliderBody"/> with the ability to set the drawn vertices manually.
|
||||||
|
/// </summary>
|
||||||
|
public class ManualSliderBody : SliderBody
|
||||||
|
{
|
||||||
|
public new void SetVertices(IReadOnlyList<Vector2> vertices)
|
||||||
|
{
|
||||||
|
base.SetVertices(vertices);
|
||||||
|
Size = Path.Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
{
|
{
|
||||||
public class NumberPiece : Container
|
public class NumberPiece : Container
|
||||||
{
|
{
|
||||||
private readonly SpriteText number;
|
private readonly SkinnableSpriteText number;
|
||||||
|
|
||||||
public string Text
|
public string Text
|
||||||
{
|
{
|
||||||
@ -41,15 +40,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
},
|
},
|
||||||
Child = new Box()
|
Child = new Box()
|
||||||
}, s => s.GetTexture("Play/osu/hitcircle") == null),
|
}, s => s.GetTexture("Play/osu/hitcircle") == null),
|
||||||
number = new OsuSpriteText
|
number = new SkinnableSpriteText("Play/osu/number-text", _ => new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = @"1",
|
|
||||||
Font = @"Venera",
|
Font = @"Venera",
|
||||||
UseFullGlyphHeight = false,
|
UseFullGlyphHeight = false,
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
TextSize = 40,
|
TextSize = 40,
|
||||||
Alpha = 1
|
}, restrictSize: false)
|
||||||
|
{
|
||||||
|
Text = @"1"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,22 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Lines;
|
using osu.Framework.Graphics.Lines;
|
||||||
using OpenTK.Graphics.ES30;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using OpenTK.Graphics.ES30;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
{
|
{
|
||||||
public class SliderBody : Container, ISliderProgress
|
public abstract class SliderBody : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly SliderPath path;
|
private readonly SliderPath path;
|
||||||
|
protected Path Path => path;
|
||||||
|
|
||||||
private readonly BufferedContainer container;
|
private readonly BufferedContainer container;
|
||||||
|
|
||||||
public float PathWidth
|
public float PathWidth
|
||||||
@ -30,15 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Offset in absolute coordinates from the start of the curve.
|
/// Offset in absolute coordinates from the start of the curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector2 PathOffset { get; private set; }
|
public virtual Vector2 PathOffset => path.PositionInBoundingBox(path.Vertices[0]);
|
||||||
|
|
||||||
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
|
|
||||||
|
|
||||||
public readonly Bindable<bool> SnakingIn = new Bindable<bool>();
|
|
||||||
public readonly Bindable<bool> SnakingOut = new Bindable<bool>();
|
|
||||||
|
|
||||||
public double? SnakedStart { get; private set; }
|
|
||||||
public double? SnakedEnd { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to colour the path.
|
/// Used to colour the path.
|
||||||
@ -74,28 +64,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
public Quad PathDrawQuad => container.ScreenSpaceDrawQuad;
|
public Quad PathDrawQuad => container.ScreenSpaceDrawQuad;
|
||||||
|
|
||||||
private Vector2 topLeftOffset;
|
protected SliderBody()
|
||||||
|
|
||||||
private readonly Slider slider;
|
|
||||||
|
|
||||||
public SliderBody(Slider s)
|
|
||||||
{
|
{
|
||||||
slider = s;
|
InternalChild = container = new BufferedContainer
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
container = new BufferedContainer
|
RelativeSizeAxes = Axes.Both,
|
||||||
{
|
CacheDrawnFrameBuffer = true,
|
||||||
RelativeSizeAxes = Axes.Both,
|
Child = path = new SliderPath { Blending = BlendingMode.None }
|
||||||
CacheDrawnFrameBuffer = true,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
path = new SliderPath
|
|
||||||
{
|
|
||||||
Blending = BlendingMode.None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
container.Attach(RenderbufferInternalFormat.DepthComponent16);
|
container.Attach(RenderbufferInternalFormat.DepthComponent16);
|
||||||
@ -103,80 +78,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => path.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
public void SetRange(double p0, double p1)
|
/// <summary>
|
||||||
|
/// Sets the vertices of the path which should be drawn by this <see cref="SliderBody"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertices">The vertices</param>
|
||||||
|
protected void SetVertices(IReadOnlyList<Vector2> vertices)
|
||||||
{
|
{
|
||||||
if (p0 > p1)
|
path.Vertices = vertices;
|
||||||
MathHelper.Swap(ref p0, ref p1);
|
container.ForceRedraw();
|
||||||
|
|
||||||
if (updateSnaking(p0, p1))
|
|
||||||
{
|
|
||||||
// The path is generated such that its size encloses it. This change of size causes the path
|
|
||||||
// to move around while snaking, so we need to offset it to make sure it maintains the
|
|
||||||
// same position as when it is fully snaked.
|
|
||||||
var newTopLeftOffset = path.PositionInBoundingBox(Vector2.Zero);
|
|
||||||
path.Position = topLeftOffset - newTopLeftOffset;
|
|
||||||
|
|
||||||
container.ForceRedraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
computeSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void computeSize()
|
|
||||||
{
|
|
||||||
// Generate the entire curve
|
|
||||||
slider.Curve.GetPathToProgress(CurrentCurve, 0, 1);
|
|
||||||
foreach (Vector2 p in CurrentCurve)
|
|
||||||
path.AddVertex(p);
|
|
||||||
|
|
||||||
Size = path.Size;
|
|
||||||
|
|
||||||
topLeftOffset = path.PositionInBoundingBox(Vector2.Zero);
|
|
||||||
PathOffset = path.PositionInBoundingBox(CurrentCurve[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool updateSnaking(double p0, double p1)
|
|
||||||
{
|
|
||||||
if (SnakedStart == p0 && SnakedEnd == p1) return false;
|
|
||||||
|
|
||||||
SnakedStart = p0;
|
|
||||||
SnakedEnd = p1;
|
|
||||||
|
|
||||||
slider.Curve.GetPathToProgress(CurrentCurve, p0, p1);
|
|
||||||
|
|
||||||
path.ClearVertices();
|
|
||||||
foreach (Vector2 p in CurrentCurve)
|
|
||||||
path.AddVertex(p);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateProgress(double completionProgress)
|
|
||||||
{
|
|
||||||
var span = slider.SpanAt(completionProgress);
|
|
||||||
var spanProgress = slider.ProgressAt(completionProgress);
|
|
||||||
|
|
||||||
double start = 0;
|
|
||||||
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
|
|
||||||
|
|
||||||
if (span >= slider.SpanCount() - 1)
|
|
||||||
{
|
|
||||||
if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1)
|
|
||||||
{
|
|
||||||
start = 0;
|
|
||||||
end = SnakingOut ? spanProgress : 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
start = SnakingOut ? spanProgress : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SetRange(start, end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SliderPath : SmoothPath
|
private class SliderPath : SmoothPath
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="SliderBody"/> which changes its curve depending on the snaking progress.
|
||||||
|
/// </summary>
|
||||||
|
public class SnakingSliderBody : SliderBody, ISliderProgress
|
||||||
|
{
|
||||||
|
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
|
||||||
|
|
||||||
|
public readonly Bindable<bool> SnakingIn = new Bindable<bool>();
|
||||||
|
public readonly Bindable<bool> SnakingOut = new Bindable<bool>();
|
||||||
|
|
||||||
|
public double? SnakedStart { get; private set; }
|
||||||
|
public double? SnakedEnd { get; private set; }
|
||||||
|
|
||||||
|
public override Vector2 PathOffset => snakedPathOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The top-left position of the path when fully snaked.
|
||||||
|
/// </summary>
|
||||||
|
private Vector2 snakedPosition;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The offset of the path from <see cref="snakedPosition"/> when fully snaked.
|
||||||
|
/// </summary>
|
||||||
|
private Vector2 snakedPathOffset;
|
||||||
|
|
||||||
|
private readonly Slider slider;
|
||||||
|
|
||||||
|
public SnakingSliderBody(Slider slider)
|
||||||
|
{
|
||||||
|
this.slider = slider;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
// Generate the entire curve
|
||||||
|
slider.Curve.GetPathToProgress(CurrentCurve, 0, 1);
|
||||||
|
SetVertices(CurrentCurve);
|
||||||
|
|
||||||
|
// The body is sized to the full path size to avoid excessive autosize computations
|
||||||
|
Size = Path.Size;
|
||||||
|
|
||||||
|
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
|
||||||
|
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateProgress(double completionProgress)
|
||||||
|
{
|
||||||
|
var span = slider.SpanAt(completionProgress);
|
||||||
|
var spanProgress = slider.ProgressAt(completionProgress);
|
||||||
|
|
||||||
|
double start = 0;
|
||||||
|
double end = SnakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadeIn, 0, 1) : 1;
|
||||||
|
|
||||||
|
if (span >= slider.SpanCount() - 1)
|
||||||
|
{
|
||||||
|
if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1)
|
||||||
|
{
|
||||||
|
start = 0;
|
||||||
|
end = SnakingOut ? spanProgress : 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start = SnakingOut ? spanProgress : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRange(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRange(double p0, double p1)
|
||||||
|
{
|
||||||
|
if (p0 > p1)
|
||||||
|
MathHelper.Swap(ref p0, ref p1);
|
||||||
|
|
||||||
|
if (SnakedStart == p0 && SnakedEnd == p1) return;
|
||||||
|
|
||||||
|
SnakedStart = p0;
|
||||||
|
SnakedEnd = p1;
|
||||||
|
|
||||||
|
slider.Curve.GetPathToProgress(CurrentCurve, p0, p1);
|
||||||
|
|
||||||
|
SetVertices(CurrentCurve);
|
||||||
|
|
||||||
|
// The bounding box of the path expands as it snakes, which in turn shifts the position of the path.
|
||||||
|
// Depending on the direction of expansion, it may appear as if the path is expanding towards the position of the slider
|
||||||
|
// rather than expanding out from the position of the slider.
|
||||||
|
// To remove this effect, the path's position is shifted towards its final snaked position
|
||||||
|
|
||||||
|
Path.Position = snakedPosition - Path.PositionInBoundingBox(Vector2.Zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs
Normal file
22
osu.Game/Rulesets/Mods/IApplicableToBeatmap.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
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="Beatmap"/>
|
||||||
|
/// after conversion and post-processing has completed.
|
||||||
|
/// </summary>
|
||||||
|
public interface IApplicableToBeatmap<TObject> : IApplicableMod
|
||||||
|
where TObject : HitObject
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Applies this <see cref="IApplicableToBeatmap{TObject}"/> to a <see cref="Beatmap{TObject}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The <see cref="Beatmap{TObject}"/> to apply to.</param>
|
||||||
|
void ApplyToBeatmap(Beatmap<TObject> beatmap);
|
||||||
|
}
|
||||||
|
}
|
@ -238,6 +238,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
KeyBindingInputManager = CreateInputManager();
|
KeyBindingInputManager = CreateInputManager();
|
||||||
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
applyBeatmapMods(Mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -255,16 +257,29 @@ namespace osu.Game.Rulesets.UI
|
|||||||
KeyBindingInputManager.Add(Cursor);
|
KeyBindingInputManager.Add(Cursor);
|
||||||
|
|
||||||
// Apply mods
|
// Apply mods
|
||||||
applyMods(Mods, config);
|
applyRulesetMods(Mods, config);
|
||||||
|
|
||||||
loadObjects();
|
loadObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the active mods to the Beatmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mods"></param>
|
||||||
|
private void applyBeatmapMods(IEnumerable<Mod> mods)
|
||||||
|
{
|
||||||
|
if (mods == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var mod in mods.OfType<IApplicableToBeatmap<TObject>>())
|
||||||
|
mod.ApplyToBeatmap(Beatmap);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the active mods to this RulesetContainer.
|
/// Applies the active mods to this RulesetContainer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="mods"></param>
|
/// <param name="mods"></param>
|
||||||
private void applyMods(IEnumerable<Mod> mods, OsuConfigManager config)
|
private void applyRulesetMods(IEnumerable<Mod> mods, OsuConfigManager config)
|
||||||
{
|
{
|
||||||
if (mods == null)
|
if (mods == null)
|
||||||
return;
|
return;
|
||||||
|
@ -307,10 +307,10 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
Alpha = 0;
|
|
||||||
|
|
||||||
InternalChild = textContainer = new FillFlowContainer
|
InternalChild = textContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
|
Alpha = 0,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Spacing = new Vector2(spacing / 2),
|
Spacing = new Vector2(spacing / 2),
|
||||||
@ -337,7 +337,7 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
this.FadeOut(transition_duration);
|
textContainer.FadeOut(transition_duration);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,8 +345,6 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsPresent => base.IsPresent || textFlow == null; // Visibility is updated in the LoadComponentAsync callback
|
|
||||||
|
|
||||||
private void setTextAsync(string text)
|
private void setTextAsync(string text)
|
||||||
{
|
{
|
||||||
LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14)
|
LoadComponentAsync(new OsuTextFlowContainer(s => s.TextSize = 14)
|
||||||
@ -361,7 +359,7 @@ namespace osu.Game.Screens.Select
|
|||||||
textContainer.Add(textFlow = loaded);
|
textContainer.Add(textFlow = loaded);
|
||||||
|
|
||||||
// fade in if we haven't yet.
|
// fade in if we haven't yet.
|
||||||
this.FadeIn(transition_duration);
|
textContainer.FadeIn(transition_duration);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Edit;
|
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -68,7 +67,7 @@ namespace osu.Game.Screens.Select
|
|||||||
BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () =>
|
BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.fa_pencil, colours.Yellow, () =>
|
||||||
{
|
{
|
||||||
ValidForResume = false;
|
ValidForResume = false;
|
||||||
Push(new Editor());
|
Edit();
|
||||||
}, Key.Number3);
|
}, Key.Number3);
|
||||||
|
|
||||||
if (dialogOverlay != null)
|
if (dialogOverlay != null)
|
||||||
|
@ -223,9 +223,9 @@ namespace osu.Game.Screens.Select
|
|||||||
Carousel.LoadBeatmapSetsFromManager(this.beatmaps);
|
Carousel.LoadBeatmapSetsFromManager(this.beatmaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Edit(BeatmapInfo beatmap)
|
public void Edit(BeatmapInfo beatmap = null)
|
||||||
{
|
{
|
||||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce);
|
||||||
Push(new Editor());
|
Push(new Editor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Skinning
|
namespace osu.Game.Skinning
|
||||||
@ -56,30 +57,39 @@ namespace osu.Game.Skinning
|
|||||||
case "Play/Great":
|
case "Play/Great":
|
||||||
componentName = "hit300";
|
componentName = "hit300";
|
||||||
break;
|
break;
|
||||||
|
case "Play/osu/number-text":
|
||||||
|
return !hasFont(Configuration.HitCircleFont) ? null : new LegacySpriteText(Textures, Configuration.HitCircleFont) { Scale = new Vector2(0.96f) };
|
||||||
}
|
}
|
||||||
|
|
||||||
float ratio = 0.72f; // brings sizing roughly in-line with stable
|
var texture = GetTexture(componentName);
|
||||||
|
|
||||||
var texture = GetTexture($"{componentName}@2x");
|
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
{
|
return null;
|
||||||
ratio *= 2;
|
|
||||||
texture = GetTexture(componentName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (texture == null) return null;
|
return new Sprite { Texture = texture };
|
||||||
|
|
||||||
return new Sprite
|
|
||||||
{
|
|
||||||
Texture = texture,
|
|
||||||
Scale = new Vector2(ratio),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Texture GetTexture(string componentName) => Textures.Get(componentName);
|
public override Texture GetTexture(string componentName)
|
||||||
|
{
|
||||||
|
float ratio = 2;
|
||||||
|
|
||||||
|
var texture = Textures.Get($"{componentName}@2x");
|
||||||
|
if (texture == null)
|
||||||
|
{
|
||||||
|
ratio = 1;
|
||||||
|
texture = Textures.Get(componentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
|
texture.ScaleAdjust = ratio / 0.72f; // brings sizing roughly in-line with stable
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName);
|
public override SampleChannel GetSample(string sampleName) => Samples.Get(sampleName);
|
||||||
|
|
||||||
|
private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null;
|
||||||
|
|
||||||
protected class LegacySkinResourceStore<T> : IResourceStore<byte[]>
|
protected class LegacySkinResourceStore<T> : IResourceStore<byte[]>
|
||||||
where T : INamedFileInfo
|
where T : INamedFileInfo
|
||||||
{
|
{
|
||||||
@ -142,5 +152,40 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class LegacySpriteText : OsuSpriteText
|
||||||
|
{
|
||||||
|
private readonly TextureStore textures;
|
||||||
|
private readonly string font;
|
||||||
|
|
||||||
|
public LegacySpriteText(TextureStore textures, string font)
|
||||||
|
{
|
||||||
|
this.textures = textures;
|
||||||
|
this.font = font;
|
||||||
|
|
||||||
|
Shadow = false;
|
||||||
|
UseFullGlyphHeight = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Texture GetTextureForCharacter(char c)
|
||||||
|
{
|
||||||
|
string textureName = $"{font}-{c}";
|
||||||
|
|
||||||
|
// Approximate value that brings character sizing roughly in-line with stable
|
||||||
|
float ratio = 36;
|
||||||
|
|
||||||
|
var texture = textures.Get($"{textureName}@2x");
|
||||||
|
if (texture == null)
|
||||||
|
{
|
||||||
|
ratio = 18;
|
||||||
|
texture = textures.Get(textureName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
|
texture.ScaleAdjust = ratio;
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ namespace osu.Game.Skinning
|
|||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
case Section.General:
|
case Section.General:
|
||||||
|
{
|
||||||
var pair = SplitKeyVal(line);
|
var pair = SplitKeyVal(line);
|
||||||
|
|
||||||
switch (pair.Key)
|
switch (pair.Key)
|
||||||
@ -32,6 +33,20 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case Section.Fonts:
|
||||||
|
{
|
||||||
|
var pair = SplitKeyVal(line);
|
||||||
|
|
||||||
|
switch (pair.Key)
|
||||||
|
{
|
||||||
|
case "HitCirclePrefix":
|
||||||
|
skin.HitCircleFont = pair.Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base.ParseLine(skin, section, line);
|
base.ParseLine(skin, section, line);
|
||||||
|
@ -14,5 +14,7 @@ namespace osu.Game.Skinning
|
|||||||
public List<Color4> ComboColours { get; set; } = new List<Color4>();
|
public List<Color4> ComboColours { get; set; } = new List<Color4>();
|
||||||
|
|
||||||
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
||||||
|
|
||||||
|
public string HitCircleFont { get; set; } = "default";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,11 @@ namespace osu.Game.Skinning
|
|||||||
public class SkinnableDrawable<T> : SkinReloadableDrawable
|
public class SkinnableDrawable<T> : SkinReloadableDrawable
|
||||||
where T : Drawable
|
where T : Drawable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The displayed component. May or may not be a type-<typeparamref name="T"/> member.
|
||||||
|
/// </summary>
|
||||||
|
protected Drawable Drawable { get; private set; }
|
||||||
|
|
||||||
private readonly Func<string, T> createDefault;
|
private readonly Func<string, T> createDefault;
|
||||||
|
|
||||||
private readonly string componentName;
|
private readonly string componentName;
|
||||||
@ -31,7 +36,8 @@ namespace osu.Game.Skinning
|
|||||||
/// <param name="defaultImplementation">A function to create the default skin implementation of this element.</param>
|
/// <param name="defaultImplementation">A function to create the default skin implementation of this element.</param>
|
||||||
/// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
|
/// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
|
||||||
/// <param name="restrictSize">Whether a user-skin drawable should be limited to the size of our parent.</param>
|
/// <param name="restrictSize">Whether a user-skin drawable should be limited to the size of our parent.</param>
|
||||||
public SkinnableDrawable(string name, Func<string, T> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true) : base(allowFallback)
|
public SkinnableDrawable(string name, Func<string, T> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
||||||
|
: base(allowFallback)
|
||||||
{
|
{
|
||||||
componentName = name;
|
componentName = name;
|
||||||
createDefault = defaultImplementation;
|
createDefault = defaultImplementation;
|
||||||
@ -42,26 +48,27 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||||
{
|
{
|
||||||
var drawable = skin.GetDrawableComponent(componentName);
|
Drawable = skin.GetDrawableComponent(componentName);
|
||||||
if (drawable != null)
|
|
||||||
|
if (Drawable != null)
|
||||||
{
|
{
|
||||||
if (restrictSize)
|
if (restrictSize)
|
||||||
{
|
{
|
||||||
drawable.RelativeSizeAxes = Axes.Both;
|
Drawable.RelativeSizeAxes = Axes.Both;
|
||||||
drawable.Size = Vector2.One;
|
Drawable.Size = Vector2.One;
|
||||||
drawable.Scale = Vector2.One;
|
Drawable.Scale = Vector2.One;
|
||||||
drawable.FillMode = FillMode.Fit;
|
Drawable.FillMode = FillMode.Fit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (allowFallback)
|
else if (allowFallback)
|
||||||
drawable = createDefault(componentName);
|
Drawable = createDefault(componentName);
|
||||||
|
|
||||||
if (drawable != null)
|
if (Drawable != null)
|
||||||
{
|
{
|
||||||
drawable.Origin = Anchor.Centre;
|
Drawable.Origin = Anchor.Centre;
|
||||||
drawable.Anchor = Anchor.Centre;
|
Drawable.Anchor = Anchor.Centre;
|
||||||
|
|
||||||
InternalChild = drawable;
|
InternalChild = Drawable;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ClearInternal();
|
ClearInternal();
|
||||||
|
40
osu.Game/Skinning/SkinnableSpriteText.cs
Normal file
40
osu.Game/Skinning/SkinnableSpriteText.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
|
||||||
|
namespace osu.Game.Skinning
|
||||||
|
{
|
||||||
|
public class SkinnableSpriteText : SkinnableDrawable<SpriteText>, IHasText
|
||||||
|
{
|
||||||
|
public SkinnableSpriteText(string name, Func<string, SpriteText> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
||||||
|
: base(name, defaultImplementation, allowFallback, restrictSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||||
|
{
|
||||||
|
base.SkinChanged(skin, allowFallback);
|
||||||
|
|
||||||
|
if (Drawable is IHasText textDrawable)
|
||||||
|
textDrawable.Text = Text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string text;
|
||||||
|
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get => text;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (text == value)
|
||||||
|
return;
|
||||||
|
text = value;
|
||||||
|
|
||||||
|
if (Drawable is IHasText textDrawable)
|
||||||
|
textDrawable.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.4" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2018.1018.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2018.1030.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user