mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 15:47:26 +08:00
Merge branch 'master' into fix-memory-leak
This commit is contained in:
commit
4aecd59c74
@ -1 +1 @@
|
||||
Subproject commit b64322a56d3d55e8e5d1e6c3328024923cecd4d3
|
||||
Subproject commit 06f9c47ef5d007b39faf8169170d16ece672b981
|
@ -158,7 +158,7 @@ namespace osu.Desktop.VisualTests.Tests
|
||||
|
||||
AddButton(@"Alter stars", delegate
|
||||
{
|
||||
stars.Count = RNG.NextSingle() * (stars.MaxStars + 1);
|
||||
stars.Count = RNG.NextSingle() * (stars.StarCount + 1);
|
||||
starsLabel.Text = stars.Count.ToString("0.00");
|
||||
});
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Modes.Catch
|
||||
|
||||
protected override HitObjectConverter<CatchBaseHit> Converter => new CatchConverter();
|
||||
|
||||
protected override double ComputeDifficulty(Dictionary<String, String> categoryDifficulty)
|
||||
protected override double CalculateInternal(Dictionary<String, String> categoryDifficulty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Modes.Mania
|
||||
|
||||
protected override HitObjectConverter<ManiaBaseHit> Converter => new ManiaConverter(columns);
|
||||
|
||||
protected override double ComputeDifficulty(Dictionary<String, String> categoryDifficulty)
|
||||
protected override double CalculateInternal(Dictionary<String, String> categoryDifficulty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,27 +29,22 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
case CurveTypes.Linear:
|
||||
return subControlPoints;
|
||||
case CurveTypes.PerfectCurve:
|
||||
// If we have a different amount than 3 control points, use bezier for perfect curves.
|
||||
if (ControlPoints.Count != 3)
|
||||
return new BezierApproximator(subControlPoints).CreateBezier();
|
||||
else
|
||||
{
|
||||
Debug.Assert(subControlPoints.Count == 3);
|
||||
//we can only use CircularArc iff we have exactly three control points and no dissection.
|
||||
if (ControlPoints.Count != 3 || subControlPoints.Count != 3)
|
||||
break;
|
||||
|
||||
// Here we have exactly 3 control points. Attempt to fit a circular arc.
|
||||
List<Vector2> subpath = new CircularArcApproximator(subControlPoints[0], subControlPoints[1], subControlPoints[2]).CreateArc();
|
||||
|
||||
// If for some reason a circular arc could not be fit to the 3 given points, fall back to a numerically stable bezier approximation.
|
||||
if (subpath.Count == 0)
|
||||
// For some reason a circular arc could not be fit to the 3 given points. Fall back
|
||||
// to a numerically stable bezier approximation.
|
||||
subpath = new BezierApproximator(subControlPoints).CreateBezier();
|
||||
break;
|
||||
|
||||
return subpath;
|
||||
}
|
||||
default:
|
||||
|
||||
return new BezierApproximator(subControlPoints).CreateBezier();
|
||||
}
|
||||
}
|
||||
|
||||
private void calculatePath()
|
||||
{
|
||||
@ -181,7 +176,7 @@ namespace osu.Game.Modes.Osu.Objects
|
||||
path.Clear();
|
||||
|
||||
int i = 0;
|
||||
for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i);
|
||||
for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) ;
|
||||
|
||||
path.Add(interpolateVertices(i, d0) + Offset);
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Modes.Osu
|
||||
((Slider)h).Curve.Calculate();
|
||||
}
|
||||
|
||||
protected override double ComputeDifficulty(Dictionary<String, String> categoryDifficulty)
|
||||
protected override double CalculateInternal(Dictionary<String, String> categoryDifficulty)
|
||||
{
|
||||
// Fill our custom DifficultyHitObject class, that carries additional information
|
||||
DifficultyHitObjects.Clear();
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Modes.Taiko
|
||||
|
||||
protected override HitObjectConverter<TaikoBaseHit> Converter => new TaikoConverter();
|
||||
|
||||
protected override double ComputeDifficulty(Dictionary<String, String> categoryDifficulty)
|
||||
protected override double CalculateInternal(Dictionary<String, String> categoryDifficulty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Modes.Objects;
|
||||
using osu.Game.Modes;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@ -57,5 +58,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
return timingPoint ?? ControlPoint.Default;
|
||||
}
|
||||
|
||||
public double CalculateStarDifficulty() => Ruleset.GetRuleset(BeatmapInfo.Mode).CreateDifficultyCalculator(this).Calculate();
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
protected double TimeRate = 1;
|
||||
|
||||
protected abstract double ComputeDifficulty(Dictionary<String, String> categoryDifficulty);
|
||||
protected abstract double CalculateInternal(Dictionary<String, String> categoryDifficulty);
|
||||
|
||||
private void loadTiming()
|
||||
{
|
||||
@ -23,10 +23,10 @@ namespace osu.Game.Beatmaps
|
||||
TimeRate = audioRate / 100.0;
|
||||
}
|
||||
|
||||
public double GetDifficulty(Dictionary<string, string> categoryDifficulty = null)
|
||||
public double Calculate(Dictionary<string, string> categoryDifficulty = null)
|
||||
{
|
||||
loadTiming();
|
||||
double difficulty = ComputeDifficulty(categoryDifficulty);
|
||||
double difficulty = CalculateInternal(categoryDifficulty);
|
||||
return difficulty;
|
||||
}
|
||||
}
|
||||
|
@ -59,16 +59,21 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapGroup(WorkingBeatmap beatmap)
|
||||
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapDatabase database)
|
||||
{
|
||||
BeatmapSet = beatmapSet;
|
||||
WorkingBeatmap beatmap = database.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||
foreach (var b in BeatmapSet.Beatmaps)
|
||||
b.StarDifficulty = (float)database.GetWorkingBeatmap(b).Beatmap.CalculateStarDifficulty();
|
||||
|
||||
Header = new BeatmapSetHeader(beatmap)
|
||||
{
|
||||
GainedSelection = headerGainedSelection,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
};
|
||||
|
||||
BeatmapSet = beatmap.BeatmapSetInfo;
|
||||
BeatmapPanels = beatmap.BeatmapSetInfo.Beatmaps.Select(b => new BeatmapPanel(b)
|
||||
BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.OrderBy(b => b.StarDifficulty).ToList();
|
||||
BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b)
|
||||
{
|
||||
Alpha = 0,
|
||||
GainedSelection = panelGainedSelection,
|
||||
|
@ -26,6 +26,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
public Action<BeatmapPanel> GainedSelection;
|
||||
public Action<BeatmapPanel> StartRequested;
|
||||
private Triangles triangles;
|
||||
private StarCounter starCounter;
|
||||
|
||||
protected override void Selected()
|
||||
{
|
||||
@ -56,6 +57,14 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
protected override void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden)
|
||||
{
|
||||
base.ApplyState(last);
|
||||
|
||||
if (last == PanelSelectedState.Hidden && State != last)
|
||||
starCounter.ReplayAnimation();
|
||||
}
|
||||
|
||||
public BeatmapPanel(BeatmapInfo beatmap)
|
||||
{
|
||||
Beatmap = beatmap;
|
||||
@ -92,7 +101,6 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
new FlowContainer
|
||||
{
|
||||
Padding = new MarginPadding { Left = 5 },
|
||||
Spacing = new Vector2(0, 5),
|
||||
Direction = FlowDirections.Vertical,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
@ -130,7 +138,11 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
},
|
||||
}
|
||||
},
|
||||
new StarCounter { Count = beatmap.StarDifficulty, StarSize = 8 }
|
||||
starCounter = new StarCounter
|
||||
{
|
||||
Count = beatmap.StarDifficulty,
|
||||
Scale = new Vector2(0.8f),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,10 +50,10 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
applyState();
|
||||
ApplyState();
|
||||
}
|
||||
|
||||
private void applyState()
|
||||
protected virtual void ApplyState(PanelSelectedState last = PanelSelectedState.Hidden)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
@ -81,9 +81,10 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
set
|
||||
{
|
||||
if (state == value) return;
|
||||
state = value;
|
||||
|
||||
applyState();
|
||||
var last = state;
|
||||
state = value;
|
||||
ApplyState(last);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,10 +119,6 @@ namespace osu.Game.Database
|
||||
using (var reader = ArchiveReader.GetReader(storage, path))
|
||||
metadata = reader.ReadMetadata();
|
||||
|
||||
if (metadata.OnlineBeatmapSetID.HasValue &&
|
||||
connection.Table<BeatmapSetInfo>().Count(b => b.OnlineBeatmapSetID == metadata.OnlineBeatmapSetID) != 0)
|
||||
return; // TODO: Update this beatmap instead
|
||||
|
||||
if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader
|
||||
{
|
||||
using (var md5 = MD5.Create())
|
||||
@ -131,10 +127,26 @@ namespace osu.Game.Database
|
||||
hash = BitConverter.ToString(md5.ComputeHash(input)).Replace("-", "").ToLowerInvariant();
|
||||
input.Seek(0, SeekOrigin.Begin);
|
||||
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
|
||||
if (!storage.Exists(path))
|
||||
using (var output = storage.GetStream(path, FileAccess.Write))
|
||||
input.CopyTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
var existing = connection.Table<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
if (existing.DeletePending)
|
||||
{
|
||||
existing.DeletePending = false;
|
||||
Update(existing, false);
|
||||
BeatmapSetAdded?.Invoke(existing);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var beatmapSet = new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = metadata.OnlineBeatmapSetID,
|
||||
|
@ -73,7 +73,6 @@ namespace osu.Game.Database
|
||||
// Metadata
|
||||
public string Version { get; set; }
|
||||
|
||||
//todo: background threaded computation of this
|
||||
private float starDifficulty = -1;
|
||||
public float StarDifficulty
|
||||
{
|
||||
@ -85,11 +84,6 @@ namespace osu.Game.Database
|
||||
set { starDifficulty = value; }
|
||||
}
|
||||
|
||||
internal void ComputeDifficulty(BeatmapDatabase database)
|
||||
{
|
||||
StarDifficulty = (float)Ruleset.GetRuleset(Mode).CreateDifficultyCalculator(database.GetWorkingBeatmap(this).Beatmap).GetDifficulty();
|
||||
}
|
||||
|
||||
public bool Equals(BeatmapInfo other)
|
||||
{
|
||||
return ID == other?.ID;
|
||||
|
@ -7,16 +7,14 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Transformations;
|
||||
using osu.Framework.MathUtils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class StarCounter : Container
|
||||
{
|
||||
private readonly Container starContainer;
|
||||
private readonly List<TextAwesome> stars = new List<TextAwesome>();
|
||||
private readonly Container<Star> stars;
|
||||
|
||||
private double transformStartTime = 0;
|
||||
private double transformStartTime;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum amount of stars displayed.
|
||||
@ -24,37 +22,20 @@ namespace osu.Game.Graphics.UserInterface
|
||||
/// <remarks>
|
||||
/// This does not limit the counter value, but the amount of stars displayed.
|
||||
/// </remarks>
|
||||
public int MaxStars
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
public int StarCount { get; }
|
||||
|
||||
private double animationDelay => 80;
|
||||
|
||||
private double scalingDuration => 500;
|
||||
private double scalingDuration => 1000;
|
||||
private EasingTypes scalingEasing => EasingTypes.OutElasticHalf;
|
||||
private float minStarScale => 0.3f;
|
||||
private float minStarScale => 0.4f;
|
||||
|
||||
private double fadingDuration => 100;
|
||||
private float minStarAlpha => 0.5f;
|
||||
|
||||
public float StarSize = 20;
|
||||
public float StarSpacing = 4;
|
||||
private const float star_size = 20;
|
||||
private float star_spacing = 4;
|
||||
|
||||
public float VisibleValue
|
||||
{
|
||||
get
|
||||
{
|
||||
double elapsedTime = Time.Current - transformStartTime;
|
||||
double expectedElapsedTime = Math.Abs(prevCount - count) * animationDelay;
|
||||
if (elapsedTime >= expectedElapsedTime)
|
||||
return count;
|
||||
return Interpolation.ValueAt(elapsedTime, prevCount, count, 0, expectedElapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
private float prevCount;
|
||||
private float count;
|
||||
|
||||
/// <summary>
|
||||
@ -69,119 +50,121 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
set
|
||||
{
|
||||
if (IsLoaded)
|
||||
{
|
||||
prevCount = VisibleValue;
|
||||
transformCount(prevCount, value);
|
||||
}
|
||||
if (count == value) return;
|
||||
|
||||
if (IsLoaded)
|
||||
transformCount(value);
|
||||
count = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a float count as stars (up to 10). Used as star difficulty display.
|
||||
/// </summary>
|
||||
public StarCounter() : this(10)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows a float count as stars. Used as star difficulty display.
|
||||
/// </summary>
|
||||
/// <param name="maxstars">Maximum amount of stars to display.</param>
|
||||
public StarCounter(int maxstars)
|
||||
/// <param name="starCount">Maximum amount of stars to display.</param>
|
||||
public StarCounter(int starCount = 10)
|
||||
{
|
||||
MaxStars = Math.Max(maxstars, 0);
|
||||
StarCount = Math.Max(starCount, 0);
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
starContainer = new Container
|
||||
stars = new FlowContainer<Star>
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FlowDirections.Horizontal,
|
||||
Spacing = new Vector2(star_spacing),
|
||||
}
|
||||
};
|
||||
|
||||
starContainer.Width = MaxStars * StarSize + Math.Max(MaxStars - 1, 0) * StarSpacing;
|
||||
starContainer.Height = StarSize;
|
||||
|
||||
for (int i = 0; i < MaxStars; i++)
|
||||
for (int i = 0; i < StarCount; i++)
|
||||
{
|
||||
TextAwesome star = new TextAwesome
|
||||
stars.Add(new Star
|
||||
{
|
||||
Icon = FontAwesome.fa_star,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
TextSize = StarSize,
|
||||
Scale = new Vector2(minStarScale),
|
||||
Alpha = minStarAlpha,
|
||||
Position = new Vector2((StarSize + StarSpacing) * i + (StarSize + StarSpacing) / 2, 0),
|
||||
};
|
||||
|
||||
//todo: user Container<T> once we have it.
|
||||
stars.Add(star);
|
||||
starContainer.Add(star);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// Animate initial state from zero.
|
||||
transformCount(0, Count);
|
||||
ReplayAnimation();
|
||||
}
|
||||
|
||||
public void ResetCount()
|
||||
{
|
||||
Count = 0;
|
||||
count = 0;
|
||||
StopAnimation();
|
||||
}
|
||||
|
||||
public void ReplayAnimation()
|
||||
{
|
||||
var t = count;
|
||||
ResetCount();
|
||||
Count = t;
|
||||
}
|
||||
|
||||
public void StopAnimation()
|
||||
{
|
||||
prevCount = count;
|
||||
transformStartTime = Time.Current;
|
||||
|
||||
for (int i = 0; i < MaxStars; i++)
|
||||
transformStarQuick(i, count);
|
||||
int i = 0;
|
||||
foreach (var star in stars.Children)
|
||||
{
|
||||
star.ClearTransformations(true);
|
||||
star.FadeTo(i < count ? 1.0f : minStarAlpha);
|
||||
star.Icon.ScaleTo(getStarScale(i, count));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private float getStarScale(int i, float value)
|
||||
{
|
||||
if (value <= i)
|
||||
return minStarScale;
|
||||
if (i + 1 <= value)
|
||||
return 1.0f;
|
||||
return Interpolation.ValueAt(value, minStarScale, 1.0f, i, i + 1);
|
||||
|
||||
return i + 1 <= value ? 1.0f : Interpolation.ValueAt(value, minStarScale, 1.0f, i, i + 1);
|
||||
}
|
||||
|
||||
private void transformStar(int i, float value)
|
||||
private void transformCount(float newValue)
|
||||
{
|
||||
stars[i].FadeTo(i < value ? 1.0f : minStarAlpha, fadingDuration);
|
||||
stars[i].ScaleTo(getStarScale(i, value), scalingDuration, scalingEasing);
|
||||
}
|
||||
|
||||
private void transformStarQuick(int i, float value)
|
||||
int i = 0;
|
||||
foreach (var star in stars.Children)
|
||||
{
|
||||
stars[i].FadeTo(i < value ? 1.0f : minStarAlpha);
|
||||
stars[i].ScaleTo(getStarScale(i, value));
|
||||
}
|
||||
|
||||
private void transformCount(float currentValue, float newValue)
|
||||
{
|
||||
for (int i = 0; i < MaxStars; i++)
|
||||
{
|
||||
stars[i].ClearTransformations();
|
||||
if (currentValue <= newValue)
|
||||
stars[i].Delay(Math.Max(i - currentValue, 0) * animationDelay);
|
||||
star.ClearTransformations(true);
|
||||
if (count <= newValue)
|
||||
star.Delay(Math.Max(i - count, 0) * animationDelay, true);
|
||||
else
|
||||
stars[i].Delay(Math.Max(currentValue - 1 - i, 0) * animationDelay);
|
||||
transformStar(i, newValue);
|
||||
stars[i].DelayReset();
|
||||
star.Delay(Math.Max(count - 1 - i, 0) * animationDelay, true);
|
||||
|
||||
star.FadeTo(i < newValue ? 1.0f : minStarAlpha, fadingDuration);
|
||||
star.Icon.ScaleTo(getStarScale(i, newValue), scalingDuration, scalingEasing);
|
||||
star.DelayReset();
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
class Star : Container
|
||||
{
|
||||
public TextAwesome Icon;
|
||||
public Star()
|
||||
{
|
||||
Size = new Vector2(star_size);
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
Icon = new TextAwesome
|
||||
{
|
||||
TextSize = star_size,
|
||||
Icon = FontAwesome.fa_star,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
}
|
||||
transformStartTime = Time.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -325,11 +325,7 @@ namespace osu.Game.Screens.Select
|
||||
if (b.Metadata == null) b.Metadata = beatmapSet.Metadata;
|
||||
});
|
||||
|
||||
foreach (var b in beatmapSet.Beatmaps)
|
||||
b.ComputeDifficulty(database);
|
||||
beatmapSet.Beatmaps = beatmapSet.Beatmaps.OrderBy(b => b.StarDifficulty).ToList();
|
||||
|
||||
var group = new BeatmapGroup(database.GetWorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault()))
|
||||
var group = new BeatmapGroup(beatmapSet, database)
|
||||
{
|
||||
SelectionChanged = selectionChanged,
|
||||
StartRequested = b => footer.StartButton.TriggerClick()
|
||||
|
Loading…
Reference in New Issue
Block a user