mirror of
https://github.com/ppy/osu.git
synced 2025-01-14 20:13:22 +08:00
Merge branch 'master' into osu-direct
This commit is contained in:
commit
4ee11764b8
@ -1 +1 @@
|
|||||||
Subproject commit 42e26d49b9046fcb96c123b0dfb48e06d741e162
|
Subproject commit 777996fb9731ba1895a5ab1323cbbc97259ff741
|
@ -1 +1 @@
|
|||||||
Subproject commit ffccbeb98dc9e8f0965520270b5885e63f244c83
|
Subproject commit 9f46a456dc3a56dcbff09671a3f588b16a464106
|
@ -18,7 +18,7 @@ using osu.Game.Rulesets.Taiko.UI;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Desktop.VisualTests.Beatmaps;
|
using osu.Desktop.VisualTests.Beatmaps;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -53,8 +53,8 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
time += RNG.Next(50, 500);
|
time += RNG.Next(50, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingInfo timing = new TimingInfo();
|
var controlPointInfo = new ControlPointInfo();
|
||||||
timing.ControlPoints.Add(new ControlPoint
|
controlPointInfo.TimingPoints.Add(new TimingControlPoint
|
||||||
{
|
{
|
||||||
BeatLength = 200
|
BeatLength = 200
|
||||||
});
|
});
|
||||||
@ -73,7 +73,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
Author = @"peppy",
|
Author = @"peppy",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TimingInfo = timing
|
ControlPointInfo = controlPointInfo
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Drawable[]
|
Add(new Drawable[]
|
||||||
|
@ -7,10 +7,10 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Timing;
|
||||||
|
|
||||||
namespace osu.Desktop.VisualTests.Tests
|
namespace osu.Desktop.VisualTests.Tests
|
||||||
{
|
{
|
||||||
@ -27,7 +27,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) =>
|
Action<int, SpecialColumnPosition> createPlayfield = (cols, pos) =>
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
Add(new ManiaPlayfield(cols, new List<ControlPoint>())
|
Add(new ManiaPlayfield(cols, new List<TimingChange>())
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -41,7 +41,7 @@ namespace osu.Desktop.VisualTests.Tests
|
|||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
ManiaPlayfield playField;
|
ManiaPlayfield playField;
|
||||||
Add(playField = new ManiaPlayfield(cols, new List<ControlPoint> { new ControlPoint { BeatLength = 200 } })
|
Add(playField = new ManiaPlayfield(cols, new List<TimingChange> { new TimingChange { BeatLength = 200 } })
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -37,5 +37,7 @@ namespace osu.Desktop.Beatmaps.IO
|
|||||||
{
|
{
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Stream GetUnderlyingStream() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using osu.Game.Rulesets.Mania.MathUtils;
|
using osu.Game.Rulesets.Mania.MathUtils;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
||||||
{
|
{
|
||||||
@ -32,11 +32,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern)
|
||||||
: base(random, hitObject, beatmap, previousPattern)
|
: base(random, hitObject, beatmap, previousPattern)
|
||||||
{
|
{
|
||||||
ControlPoint overridePoint;
|
|
||||||
ControlPoint controlPoint = Beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint);
|
|
||||||
|
|
||||||
convertType = PatternType.None;
|
convertType = PatternType.None;
|
||||||
if ((overridePoint ?? controlPoint)?.KiaiMode == false)
|
if (Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode)
|
||||||
convertType = PatternType.LowProbability;
|
convertType = PatternType.LowProbability;
|
||||||
|
|
||||||
var distanceData = hitObject as IHasDistance;
|
var distanceData = hitObject as IHasDistance;
|
||||||
@ -44,13 +41,13 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
repeatCount = repeatsData?.RepeatCount ?? 1;
|
repeatCount = repeatsData?.RepeatCount ?? 1;
|
||||||
|
|
||||||
double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(hitObject.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(hitObject.StartTime) * speedAdjustment;
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
||||||
|
|
||||||
// The true distance, accounting for any repeats
|
// The true distance, accounting for any repeats
|
||||||
double distance = (distanceData?.Distance ?? 0) * repeatCount;
|
double distance = (distanceData?.Distance ?? 0) * repeatCount;
|
||||||
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
// The velocity of the osu! hit object - calculated as the velocity of a slider
|
||||||
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / speedAdjustedBeatLength;
|
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.Difficulty.SliderMultiplier / (timingPoint.BeatLength * difficultyPoint.SpeedMultiplier);
|
||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ using System.Linq;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Mania.MathUtils;
|
using osu.Game.Rulesets.Mania.MathUtils;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -25,17 +25,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
StairType = lastStair;
|
StairType = lastStair;
|
||||||
|
|
||||||
ControlPoint overridePoint;
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
ControlPoint controlPoint = beatmap.TimingInfo.TimingPointAt(hitObject.StartTime, out overridePoint);
|
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime);
|
||||||
|
|
||||||
var positionData = hitObject as IHasPosition;
|
var positionData = hitObject as IHasPosition;
|
||||||
|
|
||||||
float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length;
|
float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length;
|
||||||
double timeSeparation = hitObject.StartTime - previousTime;
|
double timeSeparation = hitObject.StartTime - previousTime;
|
||||||
|
|
||||||
double beatLength = controlPoint.BeatLength;
|
|
||||||
bool kiai = (overridePoint ?? controlPoint).KiaiMode;
|
|
||||||
|
|
||||||
if (timeSeparation <= 125)
|
if (timeSeparation <= 125)
|
||||||
{
|
{
|
||||||
// More than 120 BPM
|
// More than 120 BPM
|
||||||
@ -72,12 +69,12 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
// More than 100 BPM stream
|
// More than 100 BPM stream
|
||||||
convertType |= PatternType.ForceStack | PatternType.LowProbability;
|
convertType |= PatternType.ForceStack | PatternType.LowProbability;
|
||||||
}
|
}
|
||||||
else if (positionSeparation < 20 && density >= beatLength / 2.5)
|
else if (positionSeparation < 20 && density >= timingPoint.BeatLength / 2.5)
|
||||||
{
|
{
|
||||||
// Low density stream
|
// Low density stream
|
||||||
convertType |= PatternType.Reverse | PatternType.LowProbability;
|
convertType |= PatternType.Reverse | PatternType.LowProbability;
|
||||||
}
|
}
|
||||||
else if (density < beatLength / 2.5 || kiai)
|
else if (density < timingPoint.BeatLength / 2.5 || effectPoint.KiaiMode)
|
||||||
{
|
{
|
||||||
// High density
|
// High density
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// 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 osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public HitWindows ReleaseHitWindows { get; protected set; } = new HitWindows();
|
public HitWindows ReleaseHitWindows { get; protected set; } = new HitWindows();
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
ReleaseHitWindows = HitWindows * release_window_lenience;
|
ReleaseHitWindows = HitWindows * release_window_lenience;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 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 osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
|
|
||||||
@ -17,9 +17,9 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public HitWindows HitWindows { get; protected set; } = new HitWindows();
|
public HitWindows HitWindows { get; protected set; } = new HitWindows();
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
HitWindows = new HitWindows(difficulty.OverallDifficulty);
|
HitWindows = new HitWindows(difficulty.OverallDifficulty);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Timing
|
namespace osu.Game.Rulesets.Mania.Timing
|
||||||
{
|
{
|
||||||
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Timing
|
|||||||
|
|
||||||
private readonly List<DrawableControlPoint> drawableControlPoints;
|
private readonly List<DrawableControlPoint> drawableControlPoints;
|
||||||
|
|
||||||
public ControlPointContainer(IEnumerable<ControlPoint> timingChanges)
|
public ControlPointContainer(IEnumerable<TimingChange> timingChanges)
|
||||||
{
|
{
|
||||||
drawableControlPoints = timingChanges.Select(t => new DrawableControlPoint(t)).ToList();
|
drawableControlPoints = timingChanges.Select(t => new DrawableControlPoint(t)).ToList();
|
||||||
Children = drawableControlPoints;
|
Children = drawableControlPoints;
|
||||||
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Timing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class DrawableControlPoint : Container
|
private class DrawableControlPoint : Container
|
||||||
{
|
{
|
||||||
private readonly ControlPoint timingChange;
|
private readonly TimingChange timingChange;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.Timing
|
|||||||
/// the content container will scroll at twice the normal rate.
|
/// the content container will scroll at twice the normal rate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="timingChange">The control point to create the drawable control point for.</param>
|
/// <param name="timingChange">The control point to create the drawable control point for.</param>
|
||||||
public DrawableControlPoint(ControlPoint timingChange)
|
public DrawableControlPoint(TimingChange timingChange)
|
||||||
{
|
{
|
||||||
this.timingChange = timingChange;
|
this.timingChange = timingChange;
|
||||||
|
|
||||||
|
23
osu.Game.Rulesets.Mania/Timing/TimingChange.cs
Normal file
23
osu.Game.Rulesets.Mania/Timing/TimingChange.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Timing
|
||||||
|
{
|
||||||
|
public class TimingChange
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The time at which this timing change happened.
|
||||||
|
/// </summary>
|
||||||
|
public double Time;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The beat length.
|
||||||
|
/// </summary>
|
||||||
|
public double BeatLength = 500;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The speed multiplier.
|
||||||
|
/// </summary>
|
||||||
|
public double SpeedMultiplier = 1;
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,6 @@ using System.Collections.Generic;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
@ -46,7 +45,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public readonly ControlPointContainer ControlPointContainer;
|
public readonly ControlPointContainer ControlPointContainer;
|
||||||
|
|
||||||
public Column(IEnumerable<ControlPoint> timingChanges)
|
public Column(IEnumerable<TimingChange> timingChanges)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
Width = column_width;
|
Width = column_width;
|
||||||
|
@ -2,19 +2,22 @@
|
|||||||
// 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Lists;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Beatmaps;
|
using osu.Game.Rulesets.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Judgements;
|
using osu.Game.Rulesets.Mania.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
|
using osu.Game.Rulesets.Mania.Timing;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -33,22 +36,32 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
protected override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield()
|
protected override Playfield<ManiaHitObject, ManiaJudgement> CreatePlayfield()
|
||||||
{
|
{
|
||||||
ControlPoint firstTimingChange = Beatmap.TimingInfo.ControlPoints.FirstOrDefault(t => t.TimingChange);
|
double lastSpeedMultiplier = 1;
|
||||||
|
double lastBeatLength = 500;
|
||||||
|
|
||||||
if (firstTimingChange == null)
|
// Merge timing + difficulty points
|
||||||
throw new InvalidOperationException("The Beatmap contains no timing points!");
|
var allPoints = new SortedList<ControlPoint>(Comparer<ControlPoint>.Default);
|
||||||
|
allPoints.AddRange(Beatmap.ControlPointInfo.TimingPoints);
|
||||||
|
allPoints.AddRange(Beatmap.ControlPointInfo.DifficultyPoints);
|
||||||
|
|
||||||
// Generate the timing points, making non-timing changes use the previous timing change
|
// Generate the timing points, making non-timing changes use the previous timing change
|
||||||
var timingChanges = Beatmap.TimingInfo.ControlPoints.Select(c =>
|
var timingChanges = allPoints.Select(c =>
|
||||||
{
|
{
|
||||||
ControlPoint t = c.Clone();
|
var timingPoint = c as TimingControlPoint;
|
||||||
|
var difficultyPoint = c as DifficultyControlPoint;
|
||||||
|
|
||||||
if (c.TimingChange)
|
if (timingPoint != null)
|
||||||
firstTimingChange = c;
|
lastBeatLength = timingPoint.BeatLength;
|
||||||
else
|
|
||||||
t.BeatLength = firstTimingChange.BeatLength;
|
|
||||||
|
|
||||||
return t;
|
if (difficultyPoint != null)
|
||||||
|
lastSpeedMultiplier = difficultyPoint.SpeedMultiplier;
|
||||||
|
|
||||||
|
return new TimingChange
|
||||||
|
{
|
||||||
|
Time = c.Time,
|
||||||
|
BeatLength = lastBeatLength,
|
||||||
|
SpeedMultiplier = lastSpeedMultiplier
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||||
|
@ -19,7 +19,6 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Mania.Timing;
|
using osu.Game.Rulesets.Mania.Timing;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
private readonly int columnCount;
|
private readonly int columnCount;
|
||||||
|
|
||||||
public ManiaPlayfield(int columnCount, IEnumerable<ControlPoint> timingChanges)
|
public ManiaPlayfield(int columnCount, IEnumerable<TimingChange> timingChanges)
|
||||||
{
|
{
|
||||||
this.columnCount = columnCount;
|
this.columnCount = columnCount;
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
<Compile Include="Mods\ManiaMod.cs" />
|
<Compile Include="Mods\ManiaMod.cs" />
|
||||||
<Compile Include="UI\SpecialColumnPosition.cs" />
|
<Compile Include="UI\SpecialColumnPosition.cs" />
|
||||||
<Compile Include="Timing\ControlPointContainer.cs" />
|
<Compile Include="Timing\ControlPointContainer.cs" />
|
||||||
|
<Compile Include="Timing\TimingChange.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||||
|
@ -6,8 +6,8 @@ using OpenTK;
|
|||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
return OsuScoreResult.Miss;
|
return OsuScoreResult.Miss;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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 OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -10,6 +9,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -62,13 +62,16 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public double Velocity;
|
public double Velocity;
|
||||||
public double TickDistance;
|
public double TickDistance;
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / timing.SpeedMultiplierAt(StartTime);
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||||
|
|
||||||
Velocity = scoringDistance / timing.BeatLengthAt(StartTime);
|
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier / difficultyPoint.SpeedMultiplier;
|
||||||
|
|
||||||
|
Velocity = scoringDistance / timingPoint.BeatLength;
|
||||||
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// 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 osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
public override bool NewCombo => true;
|
public override bool NewCombo => true;
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));
|
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Database;
|
|||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Beatmaps;
|
using osu.Game.Rulesets.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Beatmaps
|
namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||||
{
|
{
|
||||||
@ -77,8 +78,11 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
int repeats = repeatsData?.RepeatCount ?? 1;
|
int repeats = repeatsData?.RepeatCount ?? 1;
|
||||||
|
|
||||||
double speedAdjustment = beatmap.TimingInfo.SpeedMultiplierAt(obj.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime);
|
||||||
double speedAdjustedBeatLength = beatmap.TimingInfo.BeatLengthAt(obj.StartTime) * speedAdjustment;
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime);
|
||||||
|
|
||||||
|
double speedAdjustment = difficultyPoint.SpeedMultiplier;
|
||||||
|
double speedAdjustedBeatLength = timingPoint.BeatLength * speedAdjustment;
|
||||||
|
|
||||||
// The true distance, accounting for any repeats. This ends up being the drum roll distance later
|
// The true distance, accounting for any repeats. This ends up being the drum roll distance later
|
||||||
double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
|
double distance = distanceData.Distance * repeats * legacy_velocity_multiplier;
|
||||||
|
@ -5,9 +5,9 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps.Timing;
|
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
@ -55,11 +55,13 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private double tickSpacing = 100;
|
private double tickSpacing = 100;
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
tickSpacing = timing.BeatLengthAt(StartTime) / TickRate;
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
|
||||||
|
tickSpacing = timingPoint.BeatLength / TickRate;
|
||||||
|
|
||||||
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
|
RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty);
|
||||||
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
|
RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 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 osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Objects
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
@ -23,9 +23,9 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double HitWindowMiss = 95;
|
public double HitWindowMiss = 95;
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
|
HitWindowGreat = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 50, 35, 20);
|
||||||
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);
|
HitWindowGood = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 120, 80, 50);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 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 osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
@ -31,12 +31,12 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
public const float DEFAULT_STRONG_CIRCLE_DIAMETER = DEFAULT_CIRCLE_DIAMETER * STRONG_CIRCLE_DIAMETER_SCALE;
|
public const float DEFAULT_STRONG_CIRCLE_DIAMETER = DEFAULT_CIRCLE_DIAMETER * STRONG_CIRCLE_DIAMETER_SCALE;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a <see cref="ControlPoint.BeatLength"/> of 1000ms.
|
/// The time taken from the initial (off-screen) spawn position to the centre of the hit target for a <see cref="TimingControlPoint.BeatLength"/> of 1000ms.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const double scroll_time = 6000;
|
private const double scroll_time = 6000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Our adjusted <see cref="scroll_time"/> taking into consideration local <see cref="ControlPoint.BeatLength"/> and other speed multipliers.
|
/// Our adjusted <see cref="scroll_time"/> taking into consideration local <see cref="TimingControlPoint.BeatLength"/> and other speed multipliers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double ScrollTime;
|
public double ScrollTime;
|
||||||
|
|
||||||
@ -51,17 +51,17 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Kiai { get; protected set; }
|
public bool Kiai { get; protected set; }
|
||||||
|
|
||||||
public override void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaults(timing, difficulty);
|
base.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
|
||||||
ScrollTime = scroll_time * (timing.BeatLengthAt(StartTime) * timing.SpeedMultiplierAt(StartTime) / 1000) / difficulty.SliderMultiplier;
|
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
|
||||||
|
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
|
||||||
|
EffectControlPoint effectPoint = controlPointInfo.EffectPointAt(StartTime);
|
||||||
|
|
||||||
ControlPoint overridePoint;
|
ScrollTime = scroll_time * (timingPoint.BeatLength * difficultyPoint.SpeedMultiplier / 1000) / difficulty.SliderMultiplier;
|
||||||
Kiai = timing.TimingPointAt(StartTime, out overridePoint).KiaiMode;
|
|
||||||
|
|
||||||
if (overridePoint != null)
|
Kiai |= effectPoint.KiaiMode;
|
||||||
Kiai |= overridePoint.KiaiMode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -17,6 +17,7 @@ using osu.Game.Rulesets.UI;
|
|||||||
using osu.Game.Rulesets.Taiko.Replays;
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Beatmaps;
|
using osu.Game.Rulesets.Beatmaps;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.UI
|
namespace osu.Game.Rulesets.Taiko.UI
|
||||||
{
|
{
|
||||||
@ -43,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
|
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
|
||||||
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
|
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime;
|
||||||
|
|
||||||
var timingPoints = Beatmap.TimingInfo.ControlPoints.FindAll(cp => cp.TimingChange);
|
var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList();
|
||||||
|
|
||||||
if (timingPoints.Count == 0)
|
if (timingPoints.Count == 0)
|
||||||
return;
|
return;
|
||||||
@ -68,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
StartTime = time,
|
StartTime = time,
|
||||||
};
|
};
|
||||||
|
|
||||||
barLine.ApplyDefaults(Beatmap.TimingInfo, Beatmap.BeatmapInfo.Difficulty);
|
barLine.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty);
|
||||||
|
|
||||||
bool isMajor = currentBeat % (int)currentPoint.TimeSignature == 0;
|
bool isMajor = currentBeat % (int)currentPoint.TimeSignature == 0;
|
||||||
taikoPlayfield.AddBarLine(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine));
|
taikoPlayfield.AddBarLine(isMajor ? new DrawableBarLineMajor(barLine) : new DrawableBarLine(barLine));
|
||||||
|
@ -7,6 +7,7 @@ using osu.Game.Database;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
@ -17,7 +18,7 @@ namespace osu.Game.Beatmaps
|
|||||||
where T : HitObject
|
where T : HitObject
|
||||||
{
|
{
|
||||||
public BeatmapInfo BeatmapInfo;
|
public BeatmapInfo BeatmapInfo;
|
||||||
public TimingInfo TimingInfo = new TimingInfo();
|
public ControlPointInfo ControlPointInfo = new ControlPointInfo();
|
||||||
public List<BreakPeriod> Breaks = new List<BreakPeriod>();
|
public List<BreakPeriod> Breaks = new List<BreakPeriod>();
|
||||||
public readonly List<Color4> ComboColors = new List<Color4>
|
public readonly List<Color4> ComboColors = new List<Color4>
|
||||||
{
|
{
|
||||||
@ -46,7 +47,7 @@ namespace osu.Game.Beatmaps
|
|||||||
public Beatmap(Beatmap original = null)
|
public Beatmap(Beatmap original = null)
|
||||||
{
|
{
|
||||||
BeatmapInfo = original?.BeatmapInfo ?? BeatmapInfo;
|
BeatmapInfo = original?.BeatmapInfo ?? BeatmapInfo;
|
||||||
TimingInfo = original?.TimingInfo ?? TimingInfo;
|
ControlPointInfo = original?.ControlPointInfo ?? ControlPointInfo;
|
||||||
Breaks = original?.Breaks ?? Breaks;
|
Breaks = original?.Breaks ?? Breaks;
|
||||||
ComboColors = original?.ComboColors ?? ComboColors;
|
ComboColors = original?.ComboColors ?? ComboColors;
|
||||||
}
|
}
|
||||||
|
17
osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
Normal file
17
osu.Game/Beatmaps/ControlPoints/ControlPoint.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.ControlPoints
|
||||||
|
{
|
||||||
|
public class ControlPoint : IComparable<ControlPoint>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The time at which the control point takes effect.
|
||||||
|
/// </summary>
|
||||||
|
public double Time;
|
||||||
|
|
||||||
|
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
|
||||||
|
}
|
||||||
|
}
|
107
osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
Normal file
107
osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Lists;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.ControlPoints
|
||||||
|
{
|
||||||
|
public class ControlPointInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All timing points.
|
||||||
|
/// </summary>
|
||||||
|
public readonly SortedList<TimingControlPoint> TimingPoints = new SortedList<TimingControlPoint>(Comparer<TimingControlPoint>.Default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All difficulty points.
|
||||||
|
/// </summary>
|
||||||
|
public readonly SortedList<DifficultyControlPoint> DifficultyPoints = new SortedList<DifficultyControlPoint>(Comparer<DifficultyControlPoint>.Default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All sound points.
|
||||||
|
/// </summary>
|
||||||
|
public readonly SortedList<SoundControlPoint> SoundPoints = new SortedList<SoundControlPoint>(Comparer<SoundControlPoint>.Default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All effect points.
|
||||||
|
/// </summary>
|
||||||
|
public readonly SortedList<EffectControlPoint> EffectPoints = new SortedList<EffectControlPoint>(Comparer<EffectControlPoint>.Default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the difficulty control point that is active at <paramref name="time"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="time">The time to find the difficulty control point at.</param>
|
||||||
|
/// <returns>The difficulty control point.</returns>
|
||||||
|
public DifficultyControlPoint DifficultyPointAt(double time) => binarySearch(DifficultyPoints, time);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the effect control point that is active at <paramref name="time"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="time">The time to find the effect control point at.</param>
|
||||||
|
/// <returns>The effect control point.</returns>
|
||||||
|
public EffectControlPoint EffectPointAt(double time) => binarySearch(EffectPoints, time);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the sound control point that is active at <paramref name="time"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="time">The time to find the sound control point at.</param>
|
||||||
|
/// <returns>The sound control point.</returns>
|
||||||
|
public SoundControlPoint SoundPointAt(double time) => binarySearch(SoundPoints, time);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the timing control point that is active at <paramref name="time"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="time">The time to find the timing control point at.</param>
|
||||||
|
/// <returns>The timing control point.</returns>
|
||||||
|
public TimingControlPoint TimingPointAt(double time) => binarySearch(TimingPoints, time, TimingPoints.FirstOrDefault());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the maximum BPM represented by any timing control point.
|
||||||
|
/// </summary>
|
||||||
|
public double BPMMaximum =>
|
||||||
|
60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the minimum BPM represented by any timing control point.
|
||||||
|
/// </summary>
|
||||||
|
public double BPMMinimum =>
|
||||||
|
60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the mode BPM (most common BPM) represented by the control points.
|
||||||
|
/// </summary>
|
||||||
|
public double BPMMode =>
|
||||||
|
60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binary searches one of the control point lists to find the active control point at <paramref name="time"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="list">The list to search.</param>
|
||||||
|
/// <param name="time">The time to find the control point at.</param>
|
||||||
|
/// <param name="prePoint">The control point to use when <paramref name="time"/> is before any control points. If null, a new control point will be constructed.</param>
|
||||||
|
/// <returns>The active control point at <paramref name="time"/>.</returns>
|
||||||
|
private T binarySearch<T>(SortedList<T> list, double time, T prePoint = null)
|
||||||
|
where T : ControlPoint, new()
|
||||||
|
{
|
||||||
|
if (list.Count == 0)
|
||||||
|
return new T();
|
||||||
|
|
||||||
|
if (time < list[0].Time)
|
||||||
|
return prePoint ?? new T();
|
||||||
|
|
||||||
|
int index = list.BinarySearch(new T() { Time = time });
|
||||||
|
|
||||||
|
// Check if we've found an exact match (t == time)
|
||||||
|
if (index >= 0)
|
||||||
|
return list[index];
|
||||||
|
|
||||||
|
index = ~index;
|
||||||
|
|
||||||
|
// BinarySearch will return the index of the first element _greater_ than the search
|
||||||
|
// This is the inactive point - the active point is the one before it (index - 1)
|
||||||
|
return list[index - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
Normal file
13
osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.ControlPoints
|
||||||
|
{
|
||||||
|
public class DifficultyControlPoint : ControlPoint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The speed multiplier at this control point.
|
||||||
|
/// </summary>
|
||||||
|
public double SpeedMultiplier = 1;
|
||||||
|
}
|
||||||
|
}
|
18
osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
Normal file
18
osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.ControlPoints
|
||||||
|
{
|
||||||
|
public class EffectControlPoint : ControlPoint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this control point enables Kiai mode.
|
||||||
|
/// </summary>
|
||||||
|
public bool KiaiMode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the first bar line of this control point is ignored.
|
||||||
|
/// </summary>
|
||||||
|
public bool OmitFirstBarLine;
|
||||||
|
}
|
||||||
|
}
|
18
osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs
Normal file
18
osu.Game/Beatmaps/ControlPoints/SoundControlPoint.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.ControlPoints
|
||||||
|
{
|
||||||
|
public class SoundControlPoint : ControlPoint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The default sample bank at this control point.
|
||||||
|
/// </summary>
|
||||||
|
public string SampleBank;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default sample volume at this control point.
|
||||||
|
/// </summary>
|
||||||
|
public int SampleVolume;
|
||||||
|
}
|
||||||
|
}
|
20
osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
Normal file
20
osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
|
||||||
|
namespace osu.Game.Beatmaps.ControlPoints
|
||||||
|
{
|
||||||
|
public class TimingControlPoint : ControlPoint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The time signature at this control point.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSignatures TimeSignature = TimeSignatures.SimpleQuadruple;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The beat length at this control point.
|
||||||
|
/// </summary>
|
||||||
|
public double BeatLength = 500;
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ namespace osu.Game.Beatmaps
|
|||||||
Objects = CreateBeatmapConverter().Convert(beatmap, true).HitObjects;
|
Objects = CreateBeatmapConverter().Convert(beatmap, true).HitObjects;
|
||||||
|
|
||||||
foreach (var h in Objects)
|
foreach (var h in Objects)
|
||||||
h.ApplyDefaults(beatmap.TimingInfo, beatmap.BeatmapInfo.Difficulty);
|
h.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.Difficulty);
|
||||||
|
|
||||||
PreprocessHitObjects();
|
PreprocessHitObjects();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using OpenTK.Graphics;
|
|||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
{
|
{
|
||||||
@ -241,6 +242,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
||||||
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
||||||
|
double speedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1;
|
||||||
|
|
||||||
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
|
TimeSignatures timeSignature = TimeSignatures.SimpleQuadruple;
|
||||||
if (split.Length >= 3)
|
if (split.Length >= 3)
|
||||||
@ -275,18 +277,48 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
if (stringSampleSet == @"none")
|
if (stringSampleSet == @"none")
|
||||||
stringSampleSet = @"normal";
|
stringSampleSet = @"normal";
|
||||||
|
|
||||||
beatmap.TimingInfo.ControlPoints.Add(new ControlPoint
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(time);
|
||||||
|
SoundControlPoint soundPoint = beatmap.ControlPointInfo.SoundPointAt(time);
|
||||||
|
EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(time);
|
||||||
|
|
||||||
|
if (timingChange)
|
||||||
{
|
{
|
||||||
Time = time,
|
beatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint
|
||||||
BeatLength = beatLength,
|
{
|
||||||
SpeedMultiplier = beatLength < 0 ? -beatLength / 100.0 : 1,
|
Time = time,
|
||||||
TimingChange = timingChange,
|
BeatLength = beatLength,
|
||||||
TimeSignature = timeSignature,
|
TimeSignature = timeSignature
|
||||||
SampleBank = stringSampleSet,
|
});
|
||||||
SampleVolume = sampleVolume,
|
}
|
||||||
KiaiMode = kiaiMode,
|
|
||||||
OmitFirstBarLine = omitFirstBarSignature
|
if (speedMultiplier != difficultyPoint.SpeedMultiplier)
|
||||||
});
|
{
|
||||||
|
beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint
|
||||||
|
{
|
||||||
|
Time = time,
|
||||||
|
SpeedMultiplier = speedMultiplier
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stringSampleSet != soundPoint.SampleBank || sampleVolume != soundPoint.SampleVolume)
|
||||||
|
{
|
||||||
|
beatmap.ControlPointInfo.SoundPoints.Add(new SoundControlPoint
|
||||||
|
{
|
||||||
|
Time = time,
|
||||||
|
SampleBank = stringSampleSet,
|
||||||
|
SampleVolume = sampleVolume
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kiaiMode != effectPoint.KiaiMode || omitFirstBarSignature != effectPoint.OmitFirstBarLine)
|
||||||
|
{
|
||||||
|
beatmap.ControlPointInfo.EffectPoints.Add(new EffectControlPoint
|
||||||
|
{
|
||||||
|
Time = time,
|
||||||
|
KiaiMode = kiaiMode,
|
||||||
|
OmitFirstBarLine = omitFirstBarSignature
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
|
private void handleColours(Beatmap beatmap, string key, string val, ref bool hasCustomColours)
|
||||||
|
@ -63,5 +63,7 @@ namespace osu.Game.Beatmaps.IO
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract Stream GetUnderlyingStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -49,5 +49,7 @@ namespace osu.Game.Beatmaps.IO
|
|||||||
archive.Dispose();
|
archive.Dispose();
|
||||||
archiveStream.Dispose();
|
archiveStream.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Stream GetUnderlyingStream() => archiveStream;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Timing
|
|
||||||
{
|
|
||||||
public class ControlPoint
|
|
||||||
{
|
|
||||||
public string SampleBank;
|
|
||||||
public int SampleVolume;
|
|
||||||
public TimeSignatures TimeSignature = TimeSignatures.SimpleQuadruple;
|
|
||||||
public double Time;
|
|
||||||
public double BeatLength = 500;
|
|
||||||
public double SpeedMultiplier = 1;
|
|
||||||
public bool TimingChange = true;
|
|
||||||
public bool KiaiMode;
|
|
||||||
public bool OmitFirstBarLine;
|
|
||||||
|
|
||||||
public ControlPoint Clone() => (ControlPoint)MemberwiseClone();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Timing
|
|
||||||
{
|
|
||||||
public class TimingInfo
|
|
||||||
{
|
|
||||||
public readonly List<ControlPoint> ControlPoints = new List<ControlPoint>();
|
|
||||||
|
|
||||||
public double BPMMaximum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderBy(c => c.BeatLength).FirstOrDefault() ?? new ControlPoint()).BeatLength;
|
|
||||||
public double BPMMinimum => 60000 / (ControlPoints?.Where(c => c.BeatLength != 0).OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new ControlPoint()).BeatLength;
|
|
||||||
public double BPMMode => BPMAt(ControlPoints.Where(c => c.BeatLength != 0).GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).First().First().Time);
|
|
||||||
|
|
||||||
public double BPMAt(double time)
|
|
||||||
{
|
|
||||||
return 60000 / BeatLengthAt(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds the speed multiplier at a time.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="time">The time to find the speed multiplier at.</param>
|
|
||||||
/// <returns>The speed multiplier.</returns>
|
|
||||||
public double SpeedMultiplierAt(double time)
|
|
||||||
{
|
|
||||||
ControlPoint overridePoint;
|
|
||||||
ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
|
|
||||||
|
|
||||||
return overridePoint?.SpeedMultiplier ?? timingPoint?.SpeedMultiplier ?? 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds the beat length at a time. This is expressed in milliseconds.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="time">The time to find the beat length at.</param>
|
|
||||||
/// <returns>The beat length.</returns>
|
|
||||||
public double BeatLengthAt(double time)
|
|
||||||
{
|
|
||||||
ControlPoint overridePoint;
|
|
||||||
ControlPoint timingPoint = TimingPointAt(time, out overridePoint);
|
|
||||||
|
|
||||||
return timingPoint.BeatLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds the timing point at a time.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="time">The time to find the timing point at.</param>
|
|
||||||
/// <param name="overridePoint">The timing point containing the velocity change of the returned timing point.</param>
|
|
||||||
/// <returns>The timing point.</returns>
|
|
||||||
public ControlPoint TimingPointAt(double time, out ControlPoint overridePoint)
|
|
||||||
{
|
|
||||||
overridePoint = null;
|
|
||||||
|
|
||||||
ControlPoint timingPoint = null;
|
|
||||||
foreach (var controlPoint in ControlPoints)
|
|
||||||
{
|
|
||||||
// Some beatmaps have the first timingPoint (accidentally) start after the first HitObject(s).
|
|
||||||
// This null check makes it so that the first ControlPoint that makes a timing change is used as
|
|
||||||
// the timingPoint for those HitObject(s).
|
|
||||||
if (controlPoint.Time <= time || timingPoint == null)
|
|
||||||
{
|
|
||||||
if (controlPoint.TimingChange)
|
|
||||||
{
|
|
||||||
timingPoint = controlPoint;
|
|
||||||
overridePoint = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
overridePoint = controlPoint;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return timingPoint ?? new ControlPoint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,6 +12,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Beatmaps.IO;
|
using osu.Game.Beatmaps.IO;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
|
using osu.Game.Screens.Menu;
|
||||||
using SQLite.Net;
|
using SQLite.Net;
|
||||||
using SQLiteNetExtensions.Extensions;
|
using SQLiteNetExtensions.Extensions;
|
||||||
|
|
||||||
@ -38,6 +39,10 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
foreach (var b in GetAllWithChildren<BeatmapSetInfo>(b => b.DeletePending))
|
foreach (var b in GetAllWithChildren<BeatmapSetInfo>(b => b.DeletePending))
|
||||||
{
|
{
|
||||||
|
if (b.Hash == Intro.MENU_MUSIC_BEATMAP_HASH)
|
||||||
|
// this is a bit hacky, but will do for now.
|
||||||
|
continue;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Storage.Delete(b.Path);
|
Storage.Delete(b.Path);
|
||||||
@ -97,50 +102,49 @@ namespace osu.Game.Database
|
|||||||
typeof(BeatmapDifficulty),
|
typeof(BeatmapDifficulty),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public void Import(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Import(ArchiveReader.GetReader(Storage, path));
|
||||||
|
|
||||||
|
// We may or may not want to delete the file depending on where it is stored.
|
||||||
|
// e.g. reconstructing/repairing database with beatmaps from default storage.
|
||||||
|
// Also, not always a single file, i.e. for LegacyFilesystemReader
|
||||||
|
// TODO: Add a check to prevent files from storage to be deleted.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(path);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, $@"Could not delete file at {path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
e = e.InnerException ?? e;
|
||||||
|
Logger.Error(e, @"Could not import beatmap set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Import(ArchiveReader archiveReader)
|
||||||
|
{
|
||||||
|
BeatmapSetInfo set = getBeatmapSet(archiveReader);
|
||||||
|
|
||||||
|
//If we have an ID then we already exist in the database.
|
||||||
|
if (set.ID == 0)
|
||||||
|
Import(new[] { set });
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Import multiple <see cref="BeatmapSetInfo"/> from <paramref name="paths"/>.
|
/// Import multiple <see cref="BeatmapSetInfo"/> from <paramref name="paths"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="paths">Multiple locations on disk</param>
|
/// <param name="paths">Multiple locations on disk</param>
|
||||||
public void Import(IEnumerable<string> paths)
|
public void Import(params string[] paths)
|
||||||
{
|
{
|
||||||
foreach (string p in paths)
|
foreach (string p in paths)
|
||||||
{
|
Import(p);
|
||||||
try
|
|
||||||
{
|
|
||||||
BeatmapSetInfo set = getBeatmapSet(p);
|
|
||||||
|
|
||||||
//If we have an ID then we already exist in the database.
|
|
||||||
if (set.ID == 0)
|
|
||||||
Import(new[] { set });
|
|
||||||
|
|
||||||
// We may or may not want to delete the file depending on where it is stored.
|
|
||||||
// e.g. reconstructing/repairing database with beatmaps from default storage.
|
|
||||||
// Also, not always a single file, i.e. for LegacyFilesystemReader
|
|
||||||
// TODO: Add a check to prevent files from storage to be deleted.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(p);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.Error(e, $@"Could not delete file at {p}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
e = e.InnerException ?? e;
|
|
||||||
Logger.Error(e, @"Could not import beatmap set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Import <see cref="BeatmapSetInfo"/> from <paramref name="path"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">Location on disk</param>
|
|
||||||
public void Import(string path)
|
|
||||||
{
|
|
||||||
Import(new[] { path });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -148,29 +152,26 @@ namespace osu.Game.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">Content location</param>
|
/// <param name="path">Content location</param>
|
||||||
/// <returns><see cref="BeatmapSetInfo"/></returns>
|
/// <returns><see cref="BeatmapSetInfo"/></returns>
|
||||||
private BeatmapSetInfo getBeatmapSet(string path)
|
private BeatmapSetInfo getBeatmapSet(string path) => getBeatmapSet(ArchiveReader.GetReader(Storage, path));
|
||||||
{
|
|
||||||
string hash = null;
|
|
||||||
|
|
||||||
|
private BeatmapSetInfo getBeatmapSet(ArchiveReader archiveReader)
|
||||||
|
{
|
||||||
BeatmapMetadata metadata;
|
BeatmapMetadata metadata;
|
||||||
|
|
||||||
using (var reader = ArchiveReader.GetReader(Storage, path))
|
using (var stream = new StreamReader(archiveReader.GetStream(archiveReader.BeatmapFilenames[0])))
|
||||||
{
|
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
||||||
using (var stream = new StreamReader(reader.GetStream(reader.BeatmapFilenames[0])))
|
|
||||||
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(path)) // Not always the case, i.e. for LegacyFilesystemReader
|
string hash;
|
||||||
|
string path;
|
||||||
|
|
||||||
|
using (var input = archiveReader.GetUnderlyingStream())
|
||||||
{
|
{
|
||||||
using (var input = Storage.GetStream(path))
|
hash = input.GetMd5Hash();
|
||||||
{
|
input.Seek(0, SeekOrigin.Begin);
|
||||||
hash = input.GetMd5Hash();
|
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
|
||||||
input.Seek(0, SeekOrigin.Begin);
|
if (!Storage.Exists(path))
|
||||||
path = Path.Combine(@"beatmaps", hash.Remove(1), hash.Remove(2), hash);
|
using (var output = Storage.GetStream(path, FileAccess.Write))
|
||||||
if (!Storage.Exists(path))
|
input.CopyTo(output);
|
||||||
using (var output = Storage.GetStream(path, FileAccess.Write))
|
|
||||||
input.CopyTo(output);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var existing = Connection.Table<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
var existing = Connection.Table<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash);
|
||||||
|
@ -2,58 +2,65 @@
|
|||||||
// 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 osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
public class BeatSyncedContainer : Container
|
public class BeatSyncedContainer : Container
|
||||||
{
|
{
|
||||||
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
private int lastBeat;
|
private int lastBeat;
|
||||||
private ControlPoint lastControlPoint;
|
private TimingControlPoint lastTimingPoint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of time before a beat we should fire <see cref="OnNewBeat(int, TimingControlPoint, EffectControlPoint, TrackAmplitudes)"/>.
|
||||||
|
/// This allows for adding easing to animations that may be synchronised to the beat.
|
||||||
|
/// </summary>
|
||||||
|
protected double EarlyActivationMilliseconds;
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
if (beatmap.Value?.Track == null)
|
if (Beatmap.Value?.Track == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double currentTrackTime = beatmap.Value.Track.CurrentTime;
|
double currentTrackTime = Beatmap.Value.Track.CurrentTime + EarlyActivationMilliseconds;
|
||||||
ControlPoint overridePoint;
|
|
||||||
ControlPoint controlPoint = beatmap.Value.Beatmap.TimingInfo.TimingPointAt(currentTrackTime, out overridePoint);
|
|
||||||
|
|
||||||
if (controlPoint.BeatLength == 0)
|
TimingControlPoint timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
|
||||||
|
EffectControlPoint effectPoint = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
|
||||||
|
|
||||||
|
if (timingPoint.BeatLength == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool kiai = (overridePoint ?? controlPoint).KiaiMode;
|
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / timingPoint.BeatLength);
|
||||||
int beat = (int)((currentTrackTime - controlPoint.Time) / controlPoint.BeatLength);
|
|
||||||
|
|
||||||
// The beats before the start of the first control point are off by 1, this should do the trick
|
// The beats before the start of the first control point are off by 1, this should do the trick
|
||||||
if (currentTrackTime < controlPoint.Time)
|
if (currentTrackTime < timingPoint.Time)
|
||||||
beat--;
|
beatIndex--;
|
||||||
|
|
||||||
if (controlPoint == lastControlPoint && beat == lastBeat)
|
if (timingPoint == lastTimingPoint && beatIndex == lastBeat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double offsetFromBeat = (controlPoint.Time - currentTrackTime) % controlPoint.BeatLength;
|
double offsetFromBeat = (timingPoint.Time - currentTrackTime) % timingPoint.BeatLength;
|
||||||
|
|
||||||
using (BeginDelayedSequence(offsetFromBeat, true))
|
using (BeginDelayedSequence(offsetFromBeat, true))
|
||||||
OnNewBeat(beat, controlPoint.BeatLength, controlPoint.TimeSignature, kiai);
|
OnNewBeat(beatIndex, timingPoint, effectPoint, Beatmap.Value.Track.CurrentAmplitudes);
|
||||||
|
|
||||||
lastBeat = beat;
|
lastBeat = beatIndex;
|
||||||
lastControlPoint = controlPoint;
|
lastTimingPoint = timingPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGameBase game)
|
private void load(OsuGameBase game)
|
||||||
{
|
{
|
||||||
beatmap.BindTo(game.Beatmap);
|
Beatmap.BindTo(game.Beatmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnNewBeat(int newBeat, double beatLength, TimeSignatures timeSignature, bool kiai)
|
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ namespace osu.Game
|
|||||||
if (args?.Length > 0)
|
if (args?.Length > 0)
|
||||||
{
|
{
|
||||||
var paths = args.Where(a => !a.StartsWith(@"-"));
|
var paths = args.Where(a => !a.StartsWith(@"-"));
|
||||||
Task.Run(() => BeatmapDatabase.Import(paths));
|
Task.Run(() => BeatmapDatabase.Import(paths.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dependencies.Cache(this);
|
Dependencies.Cache(this);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||||
{
|
{
|
||||||
@ -11,11 +12,12 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
{
|
{
|
||||||
protected override string Header => "Layout";
|
protected override string Header => "Layout";
|
||||||
|
|
||||||
private SettingsSlider<double> letterboxPositionX;
|
private FillFlowContainer letterboxSettings;
|
||||||
private SettingsSlider<double> letterboxPositionY;
|
|
||||||
|
|
||||||
private Bindable<bool> letterboxing;
|
private Bindable<bool> letterboxing;
|
||||||
|
|
||||||
|
private const int transition_duration = 400;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager config)
|
private void load(FrameworkConfigManager config)
|
||||||
{
|
{
|
||||||
@ -33,34 +35,40 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
|||||||
LabelText = "Letterboxing",
|
LabelText = "Letterboxing",
|
||||||
Bindable = letterboxing,
|
Bindable = letterboxing,
|
||||||
},
|
},
|
||||||
letterboxPositionX = new SettingsSlider<double>
|
letterboxSettings = new FillFlowContainer
|
||||||
{
|
{
|
||||||
LabelText = "Horizontal position",
|
Direction = FillDirection.Vertical,
|
||||||
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionX)
|
RelativeSizeAxes = Axes.X,
|
||||||
},
|
AutoSizeAxes = Axes.Y,
|
||||||
letterboxPositionY = new SettingsSlider<double>
|
AutoSizeDuration = transition_duration,
|
||||||
{
|
AutoSizeEasing = EasingTypes.OutQuint,
|
||||||
LabelText = "Vertical position",
|
Masking = true,
|
||||||
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionY)
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SettingsSlider<double>
|
||||||
|
{
|
||||||
|
LabelText = "Horizontal position",
|
||||||
|
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionX)
|
||||||
|
},
|
||||||
|
new SettingsSlider<double>
|
||||||
|
{
|
||||||
|
LabelText = "Vertical position",
|
||||||
|
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionY)
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
letterboxing.ValueChanged += visibilityChanged;
|
letterboxing.ValueChanged += isVisible =>
|
||||||
letterboxing.TriggerChange();
|
{
|
||||||
}
|
letterboxSettings.ClearTransforms();
|
||||||
|
letterboxSettings.AutoSizeAxes = isVisible ? Axes.Y : Axes.None;
|
||||||
|
|
||||||
private void visibilityChanged(bool newVisibility)
|
if(!isVisible)
|
||||||
{
|
letterboxSettings.ResizeHeightTo(0, transition_duration, EasingTypes.OutQuint);
|
||||||
if (newVisibility)
|
};
|
||||||
{
|
letterboxing.TriggerChange();
|
||||||
letterboxPositionX.Show();
|
|
||||||
letterboxPositionY.Show();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
letterboxPositionX.Hide();
|
|
||||||
letterboxPositionY.Hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Beatmaps
|
|||||||
return new Beatmap<T>
|
return new Beatmap<T>
|
||||||
{
|
{
|
||||||
BeatmapInfo = original.BeatmapInfo,
|
BeatmapInfo = original.BeatmapInfo,
|
||||||
TimingInfo = original.TimingInfo,
|
ControlPointInfo = original.ControlPointInfo,
|
||||||
HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList()
|
HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// 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 osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
@ -33,31 +33,28 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies default values to this HitObject.
|
/// Applies default values to this HitObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="controlPointInfo">The control points.</param>
|
||||||
/// <param name="difficulty">The difficulty settings to use.</param>
|
/// <param name="difficulty">The difficulty settings to use.</param>
|
||||||
/// <param name="timing">The timing settings to use.</param>
|
public virtual void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
public virtual void ApplyDefaults(TimingInfo timing, BeatmapDifficulty difficulty)
|
|
||||||
{
|
{
|
||||||
ControlPoint overridePoint;
|
SoundControlPoint soundPoint = controlPointInfo.SoundPointAt(StartTime);
|
||||||
ControlPoint timingPoint = timing.TimingPointAt(StartTime, out overridePoint);
|
|
||||||
|
|
||||||
ControlPoint samplePoint = overridePoint ?? timingPoint;
|
|
||||||
|
|
||||||
// Initialize first sample
|
// Initialize first sample
|
||||||
Samples.ForEach(s => initializeSampleInfo(s, samplePoint));
|
Samples.ForEach(s => initializeSampleInfo(s, soundPoint));
|
||||||
|
|
||||||
// Initialize any repeat samples
|
// Initialize any repeat samples
|
||||||
var repeatData = this as IHasRepeats;
|
var repeatData = this as IHasRepeats;
|
||||||
repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, samplePoint)));
|
repeatData?.RepeatSamples?.ForEach(r => r.ForEach(s => initializeSampleInfo(s, soundPoint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeSampleInfo(SampleInfo sample, ControlPoint controlPoint)
|
private void initializeSampleInfo(SampleInfo sample, SoundControlPoint soundPoint)
|
||||||
{
|
{
|
||||||
if (sample.Volume == 0)
|
if (sample.Volume == 0)
|
||||||
sample.Volume = controlPoint?.SampleVolume ?? 0;
|
sample.Volume = soundPoint?.SampleVolume ?? 0;
|
||||||
|
|
||||||
// If the bank is not assigned a name, assign it from the control point
|
// If the bank is not assigned a name, assign it from the control point
|
||||||
if (string.IsNullOrEmpty(sample.Bank))
|
if (string.IsNullOrEmpty(sample.Bank))
|
||||||
sample.Bank = controlPoint?.SampleBank ?? @"normal";
|
sample.Bank = soundPoint?.SampleBank ?? @"normal";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
// Apply defaults
|
// Apply defaults
|
||||||
foreach (var h in Beatmap.HitObjects)
|
foreach (var h in Beatmap.HitObjects)
|
||||||
h.ApplyDefaults(Beatmap.TimingInfo, Beatmap.BeatmapInfo.Difficulty);
|
h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.Difficulty);
|
||||||
|
|
||||||
// Post-process the beatmap
|
// Post-process the beatmap
|
||||||
processor.PostProcess(Beatmap);
|
processor.PostProcess(Beatmap);
|
||||||
|
@ -8,7 +8,10 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Beatmaps.IO;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
@ -19,6 +22,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
private readonly OsuLogo logo;
|
private readonly OsuLogo logo;
|
||||||
|
|
||||||
|
public const string MENU_MUSIC_BEATMAP_HASH = "21c1271b91234385978b5418881fdd88";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether we have loaded the menu previously.
|
/// Whether we have loaded the menu previously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -27,7 +32,6 @@ namespace osu.Game.Screens.Menu
|
|||||||
private MainMenu mainMenu;
|
private MainMenu mainMenu;
|
||||||
private SampleChannel welcome;
|
private SampleChannel welcome;
|
||||||
private SampleChannel seeya;
|
private SampleChannel seeya;
|
||||||
private Track bgm;
|
|
||||||
|
|
||||||
internal override bool HasLocalCursorDisplayed => true;
|
internal override bool HasLocalCursorDisplayed => true;
|
||||||
|
|
||||||
@ -60,15 +64,49 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private Bindable<bool> menuVoice;
|
private Bindable<bool> menuVoice;
|
||||||
private Bindable<bool> menuMusic;
|
private Bindable<bool> menuMusic;
|
||||||
|
private Track track;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio, OsuConfigManager config)
|
private void load(AudioManager audio, OsuConfigManager config, BeatmapDatabase beatmaps, Framework.Game game)
|
||||||
{
|
{
|
||||||
menuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
|
menuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
|
||||||
menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
||||||
|
|
||||||
bgm = audio.Track.Get(@"circles");
|
var trackManager = audio.Track;
|
||||||
bgm.Looping = true;
|
|
||||||
|
BeatmapSetInfo setInfo = null;
|
||||||
|
|
||||||
|
if (!menuMusic)
|
||||||
|
{
|
||||||
|
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => !b.DeletePending);
|
||||||
|
int count = query.Count();
|
||||||
|
if (count > 0)
|
||||||
|
setInfo = query.ElementAt(RNG.Next(0, count - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setInfo == null)
|
||||||
|
{
|
||||||
|
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => b.Hash == MENU_MUSIC_BEATMAP_HASH);
|
||||||
|
|
||||||
|
setInfo = query.FirstOrDefault();
|
||||||
|
|
||||||
|
if (setInfo == null)
|
||||||
|
{
|
||||||
|
// we need to import the default menu background beatmap
|
||||||
|
beatmaps.Import(new OszArchiveReader(game.Resources.GetStream(@"Tracks/circles.osz")));
|
||||||
|
|
||||||
|
setInfo = query.First();
|
||||||
|
|
||||||
|
setInfo.DeletePending = true;
|
||||||
|
beatmaps.Update(setInfo, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
beatmaps.GetChildren(setInfo);
|
||||||
|
Beatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
|
||||||
|
|
||||||
|
track = Beatmap.Track;
|
||||||
|
trackManager.SetExclusive(track);
|
||||||
|
|
||||||
welcome = audio.Sample.Get(@"welcome");
|
welcome = audio.Sample.Get(@"welcome");
|
||||||
seeya = audio.Sample.Get(@"seeya");
|
seeya = audio.Sample.Get(@"seeya");
|
||||||
@ -83,8 +121,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
Scheduler.AddDelayed(delegate
|
Scheduler.AddDelayed(delegate
|
||||||
{
|
{
|
||||||
if (menuMusic)
|
track.Start();
|
||||||
bgm.Start();
|
|
||||||
|
|
||||||
LoadComponentAsync(mainMenu = new MainMenu());
|
LoadComponentAsync(mainMenu = new MainMenu());
|
||||||
|
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2017 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.Threading.Tasks;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
using osu.Game.Screens.Charts;
|
using osu.Game.Screens.Charts;
|
||||||
@ -54,36 +48,18 @@ namespace osu.Game.Screens.Menu
|
|||||||
OnSolo = delegate { Push(consumeSongSelect()); },
|
OnSolo = delegate { Push(consumeSongSelect()); },
|
||||||
OnMulti = delegate { Push(new Lobby()); },
|
OnMulti = delegate { Push(new Lobby()); },
|
||||||
OnExit = delegate { Exit(); },
|
OnExit = delegate { Exit(); },
|
||||||
}
|
},
|
||||||
|
new MenuSideFlashes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bindable<bool> menuMusic;
|
|
||||||
private TrackManager trackManager;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuGame game, OsuConfigManager config, BeatmapDatabase beatmaps)
|
private void load(OsuGame game)
|
||||||
{
|
{
|
||||||
menuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
|
||||||
LoadComponentAsync(background);
|
LoadComponentAsync(background);
|
||||||
|
|
||||||
if (!menuMusic)
|
|
||||||
{
|
|
||||||
trackManager = game.Audio.Track;
|
|
||||||
|
|
||||||
var query = beatmaps.Query<BeatmapSetInfo>().Where(b => !b.DeletePending);
|
|
||||||
int count = query.Count();
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
var beatmap = query.ElementAt(RNG.Next(0, count - 1));
|
|
||||||
beatmaps.GetChildren(beatmap);
|
|
||||||
Beatmap = beatmaps.GetWorkingBeatmap(beatmap.Beatmaps[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons.OnSettings = game.ToggleSettings;
|
buttons.OnSettings = game.ToggleSettings;
|
||||||
buttons.OnDirect = game.ToggleDirect;
|
buttons.OnDirect = game.ToggleDirect;
|
||||||
|
|
||||||
@ -109,14 +85,13 @@ namespace osu.Game.Screens.Menu
|
|||||||
buttons.FadeInFromZero(500);
|
buttons.FadeInFromZero(500);
|
||||||
if (last is Intro && Beatmap != null)
|
if (last is Intro && Beatmap != null)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
if (!Beatmap.Track.IsRunning)
|
||||||
{
|
{
|
||||||
trackManager.SetExclusive(Beatmap.Track);
|
|
||||||
Beatmap.Track.Seek(Beatmap.Metadata.PreviewTime);
|
Beatmap.Track.Seek(Beatmap.Metadata.PreviewTime);
|
||||||
if (Beatmap.Metadata.PreviewTime == -1)
|
if (Beatmap.Metadata.PreviewTime == -1)
|
||||||
Beatmap.Track.Seek(Beatmap.Track.Length * 0.4f);
|
Beatmap.Track.Seek(Beatmap.Track.Length * 0.4f);
|
||||||
Beatmap.Track.Start();
|
Beatmap.Track.Start();
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
96
osu.Game/Screens/Menu/MenuSideFlashes.cs
Normal file
96
osu.Game/Screens/Menu/MenuSideFlashes.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Menu
|
||||||
|
{
|
||||||
|
public class MenuSideFlashes : BeatSyncedContainer
|
||||||
|
{
|
||||||
|
public override bool HandleInput => false;
|
||||||
|
|
||||||
|
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
|
private readonly Box leftBox;
|
||||||
|
private readonly Box rightBox;
|
||||||
|
|
||||||
|
private const float amplitude_dead_zone = 0.25f;
|
||||||
|
private const float alpha_multiplier = (1 - amplitude_dead_zone) / 0.55f;
|
||||||
|
private const float kiai_multiplier = (1 - amplitude_dead_zone * 0.95f) / 0.8f;
|
||||||
|
|
||||||
|
private const int box_max_alpha = 200;
|
||||||
|
private const double box_fade_in_time = 65;
|
||||||
|
private const int box_width = 200;
|
||||||
|
|
||||||
|
public MenuSideFlashes()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
leftBox = new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = box_width,
|
||||||
|
Alpha = 0,
|
||||||
|
BlendingMode = BlendingMode.Additive,
|
||||||
|
},
|
||||||
|
rightBox = new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = box_width,
|
||||||
|
Alpha = 0,
|
||||||
|
BlendingMode = BlendingMode.Additive,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuGameBase game, OsuColour colours)
|
||||||
|
{
|
||||||
|
beatmap.BindTo(game.Beatmap);
|
||||||
|
|
||||||
|
// linear colour looks better in this case, so let's use it for now.
|
||||||
|
Color4 gradientDark = colours.Blue.Opacity(0).ToLinear();
|
||||||
|
Color4 gradientLight = colours.Blue.Opacity(0.3f).ToLinear();
|
||||||
|
|
||||||
|
leftBox.ColourInfo = ColourInfo.GradientHorizontal(gradientLight, gradientDark);
|
||||||
|
rightBox.ColourInfo = ColourInfo.GradientHorizontal(gradientDark, gradientLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||||
|
{
|
||||||
|
if (beatIndex < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (effectPoint.KiaiMode ? beatIndex % 2 == 0 : beatIndex % (int)timingPoint.TimeSignature == 0)
|
||||||
|
flash(leftBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
|
||||||
|
if (effectPoint.KiaiMode ? beatIndex % 2 == 1 : beatIndex % (int)timingPoint.TimeSignature == 0)
|
||||||
|
flash(rightBox, timingPoint.BeatLength, effectPoint.KiaiMode, amplitudes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flash(Drawable d, double beatLength, bool kiai, TrackAmplitudes amplitudes)
|
||||||
|
{
|
||||||
|
d.FadeTo(Math.Max(0, ((d.Equals(leftBox) ? amplitudes.LeftChannel : amplitudes.RightChannel) - amplitude_dead_zone) / (kiai ? kiai_multiplier : alpha_multiplier)), box_fade_in_time);
|
||||||
|
using (d.BeginDelayedSequence(box_fade_in_time))
|
||||||
|
d.FadeOut(beatLength, EasingTypes.In);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,13 +5,16 @@ using System;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Audio.Track;
|
||||||
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.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Backgrounds;
|
using osu.Game.Graphics.Backgrounds;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
@ -20,13 +23,15 @@ namespace osu.Game.Screens.Menu
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// osu! logo and its attachments (pulsing, visualiser etc.)
|
/// osu! logo and its attachments (pulsing, visualiser etc.)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OsuLogo : Container
|
public class OsuLogo : BeatSyncedContainer
|
||||||
{
|
{
|
||||||
public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1");
|
public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1");
|
||||||
|
|
||||||
private readonly Sprite logo;
|
private readonly Sprite logo;
|
||||||
private readonly CircularContainer logoContainer;
|
private readonly CircularContainer logoContainer;
|
||||||
private readonly Container logoBounceContainer;
|
private readonly Container logoBounceContainer;
|
||||||
|
private readonly Container logoBeatContainer;
|
||||||
|
private readonly Container logoAmplitudeContainer;
|
||||||
private readonly Container logoHoverContainer;
|
private readonly Container logoHoverContainer;
|
||||||
|
|
||||||
private SampleChannel sampleClick;
|
private SampleChannel sampleClick;
|
||||||
@ -67,8 +72,12 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private const float default_size = 480;
|
private const float default_size = 480;
|
||||||
|
|
||||||
|
private const double beat_in_time = 60;
|
||||||
|
|
||||||
public OsuLogo()
|
public OsuLogo()
|
||||||
{
|
{
|
||||||
|
EarlyActivationMilliseconds = beat_in_time;
|
||||||
|
|
||||||
Size = new Vector2(default_size);
|
Size = new Vector2(default_size);
|
||||||
|
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
@ -78,67 +87,16 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
logoBounceContainer = new Container
|
logoHoverContainer = new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
logoHoverContainer = new Container
|
logoBounceContainer = new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new BufferedContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
logoContainer = new CircularContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Scale = new Vector2(0.88f),
|
|
||||||
Masking = true,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
colourAndTriangles = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = OsuPink,
|
|
||||||
},
|
|
||||||
new Triangles
|
|
||||||
{
|
|
||||||
TriangleScale = 4,
|
|
||||||
ColourLight = OsuColour.FromHex(@"ff7db7"),
|
|
||||||
ColourDark = OsuColour.FromHex(@"de5b95"),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
flashLayer = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
BlendingMode = BlendingMode.Additive,
|
|
||||||
Colour = Color4.White,
|
|
||||||
Alpha = 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
logo = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rippleContainer = new Container
|
rippleContainer = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
@ -151,36 +109,101 @@ namespace osu.Game.Screens.Menu
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
BlendingMode = BlendingMode.Additive,
|
BlendingMode = BlendingMode.Additive,
|
||||||
Alpha = 0.15f
|
Alpha = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
impactContainer = new CircularContainer
|
logoAmplitudeContainer = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
AutoSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Alpha = 0,
|
|
||||||
BorderColour = Color4.White,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
BorderThickness = 10,
|
|
||||||
Masking = true,
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
logoBeatContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
AlwaysPresent = true,
|
Children = new Drawable[]
|
||||||
Alpha = 0,
|
{
|
||||||
|
new BufferedContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
logoContainer = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Scale = new Vector2(0.88f),
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
colourAndTriangles = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuPink,
|
||||||
|
},
|
||||||
|
new Triangles
|
||||||
|
{
|
||||||
|
TriangleScale = 4,
|
||||||
|
ColourLight = OsuColour.FromHex(@"ff7db7"),
|
||||||
|
ColourDark = OsuColour.FromHex(@"de5b95"),
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
flashLayer = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BlendingMode = BlendingMode.Additive,
|
||||||
|
Colour = Color4.White,
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
logo = new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
impactContainer = new CircularContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Alpha = 0,
|
||||||
|
BorderColour = Color4.White,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BorderThickness = 10,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
AlwaysPresent = true,
|
||||||
|
Alpha = 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new MenuVisualisation
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
BlendingMode = BlendingMode.Additive,
|
||||||
|
Alpha = 0.2f,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
new MenuVisualisation
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
BlendingMode = BlendingMode.Additive,
|
|
||||||
Alpha = 0.2f,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,13 +220,48 @@ namespace osu.Game.Screens.Menu
|
|||||||
ripple.Texture = textures.Get(@"Menu/logo");
|
ripple.Texture = textures.Get(@"Menu/logo");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
private int lastBeatIndex;
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
|
|
||||||
ripple.ScaleTo(ripple.Scale * 1.1f, 500);
|
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes)
|
||||||
ripple.FadeOut(500);
|
{
|
||||||
ripple.Loop(300);
|
base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
|
||||||
|
|
||||||
|
lastBeatIndex = beatIndex;
|
||||||
|
|
||||||
|
var beatLength = timingPoint.BeatLength;
|
||||||
|
|
||||||
|
float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum);
|
||||||
|
|
||||||
|
if (beatIndex < 0) return;
|
||||||
|
|
||||||
|
logoBeatContainer.ScaleTo(1 - 0.02f * amplitudeAdjust, beat_in_time, EasingTypes.Out);
|
||||||
|
using (logoBeatContainer.BeginDelayedSequence(beat_in_time))
|
||||||
|
logoBeatContainer.ScaleTo(1, beatLength * 2, EasingTypes.OutQuint);
|
||||||
|
|
||||||
|
ripple.ClearTransforms();
|
||||||
|
|
||||||
|
ripple.ScaleTo(logoAmplitudeContainer.Scale);
|
||||||
|
ripple.Alpha = 0.15f * amplitudeAdjust;
|
||||||
|
|
||||||
|
ripple.ScaleTo(logoAmplitudeContainer.Scale * (1 + 0.04f * amplitudeAdjust), beatLength, EasingTypes.OutQuint);
|
||||||
|
ripple.FadeOut(beatLength, EasingTypes.OutQuint);
|
||||||
|
|
||||||
|
if (effectPoint.KiaiMode && flashLayer.Alpha < 0.4f)
|
||||||
|
{
|
||||||
|
flashLayer.ClearTransforms();
|
||||||
|
|
||||||
|
flashLayer.FadeTo(0.2f * amplitudeAdjust, beat_in_time, EasingTypes.Out);
|
||||||
|
using (flashLayer.BeginDelayedSequence(beat_in_time))
|
||||||
|
flashLayer.FadeOut(beatLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value?.Track?.CurrentAmplitudes.Maximum ?? 0 : 0;
|
||||||
|
logoAmplitudeContainer.ScaleTo(1 - maxAmplitude * 0.04f, 50, EasingTypes.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||||
@ -254,4 +312,4 @@ namespace osu.Game.Screens.Menu
|
|||||||
impactContainer.ScaleTo(1.12f, 250);
|
impactContainer.ScaleTo(1.12f, 250);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ namespace osu.Game.Screens.Play
|
|||||||
public readonly SongProgress Progress;
|
public readonly SongProgress Progress;
|
||||||
public readonly ModDisplay ModDisplay;
|
public readonly ModDisplay ModDisplay;
|
||||||
|
|
||||||
private Bindable<bool> showKeyCounter;
|
|
||||||
private Bindable<bool> showHud;
|
private Bindable<bool> showHud;
|
||||||
|
|
||||||
private static bool hasShownNotificationOnce;
|
private static bool hasShownNotificationOnce;
|
||||||
@ -67,24 +66,8 @@ namespace osu.Game.Screens.Play
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuConfigManager config, NotificationManager notificationManager)
|
private void load(OsuConfigManager config, NotificationManager notificationManager)
|
||||||
{
|
{
|
||||||
showKeyCounter = config.GetBindable<bool>(OsuSetting.KeyOverlay);
|
|
||||||
showKeyCounter.ValueChanged += keyCounterVisibility =>
|
|
||||||
{
|
|
||||||
if (keyCounterVisibility)
|
|
||||||
KeyCounter.FadeIn(duration);
|
|
||||||
else
|
|
||||||
KeyCounter.FadeOut(duration);
|
|
||||||
};
|
|
||||||
showKeyCounter.TriggerChange();
|
|
||||||
|
|
||||||
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
||||||
showHud.ValueChanged += hudVisibility =>
|
showHud.ValueChanged += hudVisibility => content.FadeTo(hudVisibility ? 1 : 0, duration);
|
||||||
{
|
|
||||||
if (hudVisibility)
|
|
||||||
content.FadeIn(duration);
|
|
||||||
else
|
|
||||||
content.FadeOut(duration);
|
|
||||||
};
|
|
||||||
showHud.TriggerChange();
|
showHud.TriggerChange();
|
||||||
|
|
||||||
if (!showHud && !hasShownNotificationOnce)
|
if (!showHud && !hasShownNotificationOnce)
|
||||||
|
@ -6,11 +6,18 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
public class KeyCounterCollection : FillFlowContainer<KeyCounter>
|
public class KeyCounterCollection : FillFlowContainer<KeyCounter>
|
||||||
{
|
{
|
||||||
|
private const int duration = 100;
|
||||||
|
|
||||||
|
private Bindable<bool> showKeyCounter;
|
||||||
|
|
||||||
public KeyCounterCollection()
|
public KeyCounterCollection()
|
||||||
{
|
{
|
||||||
AlwaysReceiveInput = true;
|
AlwaysReceiveInput = true;
|
||||||
@ -34,6 +41,14 @@ namespace osu.Game.Screens.Play
|
|||||||
counter.ResetCount();
|
counter.ResetCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
showKeyCounter = config.GetBindable<bool>(OsuSetting.KeyOverlay);
|
||||||
|
showKeyCounter.ValueChanged += keyCounterVisibility => FadeTo(keyCounterVisibility ? 1 : 0, duration);
|
||||||
|
showKeyCounter.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
//further: change default values here and in KeyCounter if needed, instead of passing them in every constructor
|
//further: change default values here and in KeyCounter if needed, instead of passing them in every constructor
|
||||||
private bool isCounting;
|
private bool isCounting;
|
||||||
public bool IsCounting
|
public bool IsCounting
|
||||||
|
@ -123,7 +123,7 @@ namespace osu.Game.Screens.Play
|
|||||||
decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
||||||
|
|
||||||
var firstObjectTime = HitRenderer.Objects.First().StartTime;
|
var firstObjectTime = HitRenderer.Objects.First().StartTime;
|
||||||
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Beatmap.TimingInfo.BeatLengthAt(firstObjectTime) * 4, Beatmap.BeatmapInfo.AudioLeadIn)));
|
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.BeatmapInfo.AudioLeadIn)));
|
||||||
decoupledClock.ProcessFrame();
|
decoupledClock.ProcessFrame();
|
||||||
|
|
||||||
offsetClock = new FramedOffsetClock(decoupledClock);
|
offsetClock = new FramedOffsetClock(decoupledClock);
|
||||||
|
@ -170,8 +170,8 @@ namespace osu.Game.Screens.Select
|
|||||||
List<BeatmapGroup> visibleGroups = groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden).ToList();
|
List<BeatmapGroup> visibleGroups = groups.Where(selectGroup => selectGroup.State != BeatmapGroupState.Hidden).ToList();
|
||||||
if (visibleGroups.Count < 1)
|
if (visibleGroups.Count < 1)
|
||||||
return;
|
return;
|
||||||
BeatmapGroup group = visibleGroups[RNG.Next(visibleGroups.Count)];
|
|
||||||
|
|
||||||
|
BeatmapGroup group = visibleGroups[RNG.Next(visibleGroups.Count)];
|
||||||
BeatmapPanel panel = group.BeatmapPanels[RNG.Next(group.BeatmapPanels.Count)];
|
BeatmapPanel panel = group.BeatmapPanels[RNG.Next(group.BeatmapPanels.Count)];
|
||||||
|
|
||||||
selectGroup(group, panel);
|
selectGroup(group, panel);
|
||||||
|
@ -238,12 +238,12 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private string getBPMRange(Beatmap beatmap)
|
private string getBPMRange(Beatmap beatmap)
|
||||||
{
|
{
|
||||||
double bpmMax = beatmap.TimingInfo.BPMMaximum;
|
double bpmMax = beatmap.ControlPointInfo.BPMMaximum;
|
||||||
double bpmMin = beatmap.TimingInfo.BPMMinimum;
|
double bpmMin = beatmap.ControlPointInfo.BPMMinimum;
|
||||||
|
|
||||||
if (Precision.AlmostEquals(bpmMin, bpmMax)) return Math.Round(bpmMin) + "bpm";
|
if (Precision.AlmostEquals(bpmMin, bpmMax)) return Math.Round(bpmMin) + "bpm";
|
||||||
|
|
||||||
return Math.Round(bpmMin) + "-" + Math.Round(bpmMax) + "bpm (mostly " + Math.Round(beatmap.TimingInfo.BPMMode) + "bpm)";
|
return Math.Round(bpmMin) + "-" + Math.Round(bpmMax) + "bpm (mostly " + Math.Round(beatmap.ControlPointInfo.BPMMode) + "bpm)";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InfoLabel : Container
|
public class InfoLabel : Container
|
||||||
|
@ -316,11 +316,12 @@ namespace osu.Game.Screens.Select
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void selectionChanged(BeatmapInfo beatmap)
|
private void selectionChanged(BeatmapInfo beatmap)
|
||||||
{
|
{
|
||||||
bool beatmapSetChange = false;
|
selectionChangedDebounce?.Cancel();
|
||||||
|
|
||||||
if (beatmap.Equals(Beatmap?.BeatmapInfo))
|
if (beatmap.Equals(Beatmap?.BeatmapInfo))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bool beatmapSetChange = false;
|
||||||
if (beatmap.BeatmapSetInfoID == selectionChangeNoBounce?.BeatmapSetInfoID)
|
if (beatmap.BeatmapSetInfoID == selectionChangeNoBounce?.BeatmapSetInfoID)
|
||||||
sampleChangeDifficulty.Play();
|
sampleChangeDifficulty.Play();
|
||||||
else
|
else
|
||||||
@ -331,7 +332,6 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
selectionChangeNoBounce = beatmap;
|
selectionChangeNoBounce = beatmap;
|
||||||
|
|
||||||
selectionChangedDebounce?.Cancel();
|
|
||||||
selectionChangedDebounce = Scheduler.AddDelayed(delegate
|
selectionChangedDebounce = Scheduler.AddDelayed(delegate
|
||||||
{
|
{
|
||||||
Beatmap = database.GetWorkingBeatmap(beatmap, Beatmap);
|
Beatmap = database.GetWorkingBeatmap(beatmap, Beatmap);
|
||||||
|
@ -87,10 +87,15 @@
|
|||||||
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
|
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
|
||||||
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
|
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
|
||||||
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
|
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
|
||||||
|
<Compile Include="Beatmaps\ControlPoints\ControlPoint.cs" />
|
||||||
|
<Compile Include="Beatmaps\ControlPoints\ControlPointInfo.cs" />
|
||||||
|
<Compile Include="Beatmaps\ControlPoints\DifficultyControlPoint.cs" />
|
||||||
|
<Compile Include="Beatmaps\ControlPoints\EffectControlPoint.cs" />
|
||||||
|
<Compile Include="Beatmaps\ControlPoints\SoundControlPoint.cs" />
|
||||||
|
<Compile Include="Beatmaps\ControlPoints\TimingControlPoint.cs" />
|
||||||
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
|
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
|
||||||
<Compile Include="Beatmaps\Timing\BreakPeriod.cs" />
|
<Compile Include="Beatmaps\Timing\BreakPeriod.cs" />
|
||||||
<Compile Include="Beatmaps\Timing\TimeSignatures.cs" />
|
<Compile Include="Beatmaps\Timing\TimeSignatures.cs" />
|
||||||
<Compile Include="Beatmaps\Timing\TimingInfo.cs" />
|
|
||||||
<Compile Include="Database\BeatmapMetrics.cs" />
|
<Compile Include="Database\BeatmapMetrics.cs" />
|
||||||
<Compile Include="Database\Database.cs" />
|
<Compile Include="Database\Database.cs" />
|
||||||
<Compile Include="Database\RulesetInfo.cs" />
|
<Compile Include="Database\RulesetInfo.cs" />
|
||||||
@ -184,6 +189,7 @@
|
|||||||
<Compile Include="Database\RulesetDatabase.cs" />
|
<Compile Include="Database\RulesetDatabase.cs" />
|
||||||
<Compile Include="Rulesets\Scoring\Score.cs" />
|
<Compile Include="Rulesets\Scoring\Score.cs" />
|
||||||
<Compile Include="Rulesets\Scoring\ScoreProcessor.cs" />
|
<Compile Include="Rulesets\Scoring\ScoreProcessor.cs" />
|
||||||
|
<Compile Include="Screens\Menu\MenuSideFlashes.cs" />
|
||||||
<Compile Include="Screens\Play\HUD\HealthDisplay.cs" />
|
<Compile Include="Screens\Play\HUD\HealthDisplay.cs" />
|
||||||
<Compile Include="Screens\Play\HUDOverlay.cs" />
|
<Compile Include="Screens\Play\HUDOverlay.cs" />
|
||||||
<Compile Include="Screens\Play\HUD\StandardHealthDisplay.cs" />
|
<Compile Include="Screens\Play\HUD\StandardHealthDisplay.cs" />
|
||||||
@ -202,7 +208,6 @@
|
|||||||
<Compile Include="Beatmaps\Drawables\Panel.cs" />
|
<Compile Include="Beatmaps\Drawables\Panel.cs" />
|
||||||
<Compile Include="Rulesets\Objects\Drawables\DrawableHitObject.cs" />
|
<Compile Include="Rulesets\Objects\Drawables\DrawableHitObject.cs" />
|
||||||
<Compile Include="Rulesets\Objects\HitObject.cs" />
|
<Compile Include="Rulesets\Objects\HitObject.cs" />
|
||||||
<Compile Include="Beatmaps\Timing\ControlPoint.cs" />
|
|
||||||
<Compile Include="Configuration\OsuConfigManager.cs" />
|
<Compile Include="Configuration\OsuConfigManager.cs" />
|
||||||
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
|
<Compile Include="Overlays\Notifications\IHasCompletionTarget.cs" />
|
||||||
<Compile Include="Overlays\Notifications\Notification.cs" />
|
<Compile Include="Overlays\Notifications\Notification.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user