mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 12:33:01 +08:00
Merge remote-tracking branch 'upstream/master' into url-parsing-support
# Conflicts: # osu.Game/osu.Game.csproj
This commit is contained in:
commit
a5b0d51205
2
LICENCE
2
LICENCE
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit aa111a4362acc50d5684be62675685041948894f
|
Subproject commit 209021fb491e21625127be5dbf5efb4c409e6f06
|
@ -1 +1 @@
|
|||||||
Subproject commit 7724abdf1d7c9705ba2e3989a9c604e17ccdc871
|
Subproject commit 266965f0d795b94a126e2da302bd2c10eadd642a
|
@ -12,12 +12,12 @@
|
|||||||
<description>click the circles. to the beat.</description>
|
<description>click the circles. to the beat.</description>
|
||||||
<summary>click the circles.</summary>
|
<summary>click the circles.</summary>
|
||||||
<releaseNotes>testing</releaseNotes>
|
<releaseNotes>testing</releaseNotes>
|
||||||
<copyright>Copyright ppy Pty Ltd 2007-2017</copyright>
|
<copyright>Copyright ppy Pty Ltd 2007-2018</copyright>
|
||||||
<language>en-AU</language>
|
<language>en-AU</language>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/>
|
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/>
|
||||||
<file src="*.dll" target="lib\net45\"/>
|
<file src="*.dll" target="lib\net45\"/>
|
||||||
<file src="*.config" target="lib\net45\"/>
|
<file src="*.config" target="lib\net45\"/>
|
||||||
<file src="x86\*.dll" target="lib\net45\x86\"/>
|
<file src="x86\*.dll" target="lib\net45\x86\"/>
|
||||||
<file src="x64\*.dll" target="lib\net45\x64\"/>
|
<file src="x64\*.dll" target="lib\net45\x64\"/>
|
||||||
|
@ -23,6 +23,5 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
MoveRight,
|
MoveRight,
|
||||||
[Description("Engage dash")]
|
[Description("Engage dash")]
|
||||||
Dash,
|
Dash,
|
||||||
PositionUpdate
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const float base_scoring_distance = 100;
|
private const float base_scoring_distance = 100;
|
||||||
|
|
||||||
public readonly SliderCurve Curve = new SliderCurve();
|
public int RepeatCount { get; set; }
|
||||||
|
|
||||||
public int RepeatCount { get; set; } = 1;
|
|
||||||
|
|
||||||
public double Velocity;
|
public double Velocity;
|
||||||
public double TickDistance;
|
public double TickDistance;
|
||||||
@ -55,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
|
|
||||||
var length = Curve.Distance;
|
var length = Curve.Distance;
|
||||||
var tickDistance = Math.Min(TickDistance, length);
|
var tickDistance = Math.Min(TickDistance, length);
|
||||||
var repeatDuration = length / Velocity;
|
var spanDuration = length / Velocity;
|
||||||
|
|
||||||
var minDistanceFromEnd = Velocity * 0.01;
|
var minDistanceFromEnd = Velocity * 0.01;
|
||||||
|
|
||||||
@ -67,10 +65,10 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
X = X
|
X = X
|
||||||
});
|
});
|
||||||
|
|
||||||
for (var repeat = 0; repeat < RepeatCount; repeat++)
|
for (var span = 0; span < this.SpanCount(); span++)
|
||||||
{
|
{
|
||||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
var spanStartTime = StartTime + span * spanDuration;
|
||||||
var reversed = repeat % 2 == 1;
|
var reversed = span % 2 == 1;
|
||||||
|
|
||||||
for (var d = tickDistance; d <= length; d += tickDistance)
|
for (var d = tickDistance; d <= length; d += tickDistance)
|
||||||
{
|
{
|
||||||
@ -80,7 +78,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
var timeProgress = d / length;
|
var timeProgress = d / length;
|
||||||
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
|
var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
|
||||||
|
|
||||||
var lastTickTime = repeatStartTime + timeProgress * repeatDuration;
|
var lastTickTime = spanStartTime + timeProgress * spanDuration;
|
||||||
AddNested(new Droplet
|
AddNested(new Droplet
|
||||||
{
|
{
|
||||||
StartTime = lastTickTime,
|
StartTime = lastTickTime,
|
||||||
@ -95,17 +93,17 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
double tinyTickInterval = tickDistance / length * repeatDuration;
|
double tinyTickInterval = tickDistance / length * spanDuration;
|
||||||
while (tinyTickInterval > 100)
|
while (tinyTickInterval > 100)
|
||||||
tinyTickInterval /= 2;
|
tinyTickInterval /= 2;
|
||||||
|
|
||||||
for (double t = 0; t < repeatDuration; t += tinyTickInterval)
|
for (double t = 0; t < spanDuration; t += tinyTickInterval)
|
||||||
{
|
{
|
||||||
double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration;
|
double progress = reversed ? 1 - t / spanDuration : t / spanDuration;
|
||||||
|
|
||||||
AddNested(new TinyDroplet
|
AddNested(new TinyDroplet
|
||||||
{
|
{
|
||||||
StartTime = repeatStartTime + t,
|
StartTime = spanStartTime + t,
|
||||||
ComboColour = ComboColour,
|
ComboColour = ComboColour,
|
||||||
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
|
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
|
||||||
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
|
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
|
||||||
@ -121,15 +119,15 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
{
|
{
|
||||||
Samples = Samples,
|
Samples = Samples,
|
||||||
ComboColour = ComboColour,
|
ComboColour = ComboColour,
|
||||||
StartTime = repeatStartTime + repeatDuration,
|
StartTime = spanStartTime + spanDuration,
|
||||||
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
|
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
|
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
|
||||||
|
|
||||||
public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH;
|
public float EndX => Curve.PositionAt(this.ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH;
|
||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
@ -139,6 +137,8 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
set { Curve.Distance = value; }
|
set { Curve.Distance = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SliderCurve Curve { get; } = new SliderCurve();
|
||||||
|
|
||||||
public List<Vector2> ControlPoints
|
public List<Vector2> ControlPoints
|
||||||
{
|
{
|
||||||
get { return Curve.ControlPoints; }
|
get { return Curve.ControlPoints; }
|
||||||
@ -152,17 +152,5 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
get { return Curve.CurveType; }
|
get { return Curve.CurveType; }
|
||||||
set { Curve.CurveType = value; }
|
set { Curve.CurveType = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
|
|
||||||
|
|
||||||
public double ProgressAt(double progress)
|
|
||||||
{
|
|
||||||
double p = progress * RepeatCount % 1;
|
|
||||||
if (RepeatAt(progress) % 2 == 1)
|
|
||||||
p = 1 - p;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
@ -23,15 +26,78 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
|
|
||||||
public override Replay Generate()
|
public override Replay Generate()
|
||||||
{
|
{
|
||||||
|
// todo: add support for HT DT
|
||||||
|
const double dash_speed = CatcherArea.Catcher.BASE_SPEED;
|
||||||
|
const double movement_speed = dash_speed / 2;
|
||||||
|
float lastPosition = 0.5f;
|
||||||
|
double lastTime = 0;
|
||||||
|
|
||||||
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
|
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
|
||||||
Replay.Frames.Add(new CatchReplayFrame(-100000, 0));
|
Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition));
|
||||||
|
|
||||||
|
void moveToNext(CatchHitObject h)
|
||||||
|
{
|
||||||
|
float positionChange = Math.Abs(lastPosition - h.X);
|
||||||
|
double timeAvailable = h.StartTime - lastTime;
|
||||||
|
|
||||||
|
//So we can either make it there without a dash or not.
|
||||||
|
double speedRequired = positionChange / timeAvailable;
|
||||||
|
|
||||||
|
bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
|
||||||
|
|
||||||
|
// todo: get correct catcher size, based on difficulty CS.
|
||||||
|
const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
|
||||||
|
|
||||||
|
if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
|
||||||
|
{
|
||||||
|
//we are already in the correct range.
|
||||||
|
lastTime = h.StartTime;
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h is BananaShower.Banana)
|
||||||
|
{
|
||||||
|
// auto bananas unrealistically warp to catch 100% combo.
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||||
|
}
|
||||||
|
else if (h.HyperDash)
|
||||||
|
{
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition, ReplayButtonState.Right1));
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||||
|
}
|
||||||
|
else if (dashRequired)
|
||||||
|
{
|
||||||
|
//we do a movement in two parts - the dash part then the normal part...
|
||||||
|
double timeAtNormalSpeed = positionChange / movement_speed;
|
||||||
|
double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
|
||||||
|
double timeAtDashSpeed = timeWeNeedToSave / 2;
|
||||||
|
|
||||||
|
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
|
||||||
|
|
||||||
|
//dash movement
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, ReplayButtonState.Left1));
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition));
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double timeBefore = positionChange / movement_speed;
|
||||||
|
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition, ReplayButtonState.Right1));
|
||||||
|
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
|
||||||
|
}
|
||||||
|
|
||||||
|
lastTime = h.StartTime;
|
||||||
|
lastPosition = h.X;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var obj in Beatmap.HitObjects)
|
foreach (var obj in Beatmap.HitObjects)
|
||||||
{
|
{
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case Fruit _:
|
case Fruit _:
|
||||||
Replay.Frames.Add(new CatchReplayFrame(obj.StartTime, obj.X));
|
moveToNext(obj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +108,7 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
case BananaShower.Banana _:
|
case BananaShower.Banana _:
|
||||||
case TinyDroplet _:
|
case TinyDroplet _:
|
||||||
case Droplet _:
|
case Droplet _:
|
||||||
Replay.Frames.Add(new CatchReplayFrame(nestedObj.StartTime, nestedObj.X));
|
moveToNext(nestedObj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,29 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<InputState> GetPendingStates() => new List<InputState>
|
public override List<InputState> GetPendingStates()
|
||||||
{
|
{
|
||||||
new CatchReplayState
|
if (!Position.HasValue) return new List<InputState>();
|
||||||
|
|
||||||
|
var action = new List<CatchAction>();
|
||||||
|
|
||||||
|
if (CurrentFrame.ButtonState == ReplayButtonState.Left1)
|
||||||
|
action.Add(CatchAction.Dash);
|
||||||
|
|
||||||
|
if (Position.Value.X > CurrentFrame.Position.X)
|
||||||
|
action.Add(CatchAction.MoveRight);
|
||||||
|
else if (Position.Value.X < CurrentFrame.Position.X)
|
||||||
|
action.Add(CatchAction.MoveLeft);
|
||||||
|
|
||||||
|
return new List<InputState>
|
||||||
{
|
{
|
||||||
PressedActions = new List<CatchAction> { CatchAction.PositionUpdate },
|
new CatchReplayState
|
||||||
CatcherX = ((CatchReplayFrame)CurrentFrame).MouseX
|
{
|
||||||
},
|
PressedActions = action,
|
||||||
new CatchReplayState { PressedActions = new List<CatchAction>() },
|
CatcherX = Position.Value.X
|
||||||
};
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public class CatchReplayState : ReplayState<CatchAction>
|
public class CatchReplayState : ReplayState<CatchAction>
|
||||||
{
|
{
|
||||||
|
@ -9,8 +9,8 @@ namespace osu.Game.Rulesets.Catch.Replays
|
|||||||
{
|
{
|
||||||
public override bool IsImportant => MouseX > 0;
|
public override bool IsImportant => MouseX > 0;
|
||||||
|
|
||||||
public CatchReplayFrame(double time, float? x = null)
|
public CatchReplayFrame(double time, float? x = null, ReplayButtonState button = ReplayButtonState.None)
|
||||||
: base(time, x ?? -1, null, ReplayButtonState.None)
|
: base(time, x ?? -1, null, button)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ using OpenTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.UI
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
{
|
{
|
||||||
public class CatcherArea : Container, IKeyBindingHandler<CatchAction>
|
public class CatcherArea : Container
|
||||||
{
|
{
|
||||||
public const float CATCHER_SIZE = 172;
|
public const float CATCHER_SIZE = 172;
|
||||||
|
|
||||||
@ -84,16 +84,14 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(CatchAction action)
|
protected override void Update()
|
||||||
{
|
{
|
||||||
if (action != CatchAction.PositionUpdate) return false;
|
base.Update();
|
||||||
|
|
||||||
CatchFramedReplayInputHandler.CatchReplayState state = (CatchFramedReplayInputHandler.CatchReplayState)GetContainingInputManager().CurrentState;
|
var state = GetContainingInputManager().CurrentState as CatchFramedReplayInputHandler.CatchReplayState;
|
||||||
|
|
||||||
if (state.CatcherX.HasValue)
|
if (state?.CatcherX != null)
|
||||||
MovableCatcher.X = state.CatcherX.Value;
|
MovableCatcher.X = state.CatcherX.Value;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnReleased(CatchAction action) => false;
|
public bool OnReleased(CatchAction action) => false;
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The definitions for each stage in a <see cref="ManiaPlayfield"/>.
|
/// The definitions for each stage in a <see cref="ManiaPlayfield"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly List<StageDefinition> Stages = new List<StageDefinition>();
|
public List<StageDefinition> Stages = new List<StageDefinition>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total number of columns represented by all stages in this <see cref="ManiaBeatmap"/>.
|
/// Total number of columns represented by all stages in this <see cref="ManiaBeatmap"/>.
|
||||||
@ -24,10 +24,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="ManiaBeatmap"/>.
|
/// Creates a new <see cref="ManiaBeatmap"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="initialStage">The initial stage.</param>
|
/// <param name="defaultStage">The initial stages.</param>
|
||||||
public ManiaBeatmap(StageDefinition initialStage)
|
public ManiaBeatmap(StageDefinition defaultStage)
|
||||||
{
|
{
|
||||||
Stages.Add(initialStage);
|
Stages.Add(defaultStage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
if (curveData == null)
|
if (curveData == null)
|
||||||
return HitObject.Samples;
|
return HitObject.Samples;
|
||||||
|
|
||||||
double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.RepeatCount;
|
double segmentTime = (curveData.EndTime - HitObject.StartTime) / curveData.SpanCount();
|
||||||
|
|
||||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||||
return curveData.RepeatSamples[index];
|
return curveData.RepeatSamples[index];
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
private readonly double endTime;
|
private readonly double endTime;
|
||||||
private readonly double segmentDuration;
|
private readonly double segmentDuration;
|
||||||
private readonly int repeatCount;
|
private readonly int spanCount;
|
||||||
|
|
||||||
private PatternType convertType;
|
private PatternType convertType;
|
||||||
|
|
||||||
@ -39,25 +39,25 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
var distanceData = hitObject as IHasDistance;
|
var distanceData = hitObject as IHasDistance;
|
||||||
var repeatsData = hitObject as IHasRepeats;
|
var repeatsData = hitObject as IHasRepeats;
|
||||||
|
|
||||||
repeatCount = repeatsData?.RepeatCount ?? 1;
|
spanCount = repeatsData?.SpanCount() ?? 1;
|
||||||
|
|
||||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime);
|
||||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime);
|
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) * spanCount;
|
||||||
// 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.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength;
|
||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
endTime = hitObject.StartTime + osuDuration;
|
endTime = hitObject.StartTime + osuDuration;
|
||||||
segmentDuration = (endTime - HitObject.StartTime) / repeatCount;
|
segmentDuration = (endTime - HitObject.StartTime) / spanCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Pattern Generate()
|
public override Pattern Generate()
|
||||||
{
|
{
|
||||||
if (repeatCount > 1)
|
if (spanCount > 1)
|
||||||
{
|
{
|
||||||
if (segmentDuration <= 90)
|
if (segmentDuration <= 90)
|
||||||
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
return generateRandomHoldNotes(HitObject.StartTime, 1);
|
||||||
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (segmentDuration <= 120)
|
if (segmentDuration <= 120)
|
||||||
{
|
{
|
||||||
convertType |= PatternType.ForceNotStack;
|
convertType |= PatternType.ForceNotStack;
|
||||||
return generateRandomNotes(HitObject.StartTime, repeatCount + 1);
|
return generateRandomNotes(HitObject.StartTime, spanCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segmentDuration <= 160)
|
if (segmentDuration <= 160)
|
||||||
@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (duration >= 4000)
|
if (duration >= 4000)
|
||||||
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
return generateNRandomNotes(HitObject.StartTime, 0.23, 0, 0);
|
||||||
|
|
||||||
if (segmentDuration > 400 && repeatCount < TotalColumns - 1 - RandomStart)
|
if (segmentDuration > 400 && spanCount < TotalColumns - 1 - RandomStart)
|
||||||
return generateTiledHoldNotes(HitObject.StartTime);
|
return generateTiledHoldNotes(HitObject.StartTime);
|
||||||
|
|
||||||
return generateHoldAndNormalNotes(HitObject.StartTime);
|
return generateHoldAndNormalNotes(HitObject.StartTime);
|
||||||
@ -212,7 +212,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int column = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
bool increasing = Random.NextDouble() > 0.5;
|
bool increasing = Random.NextDouble() > 0.5;
|
||||||
|
|
||||||
for (int i = 0; i <= repeatCount; i++)
|
for (int i = 0; i <= spanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, column, startTime, startTime);
|
addToPattern(pattern, column, startTime, startTime);
|
||||||
startTime += segmentDuration;
|
startTime += segmentDuration;
|
||||||
@ -262,7 +262,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int interval = Random.Next(1, TotalColumns - (legacy ? 1 : 0));
|
int interval = Random.Next(1, TotalColumns - (legacy ? 1 : 0));
|
||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
for (int i = 0; i <= repeatCount; i++)
|
for (int i = 0; i <= spanCount; i++)
|
||||||
{
|
{
|
||||||
addToPattern(pattern, nextColumn, startTime, startTime);
|
addToPattern(pattern, nextColumn, startTime, startTime);
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
|
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
int columnRepeat = Math.Min(repeatCount, TotalColumns);
|
int columnRepeat = Math.Min(spanCount, TotalColumns);
|
||||||
|
|
||||||
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true);
|
||||||
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns)
|
||||||
@ -409,7 +409,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
int nextColumn = Random.Next(RandomStart, TotalColumns);
|
||||||
|
|
||||||
var rowPattern = new Pattern();
|
var rowPattern = new Pattern();
|
||||||
for (int i = 0; i <= repeatCount; i++)
|
for (int i = 0; i <= spanCount; i++)
|
||||||
{
|
{
|
||||||
if (!(ignoreHead && startTime == HitObject.StartTime))
|
if (!(ignoreHead && startTime == HitObject.StartTime))
|
||||||
{
|
{
|
||||||
@ -442,7 +442,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
if (curveData == null)
|
if (curveData == null)
|
||||||
return HitObject.Samples;
|
return HitObject.Samples;
|
||||||
|
|
||||||
double segmentTime = (endTime - HitObject.StartTime) / repeatCount;
|
double segmentTime = (endTime - HitObject.StartTime) / spanCount;
|
||||||
|
|
||||||
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
int index = (int)(segmentTime == 0 ? 0 : (time - HitObject.StartTime) / segmentTime);
|
||||||
return curveData.RepeatSamples[index];
|
return curveData.RepeatSamples[index];
|
||||||
|
34
osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs
Normal file
34
osu.Game.Rulesets.Mania/Configuration/ManiaConfigManager.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Configuration.Tracking;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Configuration;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Configuration
|
||||||
|
{
|
||||||
|
public class ManiaConfigManager : RulesetConfigManager<ManiaSetting>
|
||||||
|
{
|
||||||
|
public ManiaConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant)
|
||||||
|
: base(settings, ruleset, variant)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InitialiseDefaults()
|
||||||
|
{
|
||||||
|
base.InitialiseDefaults();
|
||||||
|
|
||||||
|
Set(ManiaSetting.ScrollTime, 1500.0, 50.0, 10000.0, 50.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||||
|
{
|
||||||
|
new TrackedSetting<double>(ManiaSetting.ScrollTime, v => new SettingDescription(v, "Scroll Time", $"{v}ms"))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ManiaSetting
|
||||||
|
{
|
||||||
|
ScrollTime
|
||||||
|
}
|
||||||
|
}
|
@ -17,8 +17,13 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public enum ManiaAction
|
public enum ManiaAction
|
||||||
{
|
{
|
||||||
[Description("Special")]
|
[Description("Special 1")]
|
||||||
Special,
|
Special1 = 1,
|
||||||
|
[Description("Special 2")]
|
||||||
|
Special2,
|
||||||
|
|
||||||
|
// This offsets the start value of normal keys in-case we add more special keys
|
||||||
|
// above at a later time, without breaking replays/configs.
|
||||||
[Description("Key 1")]
|
[Description("Key 1")]
|
||||||
Key1 = 10,
|
Key1 = 10,
|
||||||
[Description("Key 2")]
|
[Description("Key 2")]
|
||||||
@ -36,6 +41,24 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
[Description("Key 8")]
|
[Description("Key 8")]
|
||||||
Key8,
|
Key8,
|
||||||
[Description("Key 9")]
|
[Description("Key 9")]
|
||||||
Key9
|
Key9,
|
||||||
|
[Description("Key 10")]
|
||||||
|
Key10,
|
||||||
|
[Description("Key 11")]
|
||||||
|
Key11,
|
||||||
|
[Description("Key 12")]
|
||||||
|
Key12,
|
||||||
|
[Description("Key 13")]
|
||||||
|
Key13,
|
||||||
|
[Description("Key 14")]
|
||||||
|
Key14,
|
||||||
|
[Description("Key 15")]
|
||||||
|
Key15,
|
||||||
|
[Description("Key 16")]
|
||||||
|
Key16,
|
||||||
|
[Description("Key 17")]
|
||||||
|
Key17,
|
||||||
|
[Description("Key 18")]
|
||||||
|
Key18,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Mods;
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -86,7 +88,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
new ManiaModRandom(),
|
new ManiaModRandom(),
|
||||||
new ManiaModKeyCoop(),
|
new ManiaModDualStages(),
|
||||||
new MultiMod
|
new MultiMod
|
||||||
{
|
{
|
||||||
Mods = new Mod[]
|
Mods = new Mod[]
|
||||||
@ -117,42 +119,189 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<int> AvailableVariants => new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
public override IEnumerable<int> AvailableVariants
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (int i = 1; i <= 9; i++)
|
||||||
|
yield return (int)PlayfieldType.Single + i;
|
||||||
|
for (int i = 2; i <= 18; i += 2)
|
||||||
|
yield return (int)PlayfieldType.Dual + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
|
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0)
|
||||||
{
|
{
|
||||||
var leftKeys = new[]
|
switch (getPlayfieldType(variant))
|
||||||
{
|
{
|
||||||
InputKey.A,
|
case PlayfieldType.Single:
|
||||||
InputKey.S,
|
return new VariantMappingGenerator
|
||||||
InputKey.D,
|
{
|
||||||
InputKey.F
|
LeftKeys = new[]
|
||||||
};
|
{
|
||||||
|
InputKey.A,
|
||||||
|
InputKey.S,
|
||||||
|
InputKey.D,
|
||||||
|
InputKey.F
|
||||||
|
},
|
||||||
|
RightKeys = new[]
|
||||||
|
{
|
||||||
|
InputKey.J,
|
||||||
|
InputKey.K,
|
||||||
|
InputKey.L,
|
||||||
|
InputKey.Semicolon
|
||||||
|
},
|
||||||
|
SpecialKey = InputKey.Space,
|
||||||
|
SpecialAction = ManiaAction.Special1,
|
||||||
|
NormalActionStart = ManiaAction.Key1,
|
||||||
|
}.GenerateKeyBindingsFor(variant, out _);
|
||||||
|
case PlayfieldType.Dual:
|
||||||
|
int keys = getDualStageKeyCount(variant);
|
||||||
|
|
||||||
var rightKeys = new[]
|
var stage1Bindings = new VariantMappingGenerator
|
||||||
{
|
{
|
||||||
InputKey.J,
|
LeftKeys = new[]
|
||||||
InputKey.K,
|
{
|
||||||
InputKey.L,
|
InputKey.Number1,
|
||||||
InputKey.Semicolon
|
InputKey.Number2,
|
||||||
};
|
InputKey.Number3,
|
||||||
|
InputKey.Number4,
|
||||||
|
},
|
||||||
|
RightKeys = new[]
|
||||||
|
{
|
||||||
|
InputKey.Z,
|
||||||
|
InputKey.X,
|
||||||
|
InputKey.C,
|
||||||
|
InputKey.V
|
||||||
|
},
|
||||||
|
SpecialKey = InputKey.Tilde,
|
||||||
|
SpecialAction = ManiaAction.Special1,
|
||||||
|
NormalActionStart = ManiaAction.Key1
|
||||||
|
}.GenerateKeyBindingsFor(keys, out var nextNormal);
|
||||||
|
|
||||||
ManiaAction currentKey = ManiaAction.Key1;
|
var stage2Bindings = new VariantMappingGenerator
|
||||||
|
{
|
||||||
|
LeftKeys = new[]
|
||||||
|
{
|
||||||
|
InputKey.Number7,
|
||||||
|
InputKey.Number8,
|
||||||
|
InputKey.Number9,
|
||||||
|
InputKey.Number0
|
||||||
|
},
|
||||||
|
RightKeys = new[]
|
||||||
|
{
|
||||||
|
InputKey.O,
|
||||||
|
InputKey.P,
|
||||||
|
InputKey.BracketLeft,
|
||||||
|
InputKey.BracketRight
|
||||||
|
},
|
||||||
|
SpecialKey = InputKey.BackSlash,
|
||||||
|
SpecialAction = ManiaAction.Special2,
|
||||||
|
NormalActionStart = nextNormal
|
||||||
|
}.GenerateKeyBindingsFor(keys, out _);
|
||||||
|
|
||||||
var bindings = new List<KeyBinding>();
|
return stage1Bindings.Concat(stage2Bindings);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = leftKeys.Length - variant / 2; i < leftKeys.Length; i++)
|
return new KeyBinding[0];
|
||||||
bindings.Add(new KeyBinding(leftKeys[i], currentKey++));
|
|
||||||
|
|
||||||
for (int i = 0; i < variant / 2; i++)
|
|
||||||
bindings.Add(new KeyBinding(rightKeys[i], currentKey++));
|
|
||||||
|
|
||||||
if (variant % 2 == 1)
|
|
||||||
bindings.Add(new KeyBinding(InputKey.Space, ManiaAction.Special));
|
|
||||||
|
|
||||||
return bindings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetVariantName(int variant) => $"{variant}K";
|
public override string GetVariantName(int variant)
|
||||||
|
{
|
||||||
|
switch (getPlayfieldType(variant))
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return $"{variant}K";
|
||||||
|
case PlayfieldType.Dual:
|
||||||
|
{
|
||||||
|
var keys = getDualStageKeyCount(variant);
|
||||||
|
return $"{keys}K + {keys}K";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the number of keys for each stage in a <see cref="PlayfieldType.Dual"/> variant.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variant">The variant.</param>
|
||||||
|
private int getDualStageKeyCount(int variant) => (variant - (int)PlayfieldType.Dual) / 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the <see cref="PlayfieldType"/> that corresponds to a variant value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="variant">The variant value.</param>
|
||||||
|
/// <returns>The <see cref="PlayfieldType"/> that corresponds to <paramref name="variant"/>.</returns>
|
||||||
|
private PlayfieldType getPlayfieldType(int variant)
|
||||||
|
{
|
||||||
|
return (PlayfieldType)Enum.GetValues(typeof(PlayfieldType)).Cast<int>().OrderByDescending(i => i).First(v => variant >= v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class VariantMappingGenerator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All the <see cref="InputKey"/>s available to the left hand.
|
||||||
|
/// </summary>
|
||||||
|
public InputKey[] LeftKeys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All the <see cref="InputKey"/>s available to the right hand.
|
||||||
|
/// </summary>
|
||||||
|
public InputKey[] RightKeys;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="InputKey"/> for the special key.
|
||||||
|
/// </summary>
|
||||||
|
public InputKey SpecialKey;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="ManiaAction"/> at which the normal columns should begin.
|
||||||
|
/// </summary>
|
||||||
|
public ManiaAction NormalActionStart;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="ManiaAction"/> for the special column.
|
||||||
|
/// </summary>
|
||||||
|
public ManiaAction SpecialAction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a list of <see cref="KeyBinding"/>s for a specific number of columns.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns">The number of columns that need to be bound.</param>
|
||||||
|
/// <param name="nextNormalAction">The next <see cref="ManiaAction"/> to use for normal columns.</param>
|
||||||
|
/// <returns>The keybindings.</returns>
|
||||||
|
public IEnumerable<KeyBinding> GenerateKeyBindingsFor(int columns, out ManiaAction nextNormalAction)
|
||||||
|
{
|
||||||
|
ManiaAction currentNormalAction = NormalActionStart;
|
||||||
|
|
||||||
|
var bindings = new List<KeyBinding>();
|
||||||
|
|
||||||
|
for (int i = LeftKeys.Length - columns / 2; i < LeftKeys.Length; i++)
|
||||||
|
bindings.Add(new KeyBinding(LeftKeys[i], currentNormalAction++));
|
||||||
|
|
||||||
|
for (int i = 0; i < columns / 2; i++)
|
||||||
|
bindings.Add(new KeyBinding(RightKeys[i], currentNormalAction++));
|
||||||
|
|
||||||
|
if (columns % 2 == 1)
|
||||||
|
bindings.Add(new KeyBinding(SpecialKey, SpecialAction));
|
||||||
|
|
||||||
|
nextNormalAction = currentNormalAction;
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlayfieldType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Columns are grouped into a single stage.
|
||||||
|
/// Number of columns in this stage lies at (item - Single).
|
||||||
|
/// </summary>
|
||||||
|
Single = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Columns are grouped into two stages.
|
||||||
|
/// Overall number of columns lies at (item - Dual), further computation is required for
|
||||||
|
/// number of columns in each individual stage.
|
||||||
|
/// </summary>
|
||||||
|
Dual = 1000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
Normal file
15
osu.Game.Rulesets.Mania/Mods/IPlayfieldTypeMod.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
|
{
|
||||||
|
public interface IPlayfieldTypeMod : IApplicableMod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="PlayfieldType"/> which this <see cref="IPlayfieldTypeMod"/> requires.
|
||||||
|
/// </summary>
|
||||||
|
PlayfieldType PlayfieldType { get; }
|
||||||
|
}
|
||||||
|
}
|
53
osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
Normal file
53
osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Mods
|
||||||
|
{
|
||||||
|
public class ManiaModDualStages : Mod, IPlayfieldTypeMod, IApplicableToBeatmapConverter<ManiaHitObject>, IApplicableToRulesetContainer<ManiaHitObject>
|
||||||
|
{
|
||||||
|
public override string Name => "Dual Stages";
|
||||||
|
public override string ShortenedName => "DS";
|
||||||
|
public override string Description => @"Double the stages, double the fun!";
|
||||||
|
public override double ScoreMultiplier => 1;
|
||||||
|
public override bool Ranked => false;
|
||||||
|
|
||||||
|
public void ApplyToBeatmapConverter(BeatmapConverter<ManiaHitObject> beatmapConverter)
|
||||||
|
{
|
||||||
|
var mbc = (ManiaBeatmapConverter)beatmapConverter;
|
||||||
|
|
||||||
|
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||||
|
if (mbc.IsForCurrentRuleset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mbc.TargetColumns *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||||
|
{
|
||||||
|
var mrc = (ManiaRulesetContainer)rulesetContainer;
|
||||||
|
|
||||||
|
// Although this can work, for now let's not allow keymods for mania-specific beatmaps
|
||||||
|
if (mrc.IsForCurrentRuleset)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newDefinitions = new List<StageDefinition>();
|
||||||
|
foreach (var existing in mrc.Beatmap.Stages)
|
||||||
|
{
|
||||||
|
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
||||||
|
newDefinitions.Add(new StageDefinition { Columns = existing.Columns / 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
mrc.Beatmap.Stages = newDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayfieldType PlayfieldType => PlayfieldType.Dual;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Mods
|
|
||||||
{
|
|
||||||
public class ManiaModKeyCoop : Mod
|
|
||||||
{
|
|
||||||
public override string Name => "KeyCoop";
|
|
||||||
public override string ShortenedName => "2P";
|
|
||||||
public override string Description => @"Double the key amount, double the fun!";
|
|
||||||
public override double ScoreMultiplier => 1;
|
|
||||||
public override bool Ranked => true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
RelativeChildSize = new Vector2(1, 10000),
|
RelativeChildSize = new Vector2(1, 10000),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new DrawableHoldNote(new HoldNote { Duration = 1 }, ManiaAction.Key1)
|
new DrawableHoldNote(new HoldNote { Duration = 1000 } , ManiaAction.Key1)
|
||||||
{
|
{
|
||||||
Y = 5000,
|
Y = 5000,
|
||||||
Height = 1000,
|
Height = 1000,
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
// 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 NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
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;
|
||||||
@ -31,15 +33,43 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
var rng = new Random(1337);
|
var rng = new Random(1337);
|
||||||
|
|
||||||
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
|
AddStep("1 column", () => createPlayfield(1));
|
||||||
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
|
AddStep("4 columns", () => createPlayfield(4));
|
||||||
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
|
AddStep("5 columns", () => createPlayfield(5));
|
||||||
AddStep("Right special style", () => createPlayfield(4, SpecialColumnPosition.Right));
|
AddStep("8 columns", () => createPlayfield(8));
|
||||||
AddStep("5 columns", () => createPlayfield(5, SpecialColumnPosition.Normal));
|
AddStep("4 + 4 columns", () =>
|
||||||
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
|
{
|
||||||
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
|
var stages = new List<StageDefinition>
|
||||||
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
|
{
|
||||||
AddStep("Reversed", () => createPlayfield(4, SpecialColumnPosition.Normal, true));
|
new StageDefinition { Columns = 4 },
|
||||||
|
new StageDefinition { Columns = 4 },
|
||||||
|
};
|
||||||
|
createPlayfield(stages);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("2 + 4 + 2 columns", () =>
|
||||||
|
{
|
||||||
|
var stages = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = 2 },
|
||||||
|
new StageDefinition { Columns = 4 },
|
||||||
|
new StageDefinition { Columns = 2 },
|
||||||
|
};
|
||||||
|
createPlayfield(stages);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("1 + 8 + 1 columns", () =>
|
||||||
|
{
|
||||||
|
var stages = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = 1 },
|
||||||
|
new StageDefinition { Columns = 8 },
|
||||||
|
new StageDefinition { Columns = 1 },
|
||||||
|
};
|
||||||
|
createPlayfield(stages);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("Reversed", () => createPlayfield(4, true));
|
||||||
|
|
||||||
AddStep("Notes with input", () => createPlayfieldWithNotes());
|
AddStep("Notes with input", () => createPlayfieldWithNotes());
|
||||||
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(true));
|
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(true));
|
||||||
@ -48,7 +78,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
|
|
||||||
AddStep("Hit explosion", () =>
|
AddStep("Hit explosion", () =>
|
||||||
{
|
{
|
||||||
var playfield = createPlayfield(4, SpecialColumnPosition.Normal);
|
var playfield = createPlayfield(4);
|
||||||
|
|
||||||
int col = rng.Next(0, 4);
|
int col = rng.Next(0, 4);
|
||||||
|
|
||||||
@ -58,6 +88,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
};
|
};
|
||||||
|
|
||||||
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||||
|
playfield.Columns[col].OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,19 +98,29 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
maniaRuleset = rulesets.GetRuleset(3);
|
maniaRuleset = rulesets.GetRuleset(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ManiaPlayfield createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
|
private ManiaPlayfield createPlayfield(int cols, bool inverted = false)
|
||||||
|
{
|
||||||
|
var stages = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = cols },
|
||||||
|
};
|
||||||
|
|
||||||
|
return createPlayfield(stages, inverted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ManiaPlayfield createPlayfield(List<StageDefinition> stages, bool inverted = false)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
var inputManager = new ManiaInputManager(maniaRuleset, cols) { RelativeSizeAxes = Axes.Both };
|
var inputManager = new ManiaInputManager(maniaRuleset, stages.Sum(g => g.Columns)) { RelativeSizeAxes = Axes.Both };
|
||||||
Add(inputManager);
|
Add(inputManager);
|
||||||
|
|
||||||
ManiaPlayfield playfield;
|
ManiaPlayfield playfield;
|
||||||
inputManager.Add(playfield = new ManiaPlayfield(cols)
|
|
||||||
|
inputManager.Add(playfield = new ManiaPlayfield(stages)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
SpecialColumnPosition = specialPos
|
|
||||||
});
|
});
|
||||||
|
|
||||||
playfield.Inverted.Value = inverted;
|
playfield.Inverted.Value = inverted;
|
||||||
@ -97,7 +138,12 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
Add(inputManager);
|
Add(inputManager);
|
||||||
|
|
||||||
ManiaPlayfield playfield;
|
ManiaPlayfield playfield;
|
||||||
inputManager.Add(playfield = new ManiaPlayfield(4)
|
var stages = new List<StageDefinition>
|
||||||
|
{
|
||||||
|
new StageDefinition { Columns = 4 },
|
||||||
|
};
|
||||||
|
|
||||||
|
inputManager.Add(playfield = new ManiaPlayfield(stages)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -11,13 +11,14 @@ using osu.Framework.Graphics.Colour;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
public class Column : ScrollingPlayfield, IHasAccentColour
|
public class Column : ScrollingPlayfield, IKeyBindingHandler<ManiaAction>, IHasAccentColour
|
||||||
{
|
{
|
||||||
private const float key_icon_size = 10;
|
private const float key_icon_size = 10;
|
||||||
private const float key_icon_corner_radius = 3;
|
private const float key_icon_corner_radius = 3;
|
||||||
@ -47,6 +48,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public Column()
|
public Column()
|
||||||
: base(ScrollingDirection.Up)
|
: base(ScrollingDirection.Up)
|
||||||
{
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
Width = column_width;
|
Width = column_width;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
@ -61,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
Name = "Hit target + hit objects",
|
Name = "Hit target + hit objects",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Top = ManiaPlayfield.HIT_TARGET_POSITION },
|
Padding = new MarginPadding { Top = ManiaStage.HIT_TARGET_POSITION },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
@ -115,7 +117,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
Name = "Key",
|
Name = "Key",
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = ManiaPlayfield.HIT_TARGET_POSITION,
|
Height = ManiaStage.HIT_TARGET_POSITION,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -205,12 +207,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
hitObject.Depth = (float)hitObject.HitObject.StartTime;
|
hitObject.Depth = (float)hitObject.HitObject.StartTime;
|
||||||
hitObject.AccentColour = AccentColour;
|
hitObject.AccentColour = AccentColour;
|
||||||
hitObject.OnJudgement += onJudgement;
|
hitObject.OnJudgement += OnJudgement;
|
||||||
|
|
||||||
HitObjects.Add(hitObject);
|
HitObjects.Add(hitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||||
{
|
{
|
||||||
if (!judgement.IsHit)
|
if (!judgement.IsHit)
|
||||||
return;
|
return;
|
||||||
@ -258,5 +260,26 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false;
|
public bool OnPressed(ManiaAction action) => Pressed?.Invoke(action) ?? false;
|
||||||
public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false;
|
public bool OnReleased(ManiaAction action) => Released?.Invoke(action) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(ManiaAction action)
|
||||||
|
{
|
||||||
|
// Play the sounds of the next hitobject
|
||||||
|
if (HitObjects.AliveObjects.Any())
|
||||||
|
{
|
||||||
|
// If there are alive hitobjects, we can abuse the fact that AliveObjects are sorted by time (see: Add())
|
||||||
|
HitObjects.AliveObjects.First().PlaySamples();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If not, we do a slow search - we might want to do a BinarySearch here if this becomes problematic
|
||||||
|
// We fallback to LastOrDefault() if we're beyond the last note in the map
|
||||||
|
var hitObject = HitObjects.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? HitObjects.Objects.LastOrDefault();
|
||||||
|
hitObject?.PlaySamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(ManiaAction action) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
internal class DrawableManiaJudgement : DrawableJudgement
|
internal class DrawableManiaJudgement : DrawableJudgement
|
||||||
{
|
{
|
||||||
public DrawableManiaJudgement(Judgement judgement)
|
public DrawableManiaJudgement(Judgement judgement)
|
||||||
: base(judgement)
|
: base(judgement)
|
||||||
{
|
{
|
||||||
JudgementText.TextSize = 25;
|
JudgementText.TextSize = 25;
|
||||||
}
|
}
|
||||||
|
@ -3,237 +3,92 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Objects;
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
using OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
public class ManiaPlayfield : ScrollingPlayfield
|
public class ManiaPlayfield : ScrollingPlayfield
|
||||||
{
|
{
|
||||||
public const float HIT_TARGET_POSITION = 50;
|
|
||||||
|
|
||||||
private SpecialColumnPosition specialColumnPosition;
|
|
||||||
/// <summary>
|
|
||||||
/// The style to use for the special column.
|
|
||||||
/// </summary>
|
|
||||||
public SpecialColumnPosition SpecialColumnPosition
|
|
||||||
{
|
|
||||||
get { return specialColumnPosition; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (IsLoaded)
|
|
||||||
throw new InvalidOperationException($"Setting {nameof(SpecialColumnPosition)} after the playfield is loaded requires re-creating the playfield.");
|
|
||||||
specialColumnPosition = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this playfield should be inverted. This flips everything inside the playfield.
|
/// Whether this playfield should be inverted. This flips everything inside the playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
|
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
|
||||||
|
|
||||||
private readonly FlowContainer<Column> columns;
|
public List<Column> Columns => stages.SelectMany(x => x.Columns).ToList();
|
||||||
public IEnumerable<Column> Columns => columns.Children;
|
private readonly List<ManiaStage> stages = new List<ManiaStage>();
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||||
private readonly Container<Drawable> content;
|
|
||||||
|
|
||||||
private List<Color4> normalColumnColours = new List<Color4>();
|
|
||||||
private Color4 specialColumnColour;
|
|
||||||
|
|
||||||
private readonly Container<DrawableManiaJudgement> judgements;
|
|
||||||
|
|
||||||
private readonly int columnCount;
|
|
||||||
|
|
||||||
public ManiaPlayfield(int columnCount)
|
|
||||||
: base(ScrollingDirection.Up)
|
: base(ScrollingDirection.Up)
|
||||||
{
|
{
|
||||||
this.columnCount = columnCount;
|
if (stageDefinitions == null)
|
||||||
|
throw new ArgumentNullException(nameof(stageDefinitions));
|
||||||
|
|
||||||
if (columnCount <= 0)
|
if (stageDefinitions.Count <= 0)
|
||||||
throw new ArgumentException("Can't have zero or fewer columns.");
|
throw new ArgumentException("Can't have zero or fewer stages.");
|
||||||
|
|
||||||
Inverted.Value = true;
|
Inverted.Value = true;
|
||||||
|
|
||||||
Container topLevelContainer;
|
GridContainer playfieldGrid;
|
||||||
InternalChildren = new Drawable[]
|
InternalChild = playfieldGrid = new GridContainer
|
||||||
{
|
{
|
||||||
new Container
|
RelativeSizeAxes = Axes.Both,
|
||||||
{
|
Content = new[] { new Drawable[stageDefinitions.Count] }
|
||||||
Name = "Playfield elements",
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Name = "Columns mask",
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Masking = true,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
Name = "Background",
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4.Black
|
|
||||||
},
|
|
||||||
columns = new FillFlowContainer<Column>
|
|
||||||
{
|
|
||||||
Name = "Columns",
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Padding = new MarginPadding { Left = 1, Right = 1 },
|
|
||||||
Spacing = new Vector2(1, 0)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Name = "Barlines mask",
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Width = 1366, // Bar lines should only be masked on the vertical axis
|
|
||||||
BypassAutoSizeAxes = Axes.Both,
|
|
||||||
Masking = true,
|
|
||||||
Child = content = new Container
|
|
||||||
{
|
|
||||||
Name = "Bar lines",
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.TopCentre,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
judgements = new Container<DrawableManiaJudgement>
|
|
||||||
{
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Y = HIT_TARGET_POSITION + 150,
|
|
||||||
BypassAutoSizeAxes = Axes.Both
|
|
||||||
},
|
|
||||||
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var currentAction = ManiaAction.Key1;
|
var normalColumnAction = ManiaAction.Key1;
|
||||||
for (int i = 0; i < columnCount; i++)
|
var specialColumnAction = ManiaAction.Special1;
|
||||||
|
int firstColumnIndex = 0;
|
||||||
|
for (int i = 0; i < stageDefinitions.Count; i++)
|
||||||
{
|
{
|
||||||
var c = new Column();
|
var newStage = new ManiaStage(firstColumnIndex, stageDefinitions[i], ref normalColumnAction, ref specialColumnAction);
|
||||||
c.VisibleTimeRange.BindTo(VisibleTimeRange);
|
newStage.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||||
|
newStage.Inverted.BindTo(Inverted);
|
||||||
|
|
||||||
c.IsSpecial = isSpecialColumn(i);
|
playfieldGrid.Content[0][i] = newStage;
|
||||||
c.Action = c.IsSpecial ? ManiaAction.Special : currentAction++;
|
|
||||||
|
|
||||||
topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
|
stages.Add(newStage);
|
||||||
|
AddNested(newStage);
|
||||||
|
|
||||||
columns.Add(c);
|
firstColumnIndex += newStage.Columns.Count;
|
||||||
AddNested(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Inverted.ValueChanged += invertedChanged;
|
|
||||||
Inverted.TriggerChange();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invertedChanged(bool newValue)
|
public override void Add(DrawableHitObject h) => getStageByColumn(((ManiaHitObject)h.HitObject).Column).Add(h);
|
||||||
|
|
||||||
|
public void Add(BarLine barline) => stages.ForEach(s => s.Add(barline));
|
||||||
|
|
||||||
|
private ManiaStage getStageByColumn(int column)
|
||||||
{
|
{
|
||||||
Scale = new Vector2(1, newValue ? -1 : 1);
|
int sum = 0;
|
||||||
judgements.Scale = Scale;
|
foreach (var stage in stages)
|
||||||
|
{
|
||||||
|
sum = sum + stage.Columns.Count;
|
||||||
|
if (sum > column)
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(ManiaConfigManager maniaConfig)
|
||||||
{
|
{
|
||||||
normalColumnColours = new List<Color4>
|
maniaConfig.BindWith(ManiaSetting.ScrollTime, VisibleTimeRange);
|
||||||
{
|
|
||||||
colours.RedDark,
|
|
||||||
colours.GreenDark
|
|
||||||
};
|
|
||||||
|
|
||||||
specialColumnColour = colours.BlueDark;
|
|
||||||
|
|
||||||
// Set the special column + colour + key
|
|
||||||
foreach (var column in Columns)
|
|
||||||
{
|
|
||||||
if (!column.IsSpecial)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
column.AccentColour = specialColumnColour;
|
|
||||||
}
|
|
||||||
|
|
||||||
var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList();
|
|
||||||
|
|
||||||
// We'll set the colours of the non-special columns in a separate loop, because the non-special
|
|
||||||
// column colours are mirrored across their centre and special styles mess with this
|
|
||||||
for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++)
|
|
||||||
{
|
|
||||||
Color4 colour = normalColumnColours[i % normalColumnColours.Count];
|
|
||||||
nonSpecialColumns[i].AccentColour = colour;
|
|
||||||
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||||
{
|
{
|
||||||
judgements.Clear();
|
getStageByColumn(((ManiaHitObject)judgedObject.HitObject).Column).OnJudgement(judgedObject, judgement);
|
||||||
judgements.Add(new DrawableManiaJudgement(judgement)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the column index is a special column for this playfield.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="column">The 0-based column index.</param>
|
|
||||||
/// <returns>Whether the column is a special column.</returns>
|
|
||||||
private bool isSpecialColumn(int column)
|
|
||||||
{
|
|
||||||
switch (SpecialColumnPosition)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case SpecialColumnPosition.Normal:
|
|
||||||
return columnCount % 2 == 1 && column == columnCount / 2;
|
|
||||||
case SpecialColumnPosition.Left:
|
|
||||||
return column == 0;
|
|
||||||
case SpecialColumnPosition.Right:
|
|
||||||
return column == columnCount - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Add(DrawableHitObject h)
|
|
||||||
{
|
|
||||||
h.OnJudgement += OnJudgement;
|
|
||||||
Columns.ElementAt(((ManiaHitObject)h.HitObject).Column).Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(DrawableBarLine barline) => HitObjects.Add(barline);
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
// Due to masking differences, it is not possible to get the width of the columns container automatically
|
|
||||||
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
|
|
||||||
content.Width = columns.Width;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -11,7 +10,11 @@ using osu.Framework.Input;
|
|||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Rulesets.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
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.Replays;
|
using osu.Game.Rulesets.Mania.Replays;
|
||||||
@ -22,6 +25,7 @@ using osu.Game.Rulesets.Replays;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
{
|
{
|
||||||
@ -29,7 +33,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
|
public new ManiaBeatmap Beatmap => (ManiaBeatmap)base.Beatmap;
|
||||||
|
|
||||||
public IEnumerable<DrawableBarLine> BarLines;
|
public IEnumerable<BarLine> BarLines;
|
||||||
|
|
||||||
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||||
: base(ruleset, beatmap, isForCurrentRuleset)
|
: base(ruleset, beatmap, isForCurrentRuleset)
|
||||||
@ -38,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue;
|
||||||
|
|
||||||
var timingPoints = Beatmap.ControlPointInfo.TimingPoints;
|
var timingPoints = Beatmap.ControlPointInfo.TimingPoints;
|
||||||
var barLines = new List<DrawableBarLine>();
|
var barLines = new List<BarLine>();
|
||||||
|
|
||||||
for (int i = 0; i < timingPoints.Count; i++)
|
for (int i = 0; i < timingPoints.Count; i++)
|
||||||
{
|
{
|
||||||
@ -50,12 +54,12 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
|
for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++)
|
||||||
{
|
{
|
||||||
barLines.Add(new DrawableBarLine(new BarLine
|
barLines.Add(new BarLine
|
||||||
{
|
{
|
||||||
StartTime = t,
|
StartTime = t,
|
||||||
ControlPoint = point,
|
ControlPoint = point,
|
||||||
BeatIndex = index
|
BeatIndex = index
|
||||||
}));
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +72,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
BarLines.ForEach(Playfield.Add);
|
BarLines.ForEach(Playfield.Add);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.TotalColumns)
|
protected sealed override Playfield CreatePlayfield() => new ManiaPlayfield(Beatmap.Stages)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -76,7 +80,9 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
|
||||||
|
|
||||||
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Beatmap.TotalColumns);
|
public override int Variant => (int)(Mods.OfType<IPlayfieldTypeMod>().FirstOrDefault()?.PlayfieldType ?? PlayfieldType.Single) + Beatmap.TotalColumns;
|
||||||
|
|
||||||
|
public override PassThroughInputManager CreateInputManager() => new ManiaInputManager(Ruleset.RulesetInfo, Variant);
|
||||||
|
|
||||||
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);
|
protected override BeatmapConverter<ManiaHitObject> CreateBeatmapConverter() => new ManiaBeatmapConverter(IsForCurrentRuleset, WorkingBeatmap.Beatmap);
|
||||||
|
|
||||||
@ -98,5 +104,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
|
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(1, 0.8f);
|
||||||
|
|
||||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay, this);
|
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay, this);
|
||||||
|
|
||||||
|
protected override IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => new ManiaConfigManager(settings, Ruleset.RulesetInfo, Variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
229
osu.Game.Rulesets.Mania/UI/ManiaStage.cs
Normal file
229
osu.Game.Rulesets.Mania/UI/ManiaStage.cs
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.UI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of <see cref="Column"/>s.
|
||||||
|
/// </summary>
|
||||||
|
internal class ManiaStage : ScrollingPlayfield
|
||||||
|
{
|
||||||
|
public const float HIT_TARGET_POSITION = 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this playfield should be inverted. This flips everything inside the playfield.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Bindable<bool> Inverted = new Bindable<bool>(true);
|
||||||
|
|
||||||
|
public IReadOnlyList<Column> Columns => columnFlow.Children;
|
||||||
|
private readonly FillFlowContainer<Column> columnFlow;
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
private readonly Container<Drawable> content;
|
||||||
|
|
||||||
|
public Container<DrawableManiaJudgement> Judgements => judgements;
|
||||||
|
private readonly Container<DrawableManiaJudgement> judgements;
|
||||||
|
|
||||||
|
private readonly Container topLevelContainer;
|
||||||
|
|
||||||
|
private List<Color4> normalColumnColours = new List<Color4>();
|
||||||
|
private Color4 specialColumnColour;
|
||||||
|
|
||||||
|
private readonly int firstColumnIndex;
|
||||||
|
private readonly StageDefinition definition;
|
||||||
|
|
||||||
|
public ManiaStage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction)
|
||||||
|
: base(ScrollingDirection.Up)
|
||||||
|
{
|
||||||
|
this.firstColumnIndex = firstColumnIndex;
|
||||||
|
this.definition = definition;
|
||||||
|
|
||||||
|
Name = "Stage";
|
||||||
|
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = "Columns mask",
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Name = "Background",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black
|
||||||
|
},
|
||||||
|
columnFlow = new FillFlowContainer<Column>
|
||||||
|
{
|
||||||
|
Name = "Columns",
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Padding = new MarginPadding { Left = 1, Right = 1 },
|
||||||
|
Spacing = new Vector2(1, 0)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = "Barlines mask",
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = 1366, // Bar lines should only be masked on the vertical axis
|
||||||
|
BypassAutoSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Child = content = new Container
|
||||||
|
{
|
||||||
|
Name = "Bar lines",
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Padding = new MarginPadding { Top = HIT_TARGET_POSITION }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
judgements = new Container<DrawableManiaJudgement>
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Y = HIT_TARGET_POSITION + 150,
|
||||||
|
BypassAutoSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < definition.Columns; i++)
|
||||||
|
{
|
||||||
|
var isSpecial = isSpecialColumn(i);
|
||||||
|
var column = new Column
|
||||||
|
{
|
||||||
|
IsSpecial = isSpecial,
|
||||||
|
Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++
|
||||||
|
};
|
||||||
|
|
||||||
|
AddColumn(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
Inverted.ValueChanged += invertedChanged;
|
||||||
|
Inverted.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invertedChanged(bool newValue)
|
||||||
|
{
|
||||||
|
Scale = new Vector2(1, newValue ? -1 : 1);
|
||||||
|
Judgements.Scale = Scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddColumn(Column c)
|
||||||
|
{
|
||||||
|
c.VisibleTimeRange.BindTo(VisibleTimeRange);
|
||||||
|
|
||||||
|
topLevelContainer.Add(c.TopLevelContainer.CreateProxy());
|
||||||
|
columnFlow.Add(c);
|
||||||
|
AddNested(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the column index is a special column for this playfield.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column">The 0-based column index.</param>
|
||||||
|
/// <returns>Whether the column is a special column.</returns>
|
||||||
|
private bool isSpecialColumn(int column) => definition.Columns % 2 == 1 && column == definition.Columns / 2;
|
||||||
|
|
||||||
|
public override void Add(DrawableHitObject h)
|
||||||
|
{
|
||||||
|
var maniaObject = (ManiaHitObject)h.HitObject;
|
||||||
|
int columnIndex = maniaObject.Column - firstColumnIndex;
|
||||||
|
Columns.ElementAt(columnIndex).Add(h);
|
||||||
|
h.OnJudgement += OnJudgement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(BarLine barline) => base.Add(new DrawableBarLine(barline));
|
||||||
|
|
||||||
|
internal void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||||
|
{
|
||||||
|
judgements.Clear();
|
||||||
|
judgements.Add(new DrawableManiaJudgement(judgement)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
normalColumnColours = new List<Color4>
|
||||||
|
{
|
||||||
|
colours.RedDark,
|
||||||
|
colours.GreenDark
|
||||||
|
};
|
||||||
|
|
||||||
|
specialColumnColour = colours.BlueDark;
|
||||||
|
|
||||||
|
// Set the special column + colour + key
|
||||||
|
foreach (var column in Columns)
|
||||||
|
{
|
||||||
|
if (!column.IsSpecial)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
column.AccentColour = specialColumnColour;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonSpecialColumns = Columns.Where(c => !c.IsSpecial).ToList();
|
||||||
|
|
||||||
|
// We'll set the colours of the non-special columns in a separate loop, because the non-special
|
||||||
|
// column colours are mirrored across their centre and special styles mess with this
|
||||||
|
for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++)
|
||||||
|
{
|
||||||
|
Color4 colour = normalColumnColours[i % normalColumnColours.Count];
|
||||||
|
nonSpecialColumns[i].AccentColour = colour;
|
||||||
|
nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
// Due to masking differences, it is not possible to get the width of the columns container automatically
|
||||||
|
// While masking on effectively only the Y-axis, so we need to set the width of the bar line container manually
|
||||||
|
content.Width = columnFlow.Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.UI
|
|
||||||
{
|
|
||||||
public enum SpecialColumnPosition
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The special column will lie in the center of the columns.
|
|
||||||
/// </summary>
|
|
||||||
Normal,
|
|
||||||
/// <summary>
|
|
||||||
/// The special column will lie to the left of the columns.
|
|
||||||
/// </summary>
|
|
||||||
Left,
|
|
||||||
/// <summary>
|
|
||||||
/// The special column will lie to the right of the columns.
|
|
||||||
/// </summary>
|
|
||||||
Right
|
|
||||||
}
|
|
||||||
}
|
|
@ -58,12 +58,14 @@
|
|||||||
<Compile Include="Beatmaps\Patterns\Legacy\PatternType.cs" />
|
<Compile Include="Beatmaps\Patterns\Legacy\PatternType.cs" />
|
||||||
<Compile Include="Beatmaps\ManiaBeatmapConverter.cs" />
|
<Compile Include="Beatmaps\ManiaBeatmapConverter.cs" />
|
||||||
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
<Compile Include="Beatmaps\Patterns\Pattern.cs" />
|
||||||
|
<Compile Include="Configuration\ManiaConfigManager.cs" />
|
||||||
<Compile Include="MathUtils\FastRandom.cs" />
|
<Compile Include="MathUtils\FastRandom.cs" />
|
||||||
<Compile Include="Judgements\HitWindows.cs" />
|
<Compile Include="Judgements\HitWindows.cs" />
|
||||||
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
<Compile Include="Judgements\HoldNoteTailJudgement.cs" />
|
||||||
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
<Compile Include="Judgements\HoldNoteTickJudgement.cs" />
|
||||||
<Compile Include="Judgements\ManiaJudgement.cs" />
|
<Compile Include="Judgements\ManiaJudgement.cs" />
|
||||||
<Compile Include="ManiaDifficultyCalculator.cs" />
|
<Compile Include="ManiaDifficultyCalculator.cs" />
|
||||||
|
<Compile Include="Mods\IPlayfieldTypeMod.cs" />
|
||||||
<Compile Include="Mods\ManiaKeyMod.cs" />
|
<Compile Include="Mods\ManiaKeyMod.cs" />
|
||||||
<Compile Include="Mods\ManiaModAutoplay.cs" />
|
<Compile Include="Mods\ManiaModAutoplay.cs" />
|
||||||
<Compile Include="Mods\ManiaModDaycore.cs" />
|
<Compile Include="Mods\ManiaModDaycore.cs" />
|
||||||
@ -83,7 +85,7 @@
|
|||||||
<Compile Include="Mods\ManiaModKey7.cs" />
|
<Compile Include="Mods\ManiaModKey7.cs" />
|
||||||
<Compile Include="Mods\ManiaModKey8.cs" />
|
<Compile Include="Mods\ManiaModKey8.cs" />
|
||||||
<Compile Include="Mods\ManiaModKey9.cs" />
|
<Compile Include="Mods\ManiaModKey9.cs" />
|
||||||
<Compile Include="Mods\ManiaModKeyCoop.cs" />
|
<Compile Include="Mods\ManiaModDualStages.cs" />
|
||||||
<Compile Include="Mods\ManiaModNightcore.cs" />
|
<Compile Include="Mods\ManiaModNightcore.cs" />
|
||||||
<Compile Include="Mods\ManiaModPerfect.cs" />
|
<Compile Include="Mods\ManiaModPerfect.cs" />
|
||||||
<Compile Include="Mods\ManiaModRandom.cs" />
|
<Compile Include="Mods\ManiaModRandom.cs" />
|
||||||
@ -115,12 +117,12 @@
|
|||||||
<Compile Include="Tests\TestCasePerformancePoints.cs" />
|
<Compile Include="Tests\TestCasePerformancePoints.cs" />
|
||||||
<Compile Include="UI\Column.cs" />
|
<Compile Include="UI\Column.cs" />
|
||||||
<Compile Include="UI\DrawableManiaJudgement.cs" />
|
<Compile Include="UI\DrawableManiaJudgement.cs" />
|
||||||
|
<Compile Include="UI\ManiaStage.cs" />
|
||||||
<Compile Include="UI\HitExplosion.cs" />
|
<Compile Include="UI\HitExplosion.cs" />
|
||||||
<Compile Include="UI\ManiaRulesetContainer.cs" />
|
<Compile Include="UI\ManiaRulesetContainer.cs" />
|
||||||
<Compile Include="UI\ManiaPlayfield.cs" />
|
<Compile Include="UI\ManiaPlayfield.cs" />
|
||||||
<Compile Include="ManiaRuleset.cs" />
|
<Compile Include="ManiaRuleset.cs" />
|
||||||
<Compile Include="Mods\ManiaModNoFail.cs" />
|
<Compile Include="Mods\ManiaModNoFail.cs" />
|
||||||
<Compile Include="UI\SpecialColumnPosition.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="app.config" />
|
<None Include="app.config" />
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
|
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
|
||||||
float stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||||
|
|
||||||
if (objectN.StartTime - endTime > stackThreshold)
|
if (objectN.StartTime - endTime > stackThreshold)
|
||||||
//We are no longer within stacking range of the next object.
|
//We are no longer within stacking range of the next object.
|
||||||
@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
OsuHitObject objectI = beatmap.HitObjects[i];
|
OsuHitObject objectI = beatmap.HitObjects[i];
|
||||||
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
if (objectI.StackHeight != 0 || objectI is Spinner) continue;
|
||||||
|
|
||||||
float stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f;
|
||||||
|
|
||||||
/* If this object is a hitcircle, then we enter this "special" case.
|
/* If this object is a hitcircle, then we enter this "special" case.
|
||||||
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
public override string Description => @"Play with no approach circles and fading notes for a slight score advantage.";
|
public override string Description => @"Play with no approach circles and fading notes for a slight score advantage.";
|
||||||
public override double ScoreMultiplier => 1.06;
|
public override double ScoreMultiplier => 1.06;
|
||||||
|
|
||||||
private const float fade_in_duration_multiplier = 0.4f;
|
private const double fade_in_duration_multiplier = 0.4;
|
||||||
private const double fade_out_duration_multiplier = 0.3;
|
private const double fade_out_duration_multiplier = 0.3;
|
||||||
|
|
||||||
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
public void ApplyToDrawableHitObjects(IEnumerable<DrawableHitObject> drawables)
|
||||||
|
@ -11,13 +11,12 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableRepeatPoint : DrawableOsuHitObject
|
public class DrawableRepeatPoint : DrawableOsuHitObject, ITrackSnaking
|
||||||
{
|
{
|
||||||
private readonly RepeatPoint repeatPoint;
|
private readonly RepeatPoint repeatPoint;
|
||||||
private readonly DrawableSlider drawableSlider;
|
private readonly DrawableSlider drawableSlider;
|
||||||
|
|
||||||
public double FadeInTime;
|
private double animDuration;
|
||||||
public double FadeOutTime;
|
|
||||||
|
|
||||||
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
|
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
|
||||||
: base(repeatPoint)
|
: base(repeatPoint)
|
||||||
@ -48,11 +47,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
{
|
{
|
||||||
var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime);
|
animDuration = Math.Min(150, repeatPoint.SpanDuration / 2);
|
||||||
|
|
||||||
this.FadeIn(animIn).ScaleTo(1.2f, animIn)
|
this.FadeIn(animDuration).ScaleTo(1.2f, animDuration / 2)
|
||||||
.Then()
|
.Then()
|
||||||
.ScaleTo(1, 150, Easing.Out);
|
.ScaleTo(1, animDuration / 2, Easing.Out);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateCurrentState(ArmedState state)
|
protected override void UpdateCurrentState(ArmedState state)
|
||||||
@ -60,16 +59,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
this.Delay(FadeOutTime - repeatPoint.StartTime).FadeOut();
|
this.Delay(HitObject.TimePreempt).FadeOut();
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
this.FadeOut(160);
|
this.FadeOut(animDuration);
|
||||||
break;
|
break;
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
this.FadeOut(120, Easing.OutQuint)
|
this.FadeOut(animDuration, Easing.OutQuint)
|
||||||
.ScaleTo(Scale * 1.5f, 120, Easing.OutQuint);
|
.ScaleTo(Scale * 1.5f, animDuration, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateSnakingPosition(Vector2 start, Vector2 end) => Position = repeatPoint.RepeatIndex % 2 == 0 ? end : start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public readonly DrawableHitCircle InitialCircle;
|
public readonly DrawableHitCircle InitialCircle;
|
||||||
|
|
||||||
private readonly List<ISliderProgress> components = new List<ISliderProgress>();
|
private readonly List<Drawable> components = new List<Drawable>();
|
||||||
|
|
||||||
private readonly Container<DrawableSliderTick> ticks;
|
private readonly Container<DrawableSliderTick> ticks;
|
||||||
private readonly Container<DrawableRepeatPoint> repeatPoints;
|
private readonly Container<DrawableRepeatPoint> repeatPoints;
|
||||||
@ -60,7 +61,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Samples = s.Samples,
|
Samples = s.Samples,
|
||||||
SampleControlPoint = s.SampleControlPoint,
|
SampleControlPoint = s.SampleControlPoint,
|
||||||
TimePreempt = s.TimePreempt,
|
TimePreempt = s.TimePreempt,
|
||||||
TimeFadein = s.TimeFadein
|
TimeFadein = s.TimeFadein,
|
||||||
|
HitWindow300 = s.HitWindow300,
|
||||||
|
HitWindow100 = s.HitWindow100,
|
||||||
|
HitWindow50 = s.HitWindow50
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,12 +73,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
AddNested(InitialCircle);
|
AddNested(InitialCircle);
|
||||||
|
|
||||||
var repeatDuration = s.Curve.Distance / s.Velocity;
|
|
||||||
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
|
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
|
||||||
{
|
{
|
||||||
var repeatStartTime = s.StartTime + tick.RepeatIndex * repeatDuration;
|
var spanStartTime = s.StartTime + tick.SpanIndex * s.SpanDuration;
|
||||||
var fadeInTime = repeatStartTime + (tick.StartTime - repeatStartTime) / 2 - (tick.RepeatIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2);
|
var fadeInTime = spanStartTime + (tick.StartTime - spanStartTime) / 2 - (tick.SpanIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2);
|
||||||
var fadeOutTime = repeatStartTime + repeatDuration;
|
var fadeOutTime = spanStartTime + s.SpanDuration;
|
||||||
|
|
||||||
var drawableTick = new DrawableSliderTick(tick)
|
var drawableTick = new DrawableSliderTick(tick)
|
||||||
{
|
{
|
||||||
@ -89,23 +92,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
|
foreach (var repeatPoint in s.NestedHitObjects.OfType<RepeatPoint>())
|
||||||
{
|
{
|
||||||
var repeatStartTime = s.StartTime + repeatPoint.RepeatIndex * repeatDuration;
|
|
||||||
var fadeInTime = repeatStartTime + (repeatPoint.StartTime - repeatStartTime) / 2 - (repeatPoint.RepeatIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2);
|
|
||||||
var fadeOutTime = repeatStartTime + repeatDuration;
|
|
||||||
|
|
||||||
var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
|
var drawableRepeatPoint = new DrawableRepeatPoint(repeatPoint, this)
|
||||||
{
|
{
|
||||||
FadeInTime = fadeInTime,
|
Position = repeatPoint.Position
|
||||||
FadeOutTime = fadeOutTime,
|
|
||||||
Position = repeatPoint.Position,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
repeatPoints.Add(drawableRepeatPoint);
|
repeatPoints.Add(drawableRepeatPoint);
|
||||||
|
components.Add(drawableRepeatPoint);
|
||||||
AddNested(drawableRepeatPoint);
|
AddNested(drawableRepeatPoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int currentRepeat;
|
private int currentSpan;
|
||||||
public bool Tracking;
|
public bool Tracking;
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -116,17 +114,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
double progress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
double progress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
|
||||||
|
|
||||||
int repeat = slider.RepeatAt(progress);
|
int span = slider.SpanAt(progress);
|
||||||
progress = slider.ProgressAt(progress);
|
progress = slider.ProgressAt(progress);
|
||||||
|
|
||||||
if (repeat > currentRepeat)
|
if (span > currentSpan)
|
||||||
currentRepeat = repeat;
|
currentSpan = span;
|
||||||
|
|
||||||
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
|
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
|
||||||
if (!InitialCircle.Judgements.Any(j => j.IsHit))
|
if (!InitialCircle.Judgements.Any(j => j.IsHit))
|
||||||
InitialCircle.Position = slider.Curve.PositionAt(progress);
|
InitialCircle.Position = slider.Curve.PositionAt(progress);
|
||||||
|
|
||||||
foreach (var c in components) c.UpdateProgress(progress, repeat);
|
foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(progress, span);
|
||||||
|
foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
|
||||||
foreach (var t in ticks.Children) t.Tracking = Ball.Tracking;
|
foreach (var t in ticks.Children) t.Tracking = Ball.Tracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
osu.Game.Rulesets.Osu/Objects/Drawables/ITrackSnaking.cs
Normal file
15
osu.Game.Rulesets.Osu/Objects/Drawables/ITrackSnaking.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A component which tracks the current end snaking position of a slider.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITrackSnaking
|
||||||
|
{
|
||||||
|
void UpdateSnakingPosition(Vector2 start, Vector2 end);
|
||||||
|
}
|
||||||
|
}
|
@ -139,7 +139,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateProgress(double progress, int repeat)
|
public void UpdateProgress(double progress, int span)
|
||||||
{
|
{
|
||||||
Position = slider.Curve.PositionAt(progress);
|
Position = slider.Curve.PositionAt(progress);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ using OpenTK;
|
|||||||
using OpenTK.Graphics.ES30;
|
using OpenTK.Graphics.ES30;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
{
|
{
|
||||||
@ -164,14 +165,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateProgress(double progress, int repeat)
|
public void UpdateProgress(double progress, int span)
|
||||||
{
|
{
|
||||||
double start = 0;
|
double start = 0;
|
||||||
double end = snakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadein, 0, 1) : 1;
|
double end = snakingIn ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / slider.TimeFadein, 0, 1) : 1;
|
||||||
|
|
||||||
if (repeat >= slider.RepeatCount - 1)
|
if (span >= slider.SpanCount() - 1)
|
||||||
{
|
{
|
||||||
if (Math.Min(repeat, slider.RepeatCount - 1) % 2 == 1)
|
if (Math.Min(span, slider.SpanCount() - 1) % 2 == 1)
|
||||||
{
|
{
|
||||||
start = 0;
|
start = 0;
|
||||||
end = snakingOut ? progress : 1;
|
end = snakingOut ? progress : 1;
|
||||||
|
@ -5,6 +5,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
public interface ISliderProgress
|
public interface ISliderProgress
|
||||||
{
|
{
|
||||||
void UpdateProgress(double progress, int repeat);
|
void UpdateProgress(double progress, int span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public const double OBJECT_RADIUS = 64;
|
public const double OBJECT_RADIUS = 64;
|
||||||
|
|
||||||
private const double hittable_range = 300;
|
private const double hittable_range = 300;
|
||||||
private const double hit_window_50 = 150;
|
public double HitWindow50 = 150;
|
||||||
private const double hit_window_100 = 80;
|
public double HitWindow100 = 80;
|
||||||
private const double hit_window_300 = 30;
|
public double HitWindow300 = 30;
|
||||||
|
|
||||||
public float TimePreempt = 600;
|
public double TimePreempt = 600;
|
||||||
public float TimeFadein = 400;
|
public double TimeFadein = 400;
|
||||||
|
|
||||||
public Vector2 Position { get; set; }
|
public Vector2 Position { get; set; }
|
||||||
public float X => Position.X;
|
public float X => Position.X;
|
||||||
@ -50,13 +50,13 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
return 300;
|
return hittable_range;
|
||||||
case HitResult.Meh:
|
case HitResult.Meh:
|
||||||
return 150;
|
return HitWindow50;
|
||||||
case HitResult.Good:
|
case HitResult.Good:
|
||||||
return 80;
|
return HitWindow100;
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
return 30;
|
return HitWindow300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +78,10 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
|
||||||
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
TimeFadein = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1200, 800, 300);
|
||||||
|
|
||||||
|
HitWindow50 = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 200, 150, 100);
|
||||||
|
HitWindow100 = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 140, 100, 60);
|
||||||
|
HitWindow300 = BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 80, 50, 20);
|
||||||
|
|
||||||
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,25 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public class RepeatPoint : OsuHitObject
|
public class RepeatPoint : OsuHitObject
|
||||||
{
|
{
|
||||||
public int RepeatIndex { get; set; }
|
public int RepeatIndex { get; set; }
|
||||||
|
public double SpanDuration { get; set; }
|
||||||
|
|
||||||
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
// We want to show the first RepeatPoint as the TimePreempt dictates but on short (and possibly fast) sliders
|
||||||
|
// we may need to cut down this time on following RepeatPoints to only show up to two RepeatPoints at any given time.
|
||||||
|
if (RepeatIndex > 0)
|
||||||
|
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const float base_scoring_distance = 100;
|
private const float base_scoring_distance = 100;
|
||||||
|
|
||||||
public readonly SliderCurve Curve = new SliderCurve();
|
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
|
||||||
|
|
||||||
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity;
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
public override Vector2 EndPosition => PositionAt(1);
|
public override Vector2 EndPosition => this.PositionAt(1);
|
||||||
|
|
||||||
|
public SliderCurve Curve { get; } = new SliderCurve();
|
||||||
|
|
||||||
public List<Vector2> ControlPoints
|
public List<Vector2> ControlPoints
|
||||||
{
|
{
|
||||||
@ -58,9 +58,15 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
internal float LazyTravelDistance;
|
internal float LazyTravelDistance;
|
||||||
|
|
||||||
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
|
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
|
||||||
public int RepeatCount { get; set; } = 1;
|
public int RepeatCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The length of one span of this <see cref="Slider"/>.
|
||||||
|
/// </summary>
|
||||||
|
public double SpanDuration => Duration / this.SpanCount();
|
||||||
|
|
||||||
private int stackHeight;
|
private int stackHeight;
|
||||||
|
|
||||||
public override int StackHeight
|
public override int StackHeight
|
||||||
{
|
{
|
||||||
get { return stackHeight; }
|
get { return stackHeight; }
|
||||||
@ -87,18 +93,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
TickDistance = scoringDistance / difficulty.SliderTickRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
|
|
||||||
|
|
||||||
public double ProgressAt(double progress)
|
|
||||||
{
|
|
||||||
double p = progress * RepeatCount % 1;
|
|
||||||
if (RepeatAt(progress) % 2 == 1)
|
|
||||||
p = 1 - p;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
|
|
||||||
|
|
||||||
protected override void CreateNestedHitObjects()
|
protected override void CreateNestedHitObjects()
|
||||||
{
|
{
|
||||||
base.CreateNestedHitObjects();
|
base.CreateNestedHitObjects();
|
||||||
@ -113,14 +107,13 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
var length = Curve.Distance;
|
var length = Curve.Distance;
|
||||||
var tickDistance = Math.Min(TickDistance, length);
|
var tickDistance = Math.Min(TickDistance, length);
|
||||||
var repeatDuration = length / Velocity;
|
|
||||||
|
|
||||||
var minDistanceFromEnd = Velocity * 0.01;
|
var minDistanceFromEnd = Velocity * 0.01;
|
||||||
|
|
||||||
for (var repeat = 0; repeat < RepeatCount; repeat++)
|
for (var span = 0; span < this.SpanCount(); span++)
|
||||||
{
|
{
|
||||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
var spanStartTime = StartTime + span * SpanDuration;
|
||||||
var reversed = repeat % 2 == 1;
|
var reversed = span % 2 == 1;
|
||||||
|
|
||||||
for (var d = tickDistance; d <= length; d += tickDistance)
|
for (var d = tickDistance; d <= length; d += tickDistance)
|
||||||
{
|
{
|
||||||
@ -130,20 +123,26 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
var distanceProgress = d / length;
|
var distanceProgress = d / length;
|
||||||
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
|
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
|
||||||
|
|
||||||
|
var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
|
||||||
|
var sampleList = new List<SampleInfo>();
|
||||||
|
|
||||||
|
if (firstSample != null)
|
||||||
|
sampleList.Add(new SampleInfo
|
||||||
|
{
|
||||||
|
Bank = firstSample.Bank,
|
||||||
|
Volume = firstSample.Volume,
|
||||||
|
Name = @"slidertick",
|
||||||
|
});
|
||||||
|
|
||||||
AddNested(new SliderTick
|
AddNested(new SliderTick
|
||||||
{
|
{
|
||||||
RepeatIndex = repeat,
|
SpanIndex = span,
|
||||||
StartTime = repeatStartTime + timeProgress * repeatDuration,
|
StartTime = spanStartTime + timeProgress * SpanDuration,
|
||||||
Position = Curve.PositionAt(distanceProgress),
|
Position = Curve.PositionAt(distanceProgress),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Scale = Scale,
|
Scale = Scale,
|
||||||
ComboColour = ComboColour,
|
ComboColour = ComboColour,
|
||||||
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
|
Samples = sampleList
|
||||||
{
|
|
||||||
Bank = s.Bank,
|
|
||||||
Name = @"slidertick",
|
|
||||||
Volume = s.Volume
|
|
||||||
}))
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,21 +150,18 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
private void createRepeatPoints()
|
private void createRepeatPoints()
|
||||||
{
|
{
|
||||||
var repeatDuration = Distance / Velocity;
|
for (int repeatIndex = 0, repeat = 1; repeatIndex < RepeatCount; repeatIndex++, repeat++)
|
||||||
|
|
||||||
for (var repeat = 1; repeat < RepeatCount; repeat++)
|
|
||||||
{
|
{
|
||||||
var repeatStartTime = StartTime + repeat * repeatDuration;
|
|
||||||
|
|
||||||
AddNested(new RepeatPoint
|
AddNested(new RepeatPoint
|
||||||
{
|
{
|
||||||
RepeatIndex = repeat,
|
RepeatIndex = repeatIndex,
|
||||||
StartTime = repeatStartTime,
|
SpanDuration = SpanDuration,
|
||||||
|
StartTime = StartTime + repeat * SpanDuration,
|
||||||
Position = Curve.PositionAt(repeat % 2),
|
Position = Curve.PositionAt(repeat % 2),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Scale = Scale,
|
Scale = Scale,
|
||||||
ComboColour = ComboColour,
|
ComboColour = ComboColour,
|
||||||
Samples = new List<SampleInfo>(RepeatSamples[repeat])
|
Samples = new List<SampleInfo>(RepeatSamples[repeatIndex])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
public class SliderTick : OsuHitObject
|
public class SliderTick : OsuHitObject
|
||||||
{
|
{
|
||||||
public int RepeatIndex { get; set; }
|
public int SpanIndex { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddStep("Fast Short Slider", () => testShortHighSpeed());
|
AddStep("Fast Short Slider", () => testShortHighSpeed());
|
||||||
AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1));
|
AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1));
|
||||||
AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2));
|
AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2));
|
||||||
|
AddStep("Fast Short Slider 6 Repeats", () => testShortHighSpeed(6));
|
||||||
|
|
||||||
AddStep("Perfect Curve", testCurve);
|
AddStep("Perfect Curve", testCurve);
|
||||||
// TODO more curve types?
|
// TODO more curve types?
|
||||||
@ -84,14 +85,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
private void createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2)
|
private void createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2)
|
||||||
{
|
{
|
||||||
repeats++; // The first run through the slider is considered a repeat
|
|
||||||
|
|
||||||
var repeatSamples = new List<List<SampleInfo>>();
|
var repeatSamples = new List<List<SampleInfo>>();
|
||||||
if (repeats > 1)
|
for (int i = 0; i < repeats; i++)
|
||||||
{
|
repeatSamples.Add(new List<SampleInfo>());
|
||||||
for (int i = 0; i < repeats; i++)
|
|
||||||
repeatSamples.Add(new List<SampleInfo>());
|
|
||||||
}
|
|
||||||
|
|
||||||
var slider = new Slider
|
var slider = new Slider
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
<Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
|
<Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
|
||||||
<Compile Include="Judgements\OsuJudgement.cs" />
|
<Compile Include="Judgements\OsuJudgement.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableRepeatPoint.cs" />
|
<Compile Include="Objects\Drawables\DrawableRepeatPoint.cs" />
|
||||||
|
<Compile Include="Objects\Drawables\ITrackSnaking.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
|
<Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
|
<Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
|
<Compile Include="Objects\Drawables\Pieces\CirclePiece.cs" />
|
||||||
|
@ -84,7 +84,8 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
if (distanceData != null)
|
if (distanceData != null)
|
||||||
{
|
{
|
||||||
int repeats = repeatsData?.RepeatCount ?? 1;
|
// Number of spans of the object - one for the initial length and for each repeat
|
||||||
|
int spans = repeatsData?.SpanCount() ?? 1;
|
||||||
|
|
||||||
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime);
|
TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime);
|
||||||
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime);
|
DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime);
|
||||||
@ -93,7 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
double speedAdjustedBeatLength = timingPoint.BeatLength / speedAdjustment;
|
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 * spans * legacy_velocity_multiplier;
|
||||||
|
|
||||||
// The velocity of the taiko hit object - calculated as the velocity of a drum roll
|
// The velocity of the taiko hit object - calculated as the velocity of a drum roll
|
||||||
double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
|
double taikoVelocity = taiko_base_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * legacy_velocity_multiplier / speedAdjustedBeatLength;
|
||||||
@ -111,7 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
|
// If the drum roll is to be split into hit circles, assume the ticks are 1/8 spaced within the duration of one beat
|
||||||
double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, taikoDuration / repeats);
|
double tickSpacing = Math.Min(speedAdjustedBeatLength / beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate, taikoDuration / spans);
|
||||||
|
|
||||||
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
|
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
|
||||||
{
|
{
|
||||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition);
|
Assert.AreEqual(new Vector2(320, 240), sprite.InitialPosition);
|
||||||
Assert.IsTrue(sprite.IsDrawable);
|
Assert.IsTrue(sprite.IsDrawable);
|
||||||
Assert.AreEqual(Anchor.Centre, sprite.Origin);
|
Assert.AreEqual(Anchor.Centre, sprite.Origin);
|
||||||
Assert.AreEqual(Path.Combine("SB", "lyric", "ja-21.png"), sprite.Path);
|
Assert.AreEqual("SB/lyric/ja-21.png", sprite.Path);
|
||||||
|
|
||||||
var animation = background.Elements.ElementAt(12) as StoryboardAnimation;
|
var animation = background.Elements.ElementAt(12) as StoryboardAnimation;
|
||||||
Assert.NotNull(animation);
|
Assert.NotNull(animation);
|
||||||
@ -82,7 +82,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.IsTrue(animation.IsDrawable);
|
Assert.IsTrue(animation.IsDrawable);
|
||||||
Assert.AreEqual(AnimationLoopType.LoopForever, animation.LoopType);
|
Assert.AreEqual(AnimationLoopType.LoopForever, animation.LoopType);
|
||||||
Assert.AreEqual(Anchor.Centre, animation.Origin);
|
Assert.AreEqual(Anchor.Centre, animation.Origin);
|
||||||
Assert.AreEqual(Path.Combine("SB", "red jitter", "red_0000.jpg"), animation.Path);
|
Assert.AreEqual("SB/red jitter/red_0000.jpg", animation.Path);
|
||||||
Assert.AreEqual(78993, animation.StartTime);
|
Assert.AreEqual(78993, animation.StartTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
osu.Game.Tests/Visual/TestCaseAutoplay.cs
Normal file
21
osu.Game.Tests/Visual/TestCaseAutoplay.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
[Description("Player instantiated with an autoplay mod.")]
|
||||||
|
public class TestCaseAutoplay : TestCasePlayer
|
||||||
|
{
|
||||||
|
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
||||||
|
{
|
||||||
|
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
||||||
|
return base.CreatePlayer(beatmap, ruleset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,35 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Description("Player instantiated with a replay.")]
|
||||||
public class TestCaseReplay : TestCasePlayer
|
public class TestCaseReplay : TestCasePlayer
|
||||||
{
|
{
|
||||||
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
protected override Player CreatePlayer(WorkingBeatmap beatmap, Ruleset ruleset)
|
||||||
{
|
{
|
||||||
|
// We create a dummy RulesetContainer just to get the replay - we don't want to use mods here
|
||||||
|
// to simulate setting a replay rather than having the replay already set for us
|
||||||
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
beatmap.Mods.Value = beatmap.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
|
||||||
return base.CreatePlayer(beatmap, ruleset);
|
var dummyRulesetContainer = ruleset.CreateRulesetContainerWith(beatmap, false);
|
||||||
|
|
||||||
|
// We have the replay
|
||||||
|
var replay = dummyRulesetContainer.Replay;
|
||||||
|
|
||||||
|
// Reset the mods
|
||||||
|
beatmap.Mods.Value = beatmap.Mods.Value.Where(m => !(m is ModAutoplay));
|
||||||
|
|
||||||
|
return new ReplayPlayer(replay)
|
||||||
|
{
|
||||||
|
InitialBeatmap = beatmap
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -15,6 +16,7 @@ using osu.Game.Screens.Edit.Screens.Compose.Timeline;
|
|||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
|
[Ignore("CI regularly hangs on this TestCase...")]
|
||||||
public class TestCaseWaveform : OsuTestCase
|
public class TestCaseWaveform : OsuTestCase
|
||||||
{
|
{
|
||||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||||
|
@ -138,6 +138,7 @@
|
|||||||
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
||||||
<Compile Include="Visual\TestCasePopupDialog.cs" />
|
<Compile Include="Visual\TestCasePopupDialog.cs" />
|
||||||
<Compile Include="Visual\TestCaseRankGraph.cs" />
|
<Compile Include="Visual\TestCaseRankGraph.cs" />
|
||||||
|
<Compile Include="Visual\TestCaseAutoplay.cs" />
|
||||||
<Compile Include="Visual\TestCaseReplay.cs" />
|
<Compile Include="Visual\TestCaseReplay.cs" />
|
||||||
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
|
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
|
||||||
<Compile Include="Visual\TestCaseResults.cs" />
|
<Compile Include="Visual\TestCaseResults.cs" />
|
||||||
|
@ -287,15 +287,16 @@ namespace osu.Game.Beatmaps
|
|||||||
Import(archive);
|
Import(archive);
|
||||||
|
|
||||||
downloadNotification.State = ProgressNotificationState.Completed;
|
downloadNotification.State = ProgressNotificationState.Completed;
|
||||||
|
currentDownloads.Remove(request);
|
||||||
}, TaskCreationOptions.LongRunning);
|
}, TaskCreationOptions.LongRunning);
|
||||||
|
|
||||||
currentDownloads.Remove(request);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
request.Failure += data =>
|
request.Failure += error =>
|
||||||
{
|
{
|
||||||
|
if (error is OperationCanceledException) return;
|
||||||
|
|
||||||
downloadNotification.State = ProgressNotificationState.Completed;
|
downloadNotification.State = ProgressNotificationState.Completed;
|
||||||
Logger.Error(data, "Failed to get beatmap download information");
|
Logger.Error(error, "Beatmap download failed!");
|
||||||
currentDownloads.Remove(request);
|
currentDownloads.Remove(request);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public IQueryable<BeatmapInfo> Beatmaps => GetContext().BeatmapInfo
|
public IQueryable<BeatmapInfo> Beatmaps => GetContext().BeatmapInfo
|
||||||
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
||||||
|
.Include(b => b.BeatmapSet).ThenInclude(s => s.Files).ThenInclude(f => f.FileInfo)
|
||||||
.Include(b => b.Metadata)
|
.Include(b => b.Metadata)
|
||||||
.Include(b => b.Ruleset)
|
.Include(b => b.Ruleset)
|
||||||
.Include(b => b.BaseDifficulty);
|
.Include(b => b.BaseDifficulty);
|
||||||
|
@ -301,6 +301,6 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string cleanFilename(string path) => FileSafety.PathSanitise(path.Trim('\"'));
|
private string cleanFilename(string path) => FileSafety.PathStandardise(FileSafety.PathSanitise(path.Trim('\"')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
71
osu.Game/Configuration/DatabasedConfigManager.cs
Normal file
71
osu.Game/Configuration/DatabasedConfigManager.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
|
namespace osu.Game.Configuration
|
||||||
|
{
|
||||||
|
public abstract class DatabasedConfigManager<T> : ConfigManager<T>
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
private readonly SettingsStore settings;
|
||||||
|
|
||||||
|
private readonly int variant;
|
||||||
|
|
||||||
|
private readonly List<DatabasedSetting> databasedSettings;
|
||||||
|
|
||||||
|
private readonly RulesetInfo ruleset;
|
||||||
|
|
||||||
|
protected DatabasedConfigManager(SettingsStore settings, RulesetInfo ruleset = null, int variant = 0)
|
||||||
|
{
|
||||||
|
this.settings = settings;
|
||||||
|
this.ruleset = ruleset;
|
||||||
|
this.variant = variant;
|
||||||
|
|
||||||
|
databasedSettings = settings.Query(ruleset?.ID, variant);
|
||||||
|
|
||||||
|
InitialiseDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PerformLoad()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool PerformSave()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddBindable<TBindable>(T lookup, Bindable<TBindable> bindable)
|
||||||
|
{
|
||||||
|
base.AddBindable(lookup, bindable);
|
||||||
|
|
||||||
|
var setting = databasedSettings.FirstOrDefault(s => (int)s.Key == (int)(object)lookup);
|
||||||
|
if (setting != null)
|
||||||
|
{
|
||||||
|
bindable.Parse(setting.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
settings.Update(setting = new DatabasedSetting
|
||||||
|
{
|
||||||
|
Key = lookup,
|
||||||
|
Value = bindable.Value,
|
||||||
|
RulesetID = ruleset?.ID,
|
||||||
|
Variant = variant,
|
||||||
|
});
|
||||||
|
|
||||||
|
databasedSettings.Add(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindable.ValueChanged += v =>
|
||||||
|
{
|
||||||
|
setting.Value = v;
|
||||||
|
settings.Update(setting);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
osu.Game/Configuration/DatabasedSetting.cs
Normal file
51
osu.Game/Configuration/DatabasedSetting.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
|
namespace osu.Game.Configuration
|
||||||
|
{
|
||||||
|
[Table("Settings")]
|
||||||
|
public class DatabasedSetting : IHasPrimaryKey
|
||||||
|
{
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public int? RulesetID { get; set; }
|
||||||
|
|
||||||
|
public int? Variant { get; set; }
|
||||||
|
|
||||||
|
[Column("Key")]
|
||||||
|
public int IntKey
|
||||||
|
{
|
||||||
|
get => (int)Key;
|
||||||
|
private set => Key = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Column("Value")]
|
||||||
|
public string StringValue
|
||||||
|
{
|
||||||
|
get => Value.ToString();
|
||||||
|
set => Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Key;
|
||||||
|
public object Value;
|
||||||
|
|
||||||
|
public DatabasedSetting(object key, object value)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for derived classes that may require serialisation.
|
||||||
|
/// </summary>
|
||||||
|
public DatabasedSetting()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{Key}=>{Value}";
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ using osu.Game.Screens.Select;
|
|||||||
|
|
||||||
namespace osu.Game.Configuration
|
namespace osu.Game.Configuration
|
||||||
{
|
{
|
||||||
public class OsuConfigManager : ConfigManager<OsuSetting>
|
public class OsuConfigManager : IniConfigManager<OsuSetting>
|
||||||
{
|
{
|
||||||
protected override void InitialiseDefaults()
|
protected override void InitialiseDefaults()
|
||||||
{
|
{
|
||||||
|
44
osu.Game/Configuration/SettingsStore.cs
Normal file
44
osu.Game/Configuration/SettingsStore.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Database;
|
||||||
|
|
||||||
|
namespace osu.Game.Configuration
|
||||||
|
{
|
||||||
|
public class SettingsStore : DatabaseBackedStore
|
||||||
|
{
|
||||||
|
public event Action SettingChanged;
|
||||||
|
|
||||||
|
public SettingsStore(Func<OsuDbContext> createContext)
|
||||||
|
: base(createContext)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve <see cref="DatabasedSetting"/>s for a specified ruleset/variant content.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rulesetId">The ruleset's internal ID.</param>
|
||||||
|
/// <param name="variant">An optional variant.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<DatabasedSetting> Query(int? rulesetId = null, int? variant = null) =>
|
||||||
|
GetContext().DatabasedSetting.Where(b => b.RulesetID == rulesetId && b.Variant == variant).ToList();
|
||||||
|
|
||||||
|
public void Update(DatabasedSetting setting)
|
||||||
|
{
|
||||||
|
var context = GetContext();
|
||||||
|
|
||||||
|
var newValue = setting.Value;
|
||||||
|
|
||||||
|
Refresh(ref setting);
|
||||||
|
|
||||||
|
setting.Value = newValue;
|
||||||
|
|
||||||
|
context.SaveChanges();
|
||||||
|
|
||||||
|
SettingChanged?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,8 +34,14 @@ namespace osu.Game.Database
|
|||||||
if (context.Entry(obj).State != EntityState.Detached) return;
|
if (context.Entry(obj).State != EntityState.Detached) return;
|
||||||
|
|
||||||
var id = obj.ID;
|
var id = obj.ID;
|
||||||
obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
var foundObject = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
||||||
context.Entry(obj).Reload();
|
if (foundObject != null)
|
||||||
|
{
|
||||||
|
obj = foundObject;
|
||||||
|
context.Entry(obj).Reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context.Add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -8,9 +8,10 @@ using Microsoft.EntityFrameworkCore.Diagnostics;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
|
using DatabasedKeyBinding = osu.Game.Input.Bindings.DatabasedKeyBinding;
|
||||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
@ -22,6 +23,7 @@ namespace osu.Game.Database
|
|||||||
public DbSet<BeatmapMetadata> BeatmapMetadata { get; set; }
|
public DbSet<BeatmapMetadata> BeatmapMetadata { get; set; }
|
||||||
public DbSet<BeatmapSetInfo> BeatmapSetInfo { get; set; }
|
public DbSet<BeatmapSetInfo> BeatmapSetInfo { get; set; }
|
||||||
public DbSet<DatabasedKeyBinding> DatabasedKeyBinding { get; set; }
|
public DbSet<DatabasedKeyBinding> DatabasedKeyBinding { get; set; }
|
||||||
|
public DbSet<DatabasedSetting> DatabasedSetting { get; set; }
|
||||||
public DbSet<FileInfo> FileInfo { get; set; }
|
public DbSet<FileInfo> FileInfo { get; set; }
|
||||||
public DbSet<RulesetInfo> RulesetInfo { get; set; }
|
public DbSet<RulesetInfo> RulesetInfo { get; set; }
|
||||||
|
|
||||||
@ -86,9 +88,11 @@ namespace osu.Game.Database
|
|||||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.DeletePending);
|
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.DeletePending);
|
||||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.Hash).IsUnique();
|
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||||
|
|
||||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.Variant);
|
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.IntAction);
|
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.IntAction);
|
||||||
|
|
||||||
|
modelBuilder.Entity<DatabasedSetting>().HasIndex(b => new { b.RulesetID, b.Variant });
|
||||||
|
|
||||||
modelBuilder.Entity<FileInfo>().HasIndex(b => b.Hash).IsUnique();
|
modelBuilder.Entity<FileInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||||
modelBuilder.Entity<FileInfo>().HasIndex(b => b.ReferenceCount);
|
modelBuilder.Entity<FileInfo>().HasIndex(b => b.ReferenceCount);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
public Color4 FillColour
|
public Color4 FillColour
|
||||||
{
|
{
|
||||||
set { fill.Colour = value; }
|
set { fill.FadeColour(value, 150, Easing.OutQuint); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color4 BackgroundColour
|
public Color4 BackgroundColour
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
private KeyBindingStore store;
|
private KeyBindingStore store;
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings();
|
public override IEnumerable<KeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings(variant ?? 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new instance.
|
/// Create a new instance.
|
||||||
|
@ -37,7 +37,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||||
{
|
{
|
||||||
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene)
|
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene),
|
||||||
|
new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry)
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
protected override IEnumerable<Drawable> KeyBindingInputQueue =>
|
||||||
@ -65,6 +66,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
// In-Game Keybindings
|
// In-Game Keybindings
|
||||||
[Description("Skip Cutscene")]
|
[Description("Skip Cutscene")]
|
||||||
SkipCutscene
|
SkipCutscene,
|
||||||
|
[Description("Quick Retry (Hold)")]
|
||||||
|
QuickRetry,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
329
osu.Game/Migrations/20180125143340_Settings.Designer.cs
generated
Normal file
329
osu.Game/Migrations/20180125143340_Settings.Designer.cs
generated
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using osu.Game.Database;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace osu.Game.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(OsuDbContext))]
|
||||||
|
[Migration("20180125143340_Settings")]
|
||||||
|
partial class Settings
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<float>("ApproachRate");
|
||||||
|
|
||||||
|
b.Property<float>("CircleSize");
|
||||||
|
|
||||||
|
b.Property<float>("DrainRate");
|
||||||
|
|
||||||
|
b.Property<float>("OverallDifficulty");
|
||||||
|
|
||||||
|
b.Property<float>("SliderMultiplier");
|
||||||
|
|
||||||
|
b.Property<float>("SliderTickRate");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapDifficulty");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("AudioLeadIn");
|
||||||
|
|
||||||
|
b.Property<int>("BaseDifficultyID");
|
||||||
|
|
||||||
|
b.Property<int>("BeatDivisor");
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.Property<bool>("Countdown");
|
||||||
|
|
||||||
|
b.Property<double>("DistanceSpacing");
|
||||||
|
|
||||||
|
b.Property<int>("GridSize");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<bool>("Hidden");
|
||||||
|
|
||||||
|
b.Property<bool>("LetterboxInBreaks");
|
||||||
|
|
||||||
|
b.Property<string>("MD5Hash");
|
||||||
|
|
||||||
|
b.Property<int?>("MetadataID");
|
||||||
|
|
||||||
|
b.Property<int?>("OnlineBeatmapID");
|
||||||
|
|
||||||
|
b.Property<string>("Path");
|
||||||
|
|
||||||
|
b.Property<int>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<bool>("SpecialStyle");
|
||||||
|
|
||||||
|
b.Property<float>("StackLeniency");
|
||||||
|
|
||||||
|
b.Property<double>("StarDifficulty");
|
||||||
|
|
||||||
|
b.Property<string>("StoredBookmarks");
|
||||||
|
|
||||||
|
b.Property<double>("TimelineZoom");
|
||||||
|
|
||||||
|
b.Property<string>("Version");
|
||||||
|
|
||||||
|
b.Property<bool>("WidescreenStoryboard");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BaseDifficultyID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("MD5Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineBeatmapID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Artist");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistUnicode");
|
||||||
|
|
||||||
|
b.Property<string>("AudioFile");
|
||||||
|
|
||||||
|
b.Property<string>("AuthorString")
|
||||||
|
.HasColumnName("Author");
|
||||||
|
|
||||||
|
b.Property<string>("BackgroundFile");
|
||||||
|
|
||||||
|
b.Property<int>("PreviewTime");
|
||||||
|
|
||||||
|
b.Property<string>("Source");
|
||||||
|
|
||||||
|
b.Property<string>("Tags");
|
||||||
|
|
||||||
|
b.Property<string>("Title");
|
||||||
|
|
||||||
|
b.Property<string>("TitleUnicode");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapMetadata");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.Property<int>("FileInfoID");
|
||||||
|
|
||||||
|
b.Property<string>("Filename")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("BeatmapSetInfoID");
|
||||||
|
|
||||||
|
b.HasIndex("FileInfoID");
|
||||||
|
|
||||||
|
b.ToTable("BeatmapSetFileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("DeletePending");
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int?>("MetadataID");
|
||||||
|
|
||||||
|
b.Property<int?>("OnlineBeatmapSetID");
|
||||||
|
|
||||||
|
b.Property<bool>("Protected");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("DeletePending");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("MetadataID");
|
||||||
|
|
||||||
|
b.HasIndex("OnlineBeatmapSetID")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("BeatmapSetInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("IntKey")
|
||||||
|
.HasColumnName("Key");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<string>("StringValue")
|
||||||
|
.HasColumnName("Value");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("IntAction")
|
||||||
|
.HasColumnName("Action");
|
||||||
|
|
||||||
|
b.Property<string>("KeysString")
|
||||||
|
.HasColumnName("Keys");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("IntAction");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("KeyBinding");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Hash");
|
||||||
|
|
||||||
|
b.Property<int>("ReferenceCount");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("Hash")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ReferenceCount");
|
||||||
|
|
||||||
|
b.ToTable("FileInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int?>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Available");
|
||||||
|
|
||||||
|
b.Property<string>("InstantiationInfo");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<string>("ShortName");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("Available");
|
||||||
|
|
||||||
|
b.HasIndex("ShortName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("RulesetInfo");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("BaseDifficultyID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
|
||||||
|
.WithMany("Beatmaps")
|
||||||
|
.HasForeignKey("BeatmapSetInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||||
|
.WithMany("Beatmaps")
|
||||||
|
.HasForeignKey("MetadataID");
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RulesetID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
|
||||||
|
.WithMany("Files")
|
||||||
|
.HasForeignKey("BeatmapSetInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FileInfoID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||||
|
.WithMany("BeatmapSets")
|
||||||
|
.HasForeignKey("MetadataID");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
osu.Game/Migrations/20180125143340_Settings.cs
Normal file
57
osu.Game/Migrations/20180125143340_Settings.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace osu.Game.Migrations
|
||||||
|
{
|
||||||
|
public partial class Settings : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_KeyBinding_Variant",
|
||||||
|
table: "KeyBinding");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Settings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ID = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Key = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
RulesetID = table.Column<int>(type: "INTEGER", nullable: true),
|
||||||
|
Value = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Variant = table.Column<int>(type: "INTEGER", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Settings", x => x.ID);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_KeyBinding_RulesetID_Variant",
|
||||||
|
table: "KeyBinding",
|
||||||
|
columns: new[] { "RulesetID", "Variant" });
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Settings_RulesetID_Variant",
|
||||||
|
table: "Settings",
|
||||||
|
columns: new[] { "RulesetID", "Variant" });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Settings");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_KeyBinding_RulesetID_Variant",
|
||||||
|
table: "KeyBinding");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_KeyBinding_Variant",
|
||||||
|
table: "KeyBinding",
|
||||||
|
column: "Variant");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -193,6 +193,28 @@ namespace osu.Game.Migrations
|
|||||||
b.ToTable("BeatmapSetInfo");
|
b.ToTable("BeatmapSetInfo");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ID")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("IntKey")
|
||||||
|
.HasColumnName("Key");
|
||||||
|
|
||||||
|
b.Property<int?>("RulesetID");
|
||||||
|
|
||||||
|
b.Property<string>("StringValue")
|
||||||
|
.HasColumnName("Value");
|
||||||
|
|
||||||
|
b.Property<int?>("Variant");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ID")
|
b.Property<int>("ID")
|
||||||
@ -212,7 +234,7 @@ namespace osu.Game.Migrations
|
|||||||
|
|
||||||
b.HasIndex("IntAction");
|
b.HasIndex("IntAction");
|
||||||
|
|
||||||
b.HasIndex("Variant");
|
b.HasIndex("RulesetID", "Variant");
|
||||||
|
|
||||||
b.ToTable("KeyBinding");
|
b.ToTable("KeyBinding");
|
||||||
});
|
});
|
||||||
|
@ -126,6 +126,7 @@ namespace osu.Game.Online.API
|
|||||||
userReq.Success += u =>
|
userReq.Success += u =>
|
||||||
{
|
{
|
||||||
LocalUser.Value = u;
|
LocalUser.Value = u;
|
||||||
|
Username = LocalUser.Value.Username;
|
||||||
failureCount = 0;
|
failureCount = 0;
|
||||||
|
|
||||||
//we're connected!
|
//we're connected!
|
||||||
|
@ -71,6 +71,7 @@ namespace osu.Game
|
|||||||
private OsuScreen screenStack;
|
private OsuScreen screenStack;
|
||||||
|
|
||||||
private VolumeControl volume;
|
private VolumeControl volume;
|
||||||
|
private OnScreenDisplay onscreenDisplay;
|
||||||
|
|
||||||
private Bindable<int> configRuleset;
|
private Bindable<int> configRuleset;
|
||||||
public Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
public Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
@ -110,7 +111,7 @@ namespace osu.Game
|
|||||||
Task.Run(() => BeatmapManager.Import(paths.ToArray()));
|
Task.Run(() => BeatmapManager.Import(paths.ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies.Cache(this);
|
dependencies.CacheAs<OsuGame>(this);
|
||||||
|
|
||||||
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
||||||
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
|
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
|
||||||
@ -207,7 +208,7 @@ namespace osu.Game
|
|||||||
}, overlayContent.Add);
|
}, overlayContent.Add);
|
||||||
|
|
||||||
loadComponentSingleFile(volume = new VolumeControl(), Add);
|
loadComponentSingleFile(volume = new VolumeControl(), Add);
|
||||||
loadComponentSingleFile(new OnScreenDisplay(), Add);
|
loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add);
|
||||||
|
|
||||||
//overlay elements
|
//overlay elements
|
||||||
loadComponentSingleFile(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
|
loadComponentSingleFile(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
|
||||||
@ -244,6 +245,7 @@ namespace osu.Game
|
|||||||
forwardLoggedErrorsToNotifications();
|
forwardLoggedErrorsToNotifications();
|
||||||
|
|
||||||
dependencies.Cache(settings);
|
dependencies.Cache(settings);
|
||||||
|
dependencies.Cache(onscreenDisplay);
|
||||||
dependencies.Cache(social);
|
dependencies.Cache(social);
|
||||||
dependencies.Cache(direct);
|
dependencies.Cache(direct);
|
||||||
dependencies.Cache(chat);
|
dependencies.Cache(chat);
|
||||||
|
@ -44,6 +44,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
protected KeyBindingStore KeyBindingStore;
|
protected KeyBindingStore KeyBindingStore;
|
||||||
|
|
||||||
|
protected SettingsStore SettingsStore;
|
||||||
|
|
||||||
protected CursorOverrideContainer CursorOverrideContainer;
|
protected CursorOverrideContainer CursorOverrideContainer;
|
||||||
|
|
||||||
protected override string MainResourceFile => @"osu.Game.Resources.dll";
|
protected override string MainResourceFile => @"osu.Game.Resources.dll";
|
||||||
@ -93,7 +95,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
dependencies.Cache(new LargeTextureStore(new RawTextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures"))));
|
dependencies.Cache(new LargeTextureStore(new RawTextureLoaderStore(new NamespacedResourceStore<byte[]>(Resources, @"Textures"))));
|
||||||
|
|
||||||
dependencies.Cache(this);
|
dependencies.CacheAs<OsuGameBase>(this);
|
||||||
dependencies.Cache(LocalConfig);
|
dependencies.Cache(LocalConfig);
|
||||||
|
|
||||||
runMigrations();
|
runMigrations();
|
||||||
@ -109,10 +111,11 @@ namespace osu.Game
|
|||||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory.GetContext, RulesetStore, API, Host));
|
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, contextFactory.GetContext, RulesetStore, API, Host));
|
||||||
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory.GetContext, Host, BeatmapManager, RulesetStore));
|
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, contextFactory.GetContext, Host, BeatmapManager, RulesetStore));
|
||||||
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory.GetContext, RulesetStore));
|
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory.GetContext, RulesetStore));
|
||||||
|
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory.GetContext));
|
||||||
dependencies.Cache(new OsuColour());
|
dependencies.Cache(new OsuColour());
|
||||||
|
|
||||||
//this completely overrides the framework default. will need to change once we make a proper FontStore.
|
//this completely overrides the framework default. will need to change once we make a proper FontStore.
|
||||||
dependencies.Cache(Fonts = new FontStore { ScaleAdjust = 100 }, true);
|
dependencies.Cache(Fonts = new FontStore { ScaleAdjust = 100 });
|
||||||
|
|
||||||
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/FontAwesome"));
|
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/FontAwesome"));
|
||||||
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/osuFont"));
|
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/osuFont"));
|
||||||
|
@ -82,7 +82,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
|||||||
|
|
||||||
if (Playing.Value && preview != null)
|
if (Playing.Value && preview != null)
|
||||||
{
|
{
|
||||||
progress.Width = (float)(preview.CurrentTime / preview.Length);
|
// prevent negative (potential infinite) width if a track without length was loaded
|
||||||
|
progress.Width = preview.Length > 0 ? (float)(preview.CurrentTime / preview.Length) : 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ using osu.Game.Graphics.Sprites;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
@ -65,11 +64,14 @@ namespace osu.Game.Overlays.Direct
|
|||||||
Colour = Color4.Black.Opacity(0.3f),
|
Colour = Color4.Black.Opacity(0.3f),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private OsuColour colours;
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay)
|
private void load(BeatmapManager beatmaps, OsuColour colours, BeatmapSetOverlay beatmapSetOverlay)
|
||||||
{
|
{
|
||||||
this.beatmaps = beatmaps;
|
this.beatmaps = beatmaps;
|
||||||
this.beatmapSetOverlay = beatmapSetOverlay;
|
this.beatmapSetOverlay = beatmapSetOverlay;
|
||||||
|
this.colours = colours;
|
||||||
|
|
||||||
AddInternal(content = new Container
|
AddInternal(content = new Container
|
||||||
{
|
{
|
||||||
@ -106,6 +108,8 @@ namespace osu.Game.Overlays.Direct
|
|||||||
beatmaps.BeatmapDownloadBegan += attachDownload;
|
beatmaps.BeatmapDownloadBegan += attachDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool DisposeOnDeathRemoval => true;
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
@ -180,7 +184,6 @@ namespace osu.Game.Overlays.Direct
|
|||||||
{
|
{
|
||||||
progressBar.Current.Value = 0;
|
progressBar.Current.Value = 0;
|
||||||
progressBar.FadeOut(500);
|
progressBar.FadeOut(500);
|
||||||
Logger.Error(e, "Failed to get beatmap download information");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
request.DownloadProgressed += progress => progressBar.Current.Value = progress;
|
request.DownloadProgressed += progress => progressBar.Current.Value = progress;
|
||||||
@ -188,7 +191,7 @@ namespace osu.Game.Overlays.Direct
|
|||||||
request.Success += data =>
|
request.Success += data =>
|
||||||
{
|
{
|
||||||
progressBar.Current.Value = 1;
|
progressBar.Current.Value = 1;
|
||||||
progressBar.FadeOut(500);
|
progressBar.FillColour = colours.Yellow;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Configuration;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -39,6 +40,8 @@ namespace osu.Game.Overlays.Direct
|
|||||||
private readonly SpriteIcon icon;
|
private readonly SpriteIcon icon;
|
||||||
private readonly LoadingAnimation loadingAnimation;
|
private readonly LoadingAnimation loadingAnimation;
|
||||||
|
|
||||||
|
private readonly BindableDouble muteBindable = new BindableDouble();
|
||||||
|
|
||||||
private const float transition_duration = 500;
|
private const float transition_duration = 500;
|
||||||
|
|
||||||
private bool loading
|
private bool loading
|
||||||
@ -83,9 +86,10 @@ namespace osu.Game.Overlays.Direct
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colour)
|
private void load(OsuColour colour, AudioManager audio)
|
||||||
{
|
{
|
||||||
hoverColour = colour.Yellow;
|
hoverColour = colour.Yellow;
|
||||||
|
this.audio = audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(InputState state)
|
protected override bool OnClick(InputState state)
|
||||||
@ -128,21 +132,36 @@ namespace osu.Game.Overlays.Direct
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Preview.Seek(0);
|
Preview.Restart();
|
||||||
Preview.Start();
|
|
||||||
|
audio.Track.AddAdjustment(AdjustableProperty.Volume, muteBindable);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
audio.Track.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
|
||||||
|
|
||||||
Preview?.Stop();
|
Preview?.Stop();
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
Playing.Value = false;
|
||||||
|
}
|
||||||
|
|
||||||
private TrackLoader trackLoader;
|
private TrackLoader trackLoader;
|
||||||
|
private AudioManager audio;
|
||||||
|
|
||||||
private void beginAudioLoad()
|
private void beginAudioLoad()
|
||||||
{
|
{
|
||||||
if (trackLoader != null) return;
|
if (trackLoader != null)
|
||||||
|
{
|
||||||
|
Preview = trackLoader.Preview;
|
||||||
|
Playing.TriggerChange();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
@ -164,6 +183,7 @@ namespace osu.Game.Overlays.Direct
|
|||||||
private readonly string preview;
|
private readonly string preview;
|
||||||
|
|
||||||
public Track Preview;
|
public Track Preview;
|
||||||
|
private TrackManager trackManager;
|
||||||
|
|
||||||
public TrackLoader(string preview)
|
public TrackLoader(string preview)
|
||||||
{
|
{
|
||||||
@ -171,10 +191,22 @@ namespace osu.Game.Overlays.Direct
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio, FrameworkConfigManager config)
|
||||||
{
|
{
|
||||||
|
// create a local trackManager to bypass the mute we are applying above.
|
||||||
|
audio.AddItem(trackManager = new TrackManager(new OnlineStore()));
|
||||||
|
|
||||||
|
// add back the user's music volume setting (since we are no longer in the global TrackManager's hierarchy).
|
||||||
|
config.BindWith(FrameworkSetting.VolumeMusic, trackManager.Volume);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(preview))
|
if (!string.IsNullOrEmpty(preview))
|
||||||
Preview = audio.Track.Get(preview);
|
Preview = trackManager.Get(preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
trackManager?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ namespace osu.Game.Overlays
|
|||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
var onlineIds = response.Select(r => r.OnlineBeatmapSetID).ToList();
|
var onlineIds = response.Select(r => r.OnlineBeatmapSetID).ToList();
|
||||||
var presentOnlineIds = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID)).Select(r => r.OnlineBeatmapSetID).ToList();
|
var presentOnlineIds = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID) && !s.DeletePending).Select(r => r.OnlineBeatmapSetID).ToList();
|
||||||
var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList();
|
var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList();
|
||||||
|
|
||||||
// may not need scheduling; loads async internally.
|
// may not need scheduling; loads async internally.
|
||||||
@ -313,6 +313,14 @@ namespace osu.Game.Overlays
|
|||||||
api.Queue(getSetsRequest);
|
api.Queue(getSetsRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
base.PopOut();
|
||||||
|
|
||||||
|
if (playing != null)
|
||||||
|
playing.PreviewPlaying.Value = false;
|
||||||
|
}
|
||||||
|
|
||||||
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;
|
private int distinctCount(List<string> list) => list.Distinct().ToArray().Length;
|
||||||
|
|
||||||
public class ResultCounts
|
public class ResultCounts
|
||||||
|
@ -5,8 +5,6 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
@ -20,10 +18,12 @@ using osu.Framework.Localisation;
|
|||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Overlays.Music;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays.Music;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
@ -65,6 +65,12 @@ namespace osu.Game.Overlays
|
|||||||
AlwaysPresent = true;
|
AlwaysPresent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnDragStart(InputState state)
|
||||||
|
{
|
||||||
|
base.OnDragStart(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
if (base.OnDrag(state)) return true;
|
if (base.OnDrag(state)) return true;
|
||||||
|
@ -5,7 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Configuration.Tracking;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -118,43 +118,62 @@ namespace osu.Game.Overlays
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager frameworkConfig)
|
private void load(FrameworkConfigManager frameworkConfig)
|
||||||
{
|
{
|
||||||
trackSetting(frameworkConfig.GetBindable<FrameSync>(FrameworkSetting.FrameSync), v => display(v, "Frame Limiter", v.GetDescription(), "Ctrl+F7"));
|
BeginTracking(this, frameworkConfig);
|
||||||
trackSetting(frameworkConfig.GetBindable<string>(FrameworkSetting.AudioDevice), v => display(v, "Audio Device", string.IsNullOrEmpty(v) ? "Default" : v, v));
|
|
||||||
trackSetting(frameworkConfig.GetBindable<bool>(FrameworkSetting.ShowLogOverlay), v => display(v, "Debug Logs", v ? "visible" : "hidden", "Ctrl+F10"));
|
|
||||||
|
|
||||||
void displayResolution() => display(null, "Screen Resolution", frameworkConfig.Get<int>(FrameworkSetting.Width) + "x" + frameworkConfig.Get<int>(FrameworkSetting.Height));
|
|
||||||
|
|
||||||
trackSetting(frameworkConfig.GetBindable<int>(FrameworkSetting.Width), v => displayResolution());
|
|
||||||
trackSetting(frameworkConfig.GetBindable<int>(FrameworkSetting.Height), v => displayResolution());
|
|
||||||
|
|
||||||
trackSetting(frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity), v => display(v, "Cursor Sensitivity", v.ToString(@"0.##x"), "Ctrl+Alt+R to reset"));
|
|
||||||
trackSetting(frameworkConfig.GetBindable<string>(FrameworkSetting.ActiveInputHandlers),
|
|
||||||
delegate (string v)
|
|
||||||
{
|
|
||||||
bool raw = v.Contains("Raw");
|
|
||||||
display(raw, "Raw Input", raw ? "enabled" : "disabled", "Ctrl+Alt+R to reset");
|
|
||||||
});
|
|
||||||
|
|
||||||
trackSetting(frameworkConfig.GetBindable<WindowMode>(FrameworkSetting.WindowMode), v => display(v, "Screen Mode", v.ToString(), "Alt+Enter"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<IBindable> references = new List<IBindable>();
|
private readonly Dictionary<(object, IConfigManager), TrackedSettings> trackedConfigManagers = new Dictionary<(object, IConfigManager), TrackedSettings>();
|
||||||
|
|
||||||
private void trackSetting<T>(Bindable<T> bindable, Action<T> action)
|
/// <summary>
|
||||||
|
/// Registers a <see cref="ConfigManager{T}"/> to have its settings tracked by this <see cref="OnScreenDisplay"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The object that is registering the <see cref="ConfigManager{T}"/> to be tracked.</param>
|
||||||
|
/// <param name="configManager">The <see cref="ConfigManager{T}"/> to be tracked.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">If <paramref name="configManager"/> is null.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
|
||||||
|
public void BeginTracking(object source, ITrackableConfigManager configManager)
|
||||||
{
|
{
|
||||||
// we need to keep references as we bind
|
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||||
references.Add(bindable);
|
|
||||||
|
|
||||||
bindable.ValueChanged += action;
|
if (trackedConfigManagers.ContainsKey((source, configManager)))
|
||||||
|
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
|
||||||
|
|
||||||
|
var trackedSettings = configManager.CreateTrackedSettings();
|
||||||
|
if (trackedSettings == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
configManager.LoadInto(trackedSettings);
|
||||||
|
trackedSettings.SettingChanged += display;
|
||||||
|
|
||||||
|
trackedConfigManagers.Add((source, configManager), trackedSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display(object rawValue, string settingName, string settingValue, string shortcut = @"")
|
/// <summary>
|
||||||
|
/// Unregisters a <see cref="ConfigManager{T}"/> from having its settings tracked by this <see cref="OnScreenDisplay"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The object that registered the <see cref="ConfigManager{T}"/> to be tracked.</param>
|
||||||
|
/// <param name="configManager">The <see cref="ConfigManager{T}"/> that is being tracked.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">If <paramref name="configManager"/> is null.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <see cref="source"/>.</exception>
|
||||||
|
public void StopTracking(object source, ITrackableConfigManager configManager)
|
||||||
|
{
|
||||||
|
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
||||||
|
|
||||||
|
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
|
||||||
|
throw new InvalidOperationException($"{nameof(configManager)} is not registered.");
|
||||||
|
|
||||||
|
existing.Unload();
|
||||||
|
existing.SettingChanged -= display;
|
||||||
|
|
||||||
|
trackedConfigManagers.Remove((source, configManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void display(SettingDescription description)
|
||||||
{
|
{
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
textLine1.Text = settingName.ToUpper();
|
textLine1.Text = description.Name.ToUpper();
|
||||||
textLine2.Text = settingValue;
|
textLine2.Text = description.Value;
|
||||||
textLine3.Text = shortcut.ToUpper();
|
textLine3.Text = description.Shortcut.ToUpper();
|
||||||
|
|
||||||
box.Animate(
|
box.Animate(
|
||||||
b => b.FadeIn(500, Easing.OutQuint),
|
b => b.FadeIn(500, Easing.OutQuint),
|
||||||
@ -167,16 +186,16 @@ namespace osu.Game.Overlays
|
|||||||
int optionCount = 0;
|
int optionCount = 0;
|
||||||
int selectedOption = -1;
|
int selectedOption = -1;
|
||||||
|
|
||||||
if (rawValue is bool)
|
if (description.RawValue is bool)
|
||||||
{
|
{
|
||||||
optionCount = 1;
|
optionCount = 1;
|
||||||
if ((bool)rawValue) selectedOption = 0;
|
if ((bool)description.RawValue) selectedOption = 0;
|
||||||
}
|
}
|
||||||
else if (rawValue is Enum)
|
else if (description.RawValue is Enum)
|
||||||
{
|
{
|
||||||
var values = Enum.GetValues(rawValue.GetType());
|
var values = Enum.GetValues(description.RawValue.GetType());
|
||||||
optionCount = values.Length;
|
optionCount = values.Length;
|
||||||
selectedOption = Convert.ToInt32(rawValue);
|
selectedOption = Convert.ToInt32(description.RawValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
textLine2.Origin = optionCount > 0 ? Anchor.BottomCentre : Anchor.Centre;
|
textLine2.Origin = optionCount > 0 ? Anchor.BottomCentre : Anchor.Centre;
|
||||||
|
@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(SettingsOverlay settings)
|
private void load(MainSettings settings)
|
||||||
{
|
{
|
||||||
StateContainer = settings;
|
StateContainer = settings;
|
||||||
}
|
}
|
||||||
|
11
osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs
Normal file
11
osu.Game/Rulesets/Configuration/IRulesetConfigManager.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Configuration.Tracking;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Configuration
|
||||||
|
{
|
||||||
|
public interface IRulesetConfigManager : ITrackableConfigManager
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
15
osu.Game/Rulesets/Configuration/RulesetConfigManager.cs
Normal file
15
osu.Game/Rulesets/Configuration/RulesetConfigManager.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Configuration
|
||||||
|
{
|
||||||
|
public abstract class RulesetConfigManager<T> : DatabasedConfigManager<T>, IRulesetConfigManager
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
protected RulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int variant) : base(settings, ruleset, variant)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -136,7 +136,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<DrawableHitObject, ArmedState> ApplyCustomUpdateState;
|
public event Action<DrawableHitObject, ArmedState> ApplyCustomUpdateState;
|
||||||
|
|
||||||
protected void PlaySamples() => Samples.ForEach(s => s?.Play());
|
/// <summary>
|
||||||
|
/// Plays all the hitsounds for this <see cref="DrawableHitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
public void PlaySamples() => Samples.ForEach(s => s?.Play());
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
|
@ -77,6 +77,10 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
if (repeatCount > 9000)
|
if (repeatCount > 9000)
|
||||||
throw new ArgumentOutOfRangeException(nameof(repeatCount), @"Repeat count is way too high");
|
throw new ArgumentOutOfRangeException(nameof(repeatCount), @"Repeat count is way too high");
|
||||||
|
|
||||||
|
// osu-stable treated the first span of the slider as a repeat, but no repeats are happening
|
||||||
|
repeatCount = Math.Max(0, repeatCount - 1);
|
||||||
|
|
||||||
|
|
||||||
if (split.Length > 7)
|
if (split.Length > 7)
|
||||||
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
|
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
@ -84,8 +88,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
readCustomSampleBanks(split[10], bankInfo);
|
readCustomSampleBanks(split[10], bankInfo);
|
||||||
|
|
||||||
// One node for each repeat + the start and end nodes
|
// One node for each repeat + the start and end nodes
|
||||||
// Note that the first length of the slider is considered a repeat, but there are no actual repeats happening
|
int nodes = repeatCount + 2;
|
||||||
int nodes = Math.Max(0, repeatCount - 1) + 2;
|
|
||||||
|
|
||||||
// Populate node sample bank infos with the default hit object sample bank
|
// Populate node sample bank infos with the default hit object sample bank
|
||||||
var nodeBankInfos = new List<SampleBankInfo>();
|
var nodeBankInfos = new List<SampleBankInfo>();
|
||||||
@ -128,7 +131,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
|
|
||||||
// Generate the final per-node samples
|
// Generate the final per-node samples
|
||||||
var nodeSamples = new List<List<SampleInfo>>(nodes);
|
var nodeSamples = new List<List<SampleInfo>>(nodes);
|
||||||
for (int i = 0; i <= repeatCount; i++)
|
for (int i = 0; i < nodes; i++)
|
||||||
nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
|
nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
|
||||||
|
|
||||||
result = CreateSlider(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, points, length, curveType, repeatCount, nodeSamples);
|
result = CreateSlider(new Vector2(int.Parse(split[0]), int.Parse(split[1])), combo, points, length, curveType, repeatCount, nodeSamples);
|
||||||
|
@ -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 osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -18,34 +17,23 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const float base_scoring_distance = 100;
|
private const float base_scoring_distance = 100;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="ConvertSlider"/>s don't need a curve since they're converted to ruleset-specific hitobjects.
|
||||||
|
/// </summary>
|
||||||
|
public SliderCurve Curve { get; } = null;
|
||||||
public List<Vector2> ControlPoints { get; set; }
|
public List<Vector2> ControlPoints { get; set; }
|
||||||
public CurveType CurveType { get; set; }
|
public CurveType CurveType { get; set; }
|
||||||
|
|
||||||
public double Distance { get; set; }
|
public double Distance { get; set; }
|
||||||
|
|
||||||
public List<List<SampleInfo>> RepeatSamples { get; set; }
|
public List<List<SampleInfo>> RepeatSamples { get; set; }
|
||||||
public int RepeatCount { get; set; } = 1;
|
public int RepeatCount { get; set; }
|
||||||
|
|
||||||
public double EndTime => StartTime + RepeatCount * Distance / Velocity;
|
public double EndTime => StartTime + this.SpanCount() * Distance / Velocity;
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
public double Velocity = 1;
|
public double Velocity = 1;
|
||||||
|
|
||||||
public Vector2 PositionAt(double progress)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public double ProgressAt(double progress)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RepeatAt(double progress)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
@ -11,6 +11,11 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHasCurve : IHasDistance, IHasRepeats
|
public interface IHasCurve : IHasDistance, IHasRepeats
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The curve.
|
||||||
|
/// </summary>
|
||||||
|
SliderCurve Curve { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The control points that shape the curve.
|
/// The control points that shape the curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -20,7 +25,10 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// The type of curve.
|
/// The type of curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
CurveType CurveType { get; }
|
CurveType CurveType { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HasCurveExtensions
|
||||||
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes the position on the curve at a given progress, accounting for repeat logic.
|
/// Computes the position on the curve at a given progress, accounting for repeat logic.
|
||||||
/// <para>
|
/// <para>
|
||||||
@ -28,20 +36,28 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
Vector2 PositionAt(double progress);
|
public static Vector2 PositionAt(this IHasCurve obj, double progress)
|
||||||
|
=> obj.Curve.PositionAt(obj.ProgressAt(progress));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the progress along the curve, accounting for repeat logic.
|
/// Finds the progress along the curve, accounting for repeat logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
|
/// <returns>[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</returns>
|
||||||
double ProgressAt(double progress);
|
public static double ProgressAt(this IHasCurve obj, double progress)
|
||||||
|
{
|
||||||
|
double p = progress * obj.SpanCount() % 1;
|
||||||
|
if (obj.SpanAt(progress) % 2 == 1)
|
||||||
|
p = 1 - p;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines which repeat of the curve the progress point is on.
|
/// Determines which span of the curve the progress point is on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
/// <param name="progress">[0, 1] where 0 is the beginning of the curve and 1 is the end of the curve.</param>
|
||||||
/// <returns>[0, RepeatCount] where 0 is the first run.</returns>
|
/// <returns>[0, SpanCount) where 0 is the first run.</returns>
|
||||||
int RepeatAt(double progress);
|
public static int SpanAt(this IHasCurve obj, double progress)
|
||||||
|
=> (int)(progress * obj.SpanCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,13 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
List<List<SampleInfo>> RepeatSamples { get; }
|
List<List<SampleInfo>> RepeatSamples { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class HasRepeatsExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of times the length of this <see cref="IHasRepeats"/> spans.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object that has repeats.</param>
|
||||||
|
public static int SpanCount(this IHasRepeats obj) => obj.RepeatCount + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Game.Database;
|
|||||||
using osu.Game.IO.Legacy;
|
using osu.Game.IO.Legacy;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Users;
|
||||||
using SharpCompress.Compressors.LZMA;
|
using SharpCompress.Compressors.LZMA;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
@ -54,7 +55,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
var beatmapHash = sr.ReadString();
|
var beatmapHash = sr.ReadString();
|
||||||
score.Beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == beatmapHash);
|
score.Beatmap = beatmaps.QueryBeatmap(b => b.MD5Hash == beatmapHash);
|
||||||
/* score.PlayerName = */
|
/* score.PlayerName = */
|
||||||
sr.ReadString();
|
score.User = new User { Username = sr.ReadString() };
|
||||||
/* var localScoreChecksum = */
|
/* var localScoreChecksum = */
|
||||||
sr.ReadString();
|
sr.ReadString();
|
||||||
/* score.Count300 = */
|
/* score.Count300 = */
|
||||||
@ -107,7 +108,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
|
using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize))
|
||||||
using (var reader = new StreamReader(lzma))
|
using (var reader = new StreamReader(lzma))
|
||||||
|
{
|
||||||
score.Replay = createLegacyReplay(reader);
|
score.Replay = createLegacyReplay(reader);
|
||||||
|
score.Replay.User = score.User;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +133,22 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
{
|
{
|
||||||
var split = l.Split('|');
|
var split = l.Split('|');
|
||||||
|
|
||||||
if (split.Length < 4 || float.Parse(split[0]) < 0) continue;
|
if (split.Length < 4)
|
||||||
|
continue;
|
||||||
|
|
||||||
lastTime += float.Parse(split[0]);
|
if (split[0] == "-12345")
|
||||||
|
{
|
||||||
|
// Todo: The seed is provided in split[3], which we'll need to use at some point
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var diff = float.Parse(split[0]);
|
||||||
|
lastTime += diff;
|
||||||
|
|
||||||
|
// Todo: At some point we probably want to rewind and play back the negative-time frames
|
||||||
|
// but for now we'll achieve equal playback to stable by skipping negative frames
|
||||||
|
if (diff < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
frames.Add(new ReplayFrame(
|
frames.Add(new ReplayFrame(
|
||||||
lastTime,
|
lastTime,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -36,8 +35,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width.</param>
|
/// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width.</param>
|
||||||
protected Playfield(float? customWidth = null)
|
protected Playfield(float? customWidth = null)
|
||||||
{
|
{
|
||||||
// Default height since we force relative size axes
|
RelativeSizeAxes = Axes.Both;
|
||||||
Size = Vector2.One;
|
|
||||||
|
|
||||||
AddInternal(ScaledContent = new ScaledContainer
|
AddInternal(ScaledContent = new ScaledContainer
|
||||||
{
|
{
|
||||||
@ -62,12 +60,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
Add(HitObjects);
|
Add(HitObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Axes RelativeSizeAxes
|
|
||||||
{
|
|
||||||
get { return Axes.Both; }
|
|
||||||
set { throw new InvalidOperationException($@"{nameof(Playfield)}'s {nameof(RelativeSizeAxes)} should never be changed from {Axes.Both}"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield.
|
/// Performs post-processing tasks (if any) after all DrawableHitObjects are loaded into this Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -13,8 +13,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Configuration;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -34,6 +38,11 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AspectAdjust = true;
|
public bool AspectAdjust = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The selected variant.
|
||||||
|
/// </summary>
|
||||||
|
public virtual int Variant => 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The input manager for this RulesetContainer.
|
/// The input manager for this RulesetContainer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -45,9 +54,9 @@ namespace osu.Game.Rulesets.UI
|
|||||||
public PassThroughInputManager KeyBindingInputManager;
|
public PassThroughInputManager KeyBindingInputManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether we have a replay loaded currently.
|
/// Whether a replay is currently loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool HasReplayLoaded => ReplayInputManager?.ReplayInputHandler != null;
|
public readonly BindableBool HasReplayLoaded = new BindableBool();
|
||||||
|
|
||||||
public abstract IEnumerable<HitObject> Objects { get; }
|
public abstract IEnumerable<HitObject> Objects { get; }
|
||||||
|
|
||||||
@ -64,6 +73,14 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
protected readonly Ruleset Ruleset;
|
protected readonly Ruleset Ruleset;
|
||||||
|
|
||||||
|
private IRulesetConfigManager rulesetConfig;
|
||||||
|
private OnScreenDisplay onScreenDisplay;
|
||||||
|
|
||||||
|
private DependencyContainer dependencies;
|
||||||
|
|
||||||
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
|
||||||
|
=> dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A visual representation of a <see cref="Rulesets.Ruleset"/>.
|
/// A visual representation of a <see cref="Rulesets.Ruleset"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -76,6 +93,20 @@ namespace osu.Game.Rulesets.UI
|
|||||||
Cursor = CreateCursor();
|
Cursor = CreateCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OnScreenDisplay onScreenDisplay, SettingsStore settings)
|
||||||
|
{
|
||||||
|
this.onScreenDisplay = onScreenDisplay;
|
||||||
|
|
||||||
|
rulesetConfig = CreateConfig(Ruleset, settings);
|
||||||
|
|
||||||
|
if (rulesetConfig != null)
|
||||||
|
{
|
||||||
|
dependencies.Cache(rulesetConfig);
|
||||||
|
onScreenDisplay?.BeginTracking(this, rulesetConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public abstract ScoreProcessor CreateScoreProcessor();
|
public abstract ScoreProcessor CreateScoreProcessor();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -99,6 +130,8 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
Replay = replay;
|
Replay = replay;
|
||||||
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||||
|
|
||||||
|
HasReplayLoaded.Value = ReplayInputManager.ReplayInputHandler != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -107,11 +140,24 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual CursorContainer CreateCursor() => null;
|
protected virtual CursorContainer CreateCursor() => null;
|
||||||
|
|
||||||
|
protected virtual IRulesetConfigManager CreateConfig(Ruleset ruleset, SettingsStore settings) => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a Playfield.
|
/// Creates a Playfield.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The Playfield.</returns>
|
/// <returns>The Playfield.</returns>
|
||||||
protected abstract Playfield CreatePlayfield();
|
protected abstract Playfield CreatePlayfield();
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (rulesetConfig != null)
|
||||||
|
{
|
||||||
|
onScreenDisplay?.StopTracking(this, rulesetConfig);
|
||||||
|
rulesetConfig = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -151,7 +197,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the specified beatmap is assumed to be specific to the current ruleset.
|
/// Whether the specified beatmap is assumed to be specific to the current ruleset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly bool IsForCurrentRuleset;
|
public readonly bool IsForCurrentRuleset;
|
||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this);
|
public override ScoreProcessor CreateScoreProcessor() => new ScoreProcessor<TObject>(this);
|
||||||
|
|
||||||
|
@ -41,6 +41,12 @@ namespace osu.Game.Screens.Play.BreaksOverlay
|
|||||||
private readonly InfoContainer info;
|
private readonly InfoContainer info;
|
||||||
private readonly ArrowsOverlay arrowsOverlay;
|
private readonly ArrowsOverlay arrowsOverlay;
|
||||||
|
|
||||||
|
public BreakOverlay(bool letterboxing, ScoreProcessor scoreProcessor)
|
||||||
|
: this(letterboxing)
|
||||||
|
{
|
||||||
|
bindProcessor(scoreProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
public BreakOverlay(bool letterboxing)
|
public BreakOverlay(bool letterboxing)
|
||||||
{
|
{
|
||||||
this.letterboxing = letterboxing;
|
this.letterboxing = letterboxing;
|
||||||
@ -148,7 +154,7 @@ namespace osu.Game.Screens.Play.BreaksOverlay
|
|||||||
arrowsOverlay.Hide();
|
arrowsOverlay.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindProcessor(ScoreProcessor processor)
|
private void bindProcessor(ScoreProcessor processor)
|
||||||
{
|
{
|
||||||
info.AccuracyDisplay.Current.BindTo(processor.Accuracy);
|
info.AccuracyDisplay.Current.BindTo(processor.Accuracy);
|
||||||
info.GradeDisplay.Current.BindTo(processor.Rank);
|
info.GradeDisplay.Current.BindTo(processor.Rank);
|
||||||
|
@ -6,6 +6,8 @@ using osu.Framework.Configuration;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -35,11 +37,11 @@ namespace osu.Game.Screens.Play
|
|||||||
public readonly ReplaySettingsOverlay ReplaySettingsOverlay;
|
public readonly ReplaySettingsOverlay ReplaySettingsOverlay;
|
||||||
|
|
||||||
private Bindable<bool> showHud;
|
private Bindable<bool> showHud;
|
||||||
private bool replayLoaded;
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
private static bool hasShownNotificationOnce;
|
private static bool hasShownNotificationOnce;
|
||||||
|
|
||||||
public HUDOverlay()
|
public HUDOverlay(ScoreProcessor scoreProcessor, RulesetContainer rulesetContainer, DecoupleableInterpolatingFramedClock decoupledClock, WorkingBeatmap working, IAdjustableClock adjustableSourceClock)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
@ -59,6 +61,18 @@ namespace osu.Game.Screens.Play
|
|||||||
ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BindProcessor(scoreProcessor);
|
||||||
|
BindRulesetContainer(rulesetContainer);
|
||||||
|
|
||||||
|
Progress.Objects = rulesetContainer.Objects;
|
||||||
|
Progress.AudioClock = decoupledClock;
|
||||||
|
Progress.AllowSeeking = rulesetContainer.HasReplayLoaded;
|
||||||
|
Progress.OnSeek = pos => decoupledClock.Seek(pos);
|
||||||
|
|
||||||
|
ModDisplay.Current.BindTo(working.Mods);
|
||||||
|
|
||||||
|
ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
@ -91,22 +105,39 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
(rulesetContainer.KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(KeyCounter);
|
base.LoadComplete();
|
||||||
|
|
||||||
replayLoaded = rulesetContainer.HasReplayLoaded;
|
replayLoaded.ValueChanged += replayLoadedValueChanged;
|
||||||
|
replayLoaded.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
ReplaySettingsOverlay.ReplayLoaded = replayLoaded;
|
private void replayLoadedValueChanged(bool loaded)
|
||||||
|
{
|
||||||
|
ReplaySettingsOverlay.ReplayLoaded = loaded;
|
||||||
|
|
||||||
// in the case a replay isn't loaded, we want some elements to only appear briefly.
|
if (loaded)
|
||||||
if (!replayLoaded)
|
{
|
||||||
|
ReplaySettingsOverlay.Show();
|
||||||
|
ModDisplay.FadeIn(200);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ReplaySettingsOverlay.Hide();
|
ReplaySettingsOverlay.Hide();
|
||||||
ModDisplay.Delay(2000).FadeOut(200);
|
ModDisplay.Delay(2000).FadeOut(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void BindRulesetContainer(RulesetContainer rulesetContainer)
|
||||||
|
{
|
||||||
|
(rulesetContainer.KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(KeyCounter);
|
||||||
|
|
||||||
|
replayLoaded.BindTo(rulesetContainer.HasReplayLoaded);
|
||||||
|
|
||||||
|
Progress.BindRulestContainer(rulesetContainer);
|
||||||
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Repeat) return false;
|
if (args.Repeat) return false;
|
||||||
@ -184,7 +215,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay();
|
protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay();
|
||||||
|
|
||||||
public virtual void BindProcessor(ScoreProcessor processor)
|
protected virtual void BindProcessor(ScoreProcessor processor)
|
||||||
{
|
{
|
||||||
ScoreCounter?.Current.BindTo(processor.TotalScore);
|
ScoreCounter?.Current.BindTo(processor.TotalScore);
|
||||||
AccuracyCounter?.Current.BindTo(processor.Accuracy);
|
AccuracyCounter?.Current.BindTo(processor.Accuracy);
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using OpenTK.Input;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
public class HotkeyRetryOverlay : Container
|
public class HotkeyRetryOverlay : Container, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public Action Action;
|
public Action Action;
|
||||||
|
|
||||||
@ -40,28 +40,20 @@ namespace osu.Game.Screens.Play
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
public bool OnPressed(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (args.Repeat) return false;
|
if (action != GlobalAction.QuickRetry) return false;
|
||||||
|
|
||||||
if (args.Key == Key.Tilde)
|
overlay.FadeIn(activate_delay, Easing.Out);
|
||||||
{
|
return true;
|
||||||
overlay.FadeIn(activate_delay, Easing.Out);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyDown(state, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
|
public bool OnReleased(GlobalAction action)
|
||||||
{
|
{
|
||||||
if (args.Key == Key.Tilde && !fired)
|
if (action != GlobalAction.QuickRetry) return false;
|
||||||
{
|
|
||||||
overlay.FadeOut(fadeout_delay, Easing.Out);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnKeyUp(state, args);
|
overlay.FadeOut(fadeout_delay, Easing.Out);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using OpenTK;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Input;
|
|
||||||
using osu.Framework.Logging;
|
|
||||||
using osu.Framework.Screens;
|
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets;
|
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
using osu.Game.Screens.Backgrounds;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Framework.Audio;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Screens.Ranking;
|
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Logging;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.UI;
|
||||||
|
using osu.Game.Screens.Backgrounds;
|
||||||
using osu.Game.Screens.Play.BreaksOverlay;
|
using osu.Game.Screens.Play.BreaksOverlay;
|
||||||
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Storyboards.Drawables;
|
using osu.Game.Storyboards.Drawables;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public int RestartCount;
|
public int RestartCount;
|
||||||
|
|
||||||
public CursorContainer Cursor => RulesetContainer.Cursor;
|
public CursorContainer Cursor => RulesetContainer.Cursor;
|
||||||
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded;
|
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value;
|
||||||
|
|
||||||
private IAdjustableClock adjustableSourceClock;
|
private IAdjustableClock adjustableSourceClock;
|
||||||
private FramedOffsetClock offsetClock;
|
private FramedOffsetClock offsetClock;
|
||||||
@ -79,7 +79,6 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private BreakOverlay breakOverlay;
|
|
||||||
private Container storyboardContainer;
|
private Container storyboardContainer;
|
||||||
private DrawableStoryboard storyboard;
|
private DrawableStoryboard storyboard;
|
||||||
|
|
||||||
@ -155,6 +154,8 @@ namespace osu.Game.Screens.Play
|
|||||||
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
||||||
userAudioOffset.TriggerChange();
|
userAudioOffset.TriggerChange();
|
||||||
|
|
||||||
|
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
storyboardContainer = new Container
|
storyboardContainer = new Container
|
||||||
@ -170,13 +171,12 @@ namespace osu.Game.Screens.Play
|
|||||||
OnRetry = Restart,
|
OnRetry = Restart,
|
||||||
OnQuit = Exit,
|
OnQuit = Exit,
|
||||||
CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded,
|
CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded,
|
||||||
OnPause = () => {
|
OnPause = () =>
|
||||||
|
{
|
||||||
pauseContainer.Retries = RestartCount;
|
pauseContainer.Retries = RestartCount;
|
||||||
hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused;
|
hudOverlay.KeyCounter.IsCounting = pauseContainer.IsPaused;
|
||||||
},
|
},
|
||||||
OnResume = () => {
|
OnResume = () => hudOverlay.KeyCounter.IsCounting = true,
|
||||||
hudOverlay.KeyCounter.IsCounting = true;
|
|
||||||
},
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
@ -186,12 +186,12 @@ namespace osu.Game.Screens.Play
|
|||||||
Child = RulesetContainer,
|
Child = RulesetContainer,
|
||||||
},
|
},
|
||||||
new SkipButton(firstObjectTime) { AudioClock = decoupledClock },
|
new SkipButton(firstObjectTime) { AudioClock = decoupledClock },
|
||||||
hudOverlay = new HUDOverlay
|
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, decoupledClock, working, adjustableSourceClock)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
},
|
},
|
||||||
breakOverlay = new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks)
|
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
@ -207,7 +207,8 @@ namespace osu.Game.Screens.Play
|
|||||||
},
|
},
|
||||||
new HotkeyRetryOverlay
|
new HotkeyRetryOverlay
|
||||||
{
|
{
|
||||||
Action = () => {
|
Action = () =>
|
||||||
|
{
|
||||||
//we want to hide the hitrenderer immediately (looks better).
|
//we want to hide the hitrenderer immediately (looks better).
|
||||||
//we may be able to remove this once the mouse cursor trail is improved.
|
//we may be able to remove this once the mouse cursor trail is improved.
|
||||||
RulesetContainer?.Hide();
|
RulesetContainer?.Hide();
|
||||||
@ -216,25 +217,9 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
|
||||||
|
|
||||||
if (showStoryboard)
|
if (showStoryboard)
|
||||||
initializeStoryboard(false);
|
initializeStoryboard(false);
|
||||||
|
|
||||||
hudOverlay.BindProcessor(scoreProcessor);
|
|
||||||
hudOverlay.BindRulesetContainer(RulesetContainer);
|
|
||||||
|
|
||||||
hudOverlay.Progress.Objects = RulesetContainer.Objects;
|
|
||||||
hudOverlay.Progress.AudioClock = decoupledClock;
|
|
||||||
hudOverlay.Progress.AllowSeeking = RulesetContainer.HasReplayLoaded;
|
|
||||||
hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos);
|
|
||||||
|
|
||||||
hudOverlay.ModDisplay.Current.BindTo(working.Mods);
|
|
||||||
|
|
||||||
breakOverlay.BindProcessor(scoreProcessor);
|
|
||||||
|
|
||||||
hudOverlay.ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
|
||||||
|
|
||||||
// Bind ScoreProcessor to ourselves
|
// Bind ScoreProcessor to ourselves
|
||||||
scoreProcessor.AllJudged += onCompletion;
|
scoreProcessor.AllJudged += onCompletion;
|
||||||
scoreProcessor.Failed += onFail;
|
scoreProcessor.Failed += onFail;
|
||||||
|
@ -9,9 +9,12 @@ using System.Collections.Generic;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
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.UI;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
public class SongProgress : OverlayContainer
|
public class SongProgress : OverlayContainer
|
||||||
@ -54,6 +57,8 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
@ -98,6 +103,14 @@ namespace osu.Game.Screens.Play
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
State = Visibility.Visible;
|
State = Visibility.Visible;
|
||||||
|
|
||||||
|
replayLoaded.ValueChanged += v => AllowSeeking = v;
|
||||||
|
replayLoaded.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BindRulestContainer(RulesetContainer rulesetContainer)
|
||||||
|
{
|
||||||
|
replayLoaded.BindTo(rulesetContainer.HasReplayLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool allowSeeking;
|
private bool allowSeeking;
|
||||||
|
@ -181,7 +181,7 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours)
|
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours)
|
||||||
{
|
{
|
||||||
dependencies.Cache(this);
|
dependencies.CacheAs<SongSelect>(this);
|
||||||
|
|
||||||
if (Footer != null)
|
if (Footer != null)
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,7 @@ using osu.Framework.Platform;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Tournament.Components
|
namespace osu.Game.Screens.Tournament.Components
|
||||||
{
|
{
|
||||||
public class DrawingsConfigManager : ConfigManager<DrawingsConfig>
|
public class DrawingsConfigManager : IniConfigManager<DrawingsConfig>
|
||||||
{
|
{
|
||||||
protected override string Filename => @"drawings.ini";
|
protected override string Filename => @"drawings.ini";
|
||||||
|
|
||||||
|
@ -265,12 +265,19 @@
|
|||||||
<Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" />
|
<Compile Include="Beatmaps\Formats\JsonBeatmapDecoder.cs" />
|
||||||
<Compile Include="Beatmaps\Formats\LegacyDecoder.cs" />
|
<Compile Include="Beatmaps\Formats\LegacyDecoder.cs" />
|
||||||
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
|
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoder.cs" />
|
||||||
|
<Compile Include="Configuration\DatabasedSetting.cs" />
|
||||||
|
<Compile Include="Configuration\SettingsStore.cs" />
|
||||||
|
<Compile Include="Configuration\DatabasedConfigManager.cs" />
|
||||||
<Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
|
<Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
|
||||||
<Compile Include="Database\DatabaseContextFactory.cs" />
|
<Compile Include="Database\DatabaseContextFactory.cs" />
|
||||||
<Compile Include="Database\IHasPrimaryKey.cs" />
|
<Compile Include="Database\IHasPrimaryKey.cs" />
|
||||||
<Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
|
<Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
|
||||||
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
|
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
||||||
|
<Compile Include="Migrations\20180125143340_Settings.cs" />
|
||||||
|
<Compile Include="Migrations\20180125143340_Settings.designer.cs">
|
||||||
|
<DependentUpon>20180125143340_Settings.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Overlays\Profile\SupporterIcon.cs" />
|
<Compile Include="Overlays\Profile\SupporterIcon.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetFriendsRequest.cs" />
|
<Compile Include="Online\API\Requests\GetFriendsRequest.cs" />
|
||||||
<Compile Include="Overlays\Settings\DangerousSettingsButton.cs" />
|
<Compile Include="Overlays\Settings\DangerousSettingsButton.cs" />
|
||||||
@ -318,6 +325,8 @@
|
|||||||
<Compile Include="Overlays\Profile\Sections\Ranks\ScoreModsContainer.cs" />
|
<Compile Include="Overlays\Profile\Sections\Ranks\ScoreModsContainer.cs" />
|
||||||
<Compile Include="Overlays\Settings\Sections\Gameplay\ScrollingSettings.cs" />
|
<Compile Include="Overlays\Settings\Sections\Gameplay\ScrollingSettings.cs" />
|
||||||
<Compile Include="Overlays\Settings\Sections\Maintenance\DeleteAllBeatmapsDialog.cs" />
|
<Compile Include="Overlays\Settings\Sections\Maintenance\DeleteAllBeatmapsDialog.cs" />
|
||||||
|
<Compile Include="Rulesets\Configuration\IRulesetConfigManager.cs" />
|
||||||
|
<Compile Include="Rulesets\Configuration\RulesetConfigManager.cs" />
|
||||||
<Compile Include="Rulesets\Mods\IApplicableFailOverride.cs" />
|
<Compile Include="Rulesets\Mods\IApplicableFailOverride.cs" />
|
||||||
<Compile Include="Rulesets\Mods\IApplicableMod.cs" />
|
<Compile Include="Rulesets\Mods\IApplicableMod.cs" />
|
||||||
<Compile Include="Rulesets\Mods\IApplicableToBeatmapConverter.cs" />
|
<Compile Include="Rulesets\Mods\IApplicableToBeatmapConverter.cs" />
|
||||||
|
@ -12,12 +12,12 @@
|
|||||||
<description>click the circles. to the beat.</description>
|
<description>click the circles. to the beat.</description>
|
||||||
<summary>click the circles.</summary>
|
<summary>click the circles.</summary>
|
||||||
<releaseNotes>testing</releaseNotes>
|
<releaseNotes>testing</releaseNotes>
|
||||||
<copyright>Copyright ppy Pty Ltd 2007-2017</copyright>
|
<copyright>Copyright ppy Pty Ltd 2007-2018</copyright>
|
||||||
<language>en-AU</language>
|
<language>en-AU</language>
|
||||||
</metadata>
|
</metadata>
|
||||||
<files>
|
<files>
|
||||||
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/>
|
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/>
|
||||||
<file src="*.dll" target="lib\net45\"/>
|
<file src="*.dll" target="lib\net45\"/>
|
||||||
<file src="*.config" target="lib\net45\"/>
|
<file src="*.config" target="lib\net45\"/>
|
||||||
<file src="x86\*.dll" target="lib\net45\x86\"/>
|
<file src="x86\*.dll" target="lib\net45\x86\"/>
|
||||||
<file src="x64\*.dll" target="lib\net45\x64\"/>
|
<file src="x64\*.dll" target="lib\net45\x64\"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user