mirror of
https://github.com/ppy/osu.git
synced 2025-02-21 20:53:04 +08:00
Merge remote-tracking branch 'origin/master' into editor-timeline-rework
This commit is contained in:
commit
1dfa3ff995
@ -84,10 +84,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
foreach (ManiaHitObject obj in objects)
|
foreach (ManiaHitObject obj in objects)
|
||||||
{
|
|
||||||
obj.HitWindows = original.HitWindows;
|
|
||||||
yield return obj;
|
yield return obj;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<double> prevNoteTimes = new List<double>(max_notes_for_density);
|
private readonly List<double> prevNoteTimes = new List<double>(max_notes_for_density);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
@ -49,18 +50,17 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
|
|
||||||
int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7;
|
int columnCount = (Beatmap as ManiaBeatmap)?.TotalColumns ?? 7;
|
||||||
|
|
||||||
foreach (var hitObject in Beatmap.HitObjects)
|
|
||||||
difficultyHitObjects.Add(new ManiaHitObjectDifficulty((ManiaHitObject)hitObject, columnCount));
|
|
||||||
|
|
||||||
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
|
// Sort DifficultyHitObjects by StartTime of the HitObjects - just to make sure.
|
||||||
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
|
// Note: Stable sort is done so that the ordering of hitobjects with equal start times doesn't change
|
||||||
|
difficultyHitObjects.AddRange(Beatmap.HitObjects.Select(h => new ManiaHitObjectDifficulty((ManiaHitObject)h, columnCount)).OrderBy(h => h.BaseHitObject.StartTime));
|
||||||
|
|
||||||
if (!calculateStrainValues())
|
if (!calculateStrainValues())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
double starRating = calculateDifficulty() * star_scaling_factor;
|
double starRating = calculateDifficulty() * star_scaling_factor;
|
||||||
|
|
||||||
categoryDifficulty?.Add("Strain", starRating);
|
if (categoryDifficulty != null)
|
||||||
|
categoryDifficulty["Strain"] = starRating;
|
||||||
|
|
||||||
return starRating;
|
return starRating;
|
||||||
}
|
}
|
||||||
|
126
osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
Normal file
126
osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// 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.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
|
{
|
||||||
|
public class ManiaPerformanceCalculator : PerformanceCalculator
|
||||||
|
{
|
||||||
|
private Mod[] mods;
|
||||||
|
|
||||||
|
// Score after being scaled by non-difficulty-increasing mods
|
||||||
|
private double scaledScore;
|
||||||
|
|
||||||
|
private int countPerfect;
|
||||||
|
private int countGreat;
|
||||||
|
private int countGood;
|
||||||
|
private int countOk;
|
||||||
|
private int countMeh;
|
||||||
|
private int countMiss;
|
||||||
|
|
||||||
|
public ManiaPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||||
|
: base(ruleset, beatmap, score)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
|
{
|
||||||
|
mods = Score.Mods;
|
||||||
|
scaledScore = Score.TotalScore;
|
||||||
|
countPerfect = Convert.ToInt32(Score.Statistics[HitResult.Perfect]);
|
||||||
|
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||||
|
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||||
|
countOk = Convert.ToInt32(Score.Statistics[HitResult.Ok]);
|
||||||
|
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||||
|
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||||
|
|
||||||
|
if (mods.Any(m => !m.Ranked))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IEnumerable<Mod> scoreIncreaseMods = Ruleset.GetModsFor(ModType.DifficultyIncrease);
|
||||||
|
|
||||||
|
double scoreMultiplier = 1.0;
|
||||||
|
foreach (var m in mods.Where(m => !scoreIncreaseMods.Contains(m)))
|
||||||
|
scoreMultiplier *= m.ScoreMultiplier;
|
||||||
|
|
||||||
|
// Scale score up, so it's comparable to other keymods
|
||||||
|
scaledScore *= 1.0 / scoreMultiplier;
|
||||||
|
|
||||||
|
// Arbitrary initial value for scaling pp in order to standardize distributions across game modes.
|
||||||
|
// The specific number has no intrinsic meaning and can be adjusted as needed.
|
||||||
|
double multiplier = 0.8;
|
||||||
|
|
||||||
|
if (mods.Any(m => m is ModNoFail))
|
||||||
|
multiplier *= 0.9;
|
||||||
|
if (mods.Any(m => m is ModEasy))
|
||||||
|
multiplier *= 0.5;
|
||||||
|
|
||||||
|
double strainValue = computeStrainValue();
|
||||||
|
double accValue = computeAccuracyValue(strainValue);
|
||||||
|
double totalValue =
|
||||||
|
Math.Pow(
|
||||||
|
Math.Pow(strainValue, 1.1) +
|
||||||
|
Math.Pow(accValue, 1.1), 1.0 / 1.1
|
||||||
|
) * multiplier;
|
||||||
|
|
||||||
|
if (categoryDifficulty != null)
|
||||||
|
{
|
||||||
|
categoryDifficulty["Strain"] = strainValue;
|
||||||
|
categoryDifficulty["Accuracy"] = accValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeStrainValue()
|
||||||
|
{
|
||||||
|
// Obtain strain difficulty
|
||||||
|
double strainValue = Math.Pow(5 * Math.Max(1, Attributes["Strain"] / 0.2) - 4.0, 2.2) / 135.0;
|
||||||
|
|
||||||
|
// Longer maps are worth more
|
||||||
|
strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
|
||||||
|
|
||||||
|
if (scaledScore <= 500000)
|
||||||
|
strainValue = 0;
|
||||||
|
else if (scaledScore <= 600000)
|
||||||
|
strainValue *= (scaledScore - 500000) / 100000 * 0.3;
|
||||||
|
else if (scaledScore <= 700000)
|
||||||
|
strainValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
|
||||||
|
else if (scaledScore <= 800000)
|
||||||
|
strainValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
|
||||||
|
else if (scaledScore <= 900000)
|
||||||
|
strainValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
|
||||||
|
else
|
||||||
|
strainValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
|
||||||
|
|
||||||
|
return strainValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeAccuracyValue(double strainValue)
|
||||||
|
{
|
||||||
|
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
|
||||||
|
if (hitWindowGreat <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Lots of arbitrary values from testing.
|
||||||
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||||
|
double accuracyValue = Math.Max(0.0, 0.2 - (hitWindowGreat - 34) * 0.006667)
|
||||||
|
* strainValue
|
||||||
|
* Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
|
||||||
|
|
||||||
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||||
|
// accuracyValue *= Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
||||||
|
|
||||||
|
return accuracyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double totalHits => countPerfect + countOk + countGreat + countGood + countMeh + countMiss;
|
||||||
|
}
|
||||||
|
}
|
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
Normal file
13
osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// 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.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
|
{
|
||||||
|
public class HoldNoteJudgement : ManiaJudgement
|
||||||
|
{
|
||||||
|
public override bool AffectsCombo => false;
|
||||||
|
protected override int NumericResultFor(HitResult result) => 0;
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ using osu.Game.Beatmaps.Legacy;
|
|||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Difficulty;
|
using osu.Game.Rulesets.Mania.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
{
|
{
|
||||||
@ -25,6 +26,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
{
|
{
|
||||||
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap);
|
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new ManiaRulesetContainer(this, beatmap);
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap);
|
||||||
|
public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
|
||||||
{
|
{
|
||||||
|
@ -99,6 +99,19 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected override void UpdateState(ArmedState state)
|
protected override void UpdateState(ArmedState state)
|
||||||
{
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case ArmedState.Hit:
|
||||||
|
// Good enough for now, we just want them to have a lifetime end
|
||||||
|
this.Delay(2000).Expire();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
if (tail.AllJudged)
|
||||||
|
AddJudgement(new HoldNoteJudgement { Result = HitResult.Perfect });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -191,6 +204,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private class DrawableTailNote : DrawableNote
|
private class DrawableTailNote : DrawableNote
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Lenience of release hit windows. This is to make cases where the hold note release
|
||||||
|
/// is timed alongside presses of other hit objects less awkward.
|
||||||
|
/// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps
|
||||||
|
/// </summary>
|
||||||
|
private const double release_window_lenience = 1.5;
|
||||||
|
|
||||||
private readonly DrawableHoldNote holdNote;
|
private readonly DrawableHoldNote holdNote;
|
||||||
|
|
||||||
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action)
|
||||||
@ -203,6 +223,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
|
// Factor in the release lenience
|
||||||
|
timeOffset /= release_window_lenience;
|
||||||
|
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
if (!HitObject.HitWindows.CanBeHit(timeOffset))
|
||||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The tail note of the hold.
|
/// The tail note of the hold.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Note Tail = new TailNote();
|
public readonly Note Tail = new Note();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time between ticks of this hold.
|
/// The time between ticks of this hold.
|
||||||
@ -94,25 +94,5 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The tail of the hold note.
|
|
||||||
/// </summary>
|
|
||||||
private class TailNote : Note
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Lenience of release hit windows. This is to make cases where the hold note release
|
|
||||||
/// is timed alongside presses of other hit objects less awkward.
|
|
||||||
/// Todo: This shouldn't exist for non-LegacyBeatmapDecoder beatmaps
|
|
||||||
/// </summary>
|
|
||||||
private const double release_window_lenience = 1.5;
|
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
|
||||||
{
|
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
|
||||||
|
|
||||||
HitWindows *= release_window_lenience;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +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 osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
|
||||||
using osu.Game.Rulesets.Mania.Objects.Types;
|
using osu.Game.Rulesets.Mania.Objects.Types;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
@ -12,12 +10,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
|||||||
{
|
{
|
||||||
public virtual int Column { get; set; }
|
public virtual int Column { get; set; }
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
||||||
{
|
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
|
||||||
|
|
||||||
HitWindows.AllowsPerfect = true;
|
|
||||||
HitWindows.AllowsOk = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
namespace osu.Game.Rulesets.Mania.Objects
|
||||||
{
|
{
|
||||||
public class ConvertHitWindows : HitWindows
|
public class ManiaHitWindows : HitWindows
|
||||||
{
|
{
|
||||||
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
{
|
{
|
||||||
@ -21,6 +22,9 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
|
|
||||||
public override void SetDifficulty(double difficulty)
|
public override void SetDifficulty(double difficulty)
|
||||||
{
|
{
|
||||||
|
AllowsPerfect = true;
|
||||||
|
AllowsOk = true;
|
||||||
|
|
||||||
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
Perfect = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Perfect]);
|
||||||
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
Great = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Great]);
|
||||||
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
Good = BeatmapDifficulty.DifficultyRange(difficulty, base_ranges[HitResult.Good]);
|
@ -40,8 +40,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
RepeatSamples = curveData.RepeatSamples,
|
RepeatSamples = curveData.RepeatSamples,
|
||||||
RepeatCount = curveData.RepeatCount,
|
RepeatCount = curveData.RepeatCount,
|
||||||
Position = positionData?.Position ?? Vector2.Zero,
|
Position = positionData?.Position ?? Vector2.Zero,
|
||||||
NewCombo = comboData?.NewCombo ?? false,
|
NewCombo = comboData?.NewCombo ?? false
|
||||||
HitWindows = original.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (endTimeData != null)
|
else if (endTimeData != null)
|
||||||
@ -51,8 +50,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
Samples = original.Samples,
|
Samples = original.Samples,
|
||||||
EndTime = endTimeData.EndTime,
|
EndTime = endTimeData.EndTime,
|
||||||
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2,
|
Position = positionData?.Position ?? OsuPlayfield.BASE_SIZE / 2
|
||||||
HitWindows = original.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -62,8 +60,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
|||||||
StartTime = original.StartTime,
|
StartTime = original.StartTime,
|
||||||
Samples = original.Samples,
|
Samples = original.Samples,
|
||||||
Position = positionData?.Position ?? Vector2.Zero,
|
Position = positionData?.Position ?? Vector2.Zero,
|
||||||
NewCombo = comboData?.NewCombo ?? false,
|
NewCombo = comboData?.NewCombo ?? false
|
||||||
HitWindows = original.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ using osu.Game.Rulesets.Osu.Mods;
|
|||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuPerformanceCalculator : PerformanceCalculator
|
public class OsuPerformanceCalculator : PerformanceCalculator
|
||||||
{
|
{
|
@ -71,5 +71,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OffsetPosition(Vector2 offset) => Position += offset;
|
public virtual void OffsetPosition(Vector2 offset) => Position += offset;
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new OsuHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public class ConvertHitWindows : HitWindows
|
public class OsuHitWindows : HitWindows
|
||||||
{
|
{
|
||||||
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
{
|
{
|
@ -12,7 +12,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit;
|
using osu.Game.Rulesets.Osu.Edit;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Osu.Replays;
|
using osu.Game.Rulesets.Osu.Replays;
|
||||||
|
@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko";
|
||||||
|
|
||||||
[NonParallelizable]
|
[NonParallelizable]
|
||||||
[TestCase("basic", false), Ignore("See: https://github.com/ppy/osu/issues/2152")]
|
[TestCase("basic")]
|
||||||
[TestCase("slider-generating-drumroll", false)]
|
[TestCase("slider-generating-drumroll")]
|
||||||
public new void Test(string name)
|
public new void Test(string name)
|
||||||
{
|
{
|
||||||
base.Test(name);
|
base.Test(name);
|
||||||
|
@ -8,7 +8,6 @@ using osu.Game.Rulesets.Taiko.Objects;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.IO.Serialization;
|
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
|
||||||
@ -51,8 +50,9 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
protected override Beatmap<TaikoHitObject> ConvertBeatmap(IBeatmap original)
|
protected override Beatmap<TaikoHitObject> ConvertBeatmap(IBeatmap original)
|
||||||
{
|
{
|
||||||
// Rewrite the beatmap info to add the slider velocity multiplier
|
// Rewrite the beatmap info to add the slider velocity multiplier
|
||||||
BeatmapInfo info = original.BeatmapInfo.DeepClone();
|
original.BeatmapInfo = original.BeatmapInfo.Clone();
|
||||||
info.BaseDifficulty.SliderMultiplier *= legacy_velocity_multiplier;
|
original.BeatmapInfo.BaseDifficulty = original.BeatmapInfo.BaseDifficulty.Clone();
|
||||||
|
original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= legacy_velocity_multiplier;
|
||||||
|
|
||||||
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
|
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
|
||||||
|
|
||||||
@ -98,12 +98,12 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
double distance = distanceData.Distance * spans * 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 / speedAdjustedBeatLength;
|
||||||
// The duration of the taiko hit object
|
// The duration of the taiko hit object
|
||||||
double taikoDuration = distance / taikoVelocity;
|
double taikoDuration = distance / taikoVelocity;
|
||||||
|
|
||||||
// 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 * legacy_velocity_multiplier / speedAdjustedBeatLength;
|
double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / speedAdjustedBeatLength;
|
||||||
// The duration of the osu! hit object
|
// The duration of the osu! hit object
|
||||||
double osuDuration = distance / osuVelocity;
|
double osuDuration = distance / osuVelocity;
|
||||||
|
|
||||||
@ -132,8 +132,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
StartTime = j,
|
StartTime = j,
|
||||||
Samples = currentSamples,
|
Samples = currentSamples,
|
||||||
IsStrong = strong,
|
IsStrong = strong
|
||||||
HitWindows = obj.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -142,8 +141,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
StartTime = j,
|
StartTime = j,
|
||||||
Samples = currentSamples,
|
Samples = currentSamples,
|
||||||
IsStrong = strong,
|
IsStrong = strong
|
||||||
HitWindows = obj.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,8 +156,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
Duration = taikoDuration,
|
Duration = taikoDuration,
|
||||||
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4,
|
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4
|
||||||
HitWindows = obj.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,8 +170,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
IsStrong = strong,
|
||||||
Duration = endTimeData.Duration,
|
Duration = endTimeData.Duration,
|
||||||
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier),
|
RequiredHits = (int)Math.Max(1, endTimeData.Duration / 1000 * hitMultiplier)
|
||||||
HitWindows = obj.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -187,8 +183,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
IsStrong = strong
|
||||||
HitWindows = obj.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -197,8 +192,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
IsStrong = strong
|
||||||
HitWindows = obj.HitWindows
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Difficulty
|
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||||
@ -35,6 +36,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TaikoDifficultyCalculator(IBeatmap beatmap, Mod[] mods)
|
||||||
|
: base(beatmap, mods)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
{
|
{
|
||||||
// Fill our custom DifficultyHitObject class, that carries additional information
|
// Fill our custom DifficultyHitObject class, that carries additional information
|
||||||
@ -51,10 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
double starRating = calculateDifficulty() * star_scaling_factor;
|
double starRating = calculateDifficulty() * star_scaling_factor;
|
||||||
|
|
||||||
if (categoryDifficulty != null)
|
if (categoryDifficulty != null)
|
||||||
{
|
categoryDifficulty["Strain"] = starRating;
|
||||||
categoryDifficulty.Add("Strain", starRating);
|
|
||||||
categoryDifficulty.Add("Hit window 300", 35 /*HitObjectManager.HitWindow300*/ / TimeRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return starRating;
|
return starRating;
|
||||||
}
|
}
|
||||||
|
111
osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
Normal file
111
osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// 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.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||||
|
{
|
||||||
|
public class TaikoPerformanceCalculator : PerformanceCalculator
|
||||||
|
{
|
||||||
|
private readonly int beatmapMaxCombo;
|
||||||
|
|
||||||
|
private Mod[] mods;
|
||||||
|
private int countGreat;
|
||||||
|
private int countGood;
|
||||||
|
private int countMeh;
|
||||||
|
private int countMiss;
|
||||||
|
|
||||||
|
public TaikoPerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||||
|
: base(ruleset, beatmap, score)
|
||||||
|
{
|
||||||
|
beatmapMaxCombo = beatmap.HitObjects.Count(h => h is Hit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double Calculate(Dictionary<string, double> categoryDifficulty = null)
|
||||||
|
{
|
||||||
|
mods = Score.Mods;
|
||||||
|
countGreat = Convert.ToInt32(Score.Statistics[HitResult.Great]);
|
||||||
|
countGood = Convert.ToInt32(Score.Statistics[HitResult.Good]);
|
||||||
|
countMeh = Convert.ToInt32(Score.Statistics[HitResult.Meh]);
|
||||||
|
countMiss = Convert.ToInt32(Score.Statistics[HitResult.Miss]);
|
||||||
|
|
||||||
|
// Don't count scores made with supposedly unranked mods
|
||||||
|
if (mods.Any(m => !m.Ranked))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Custom multipliers for NoFail and SpunOut.
|
||||||
|
double multiplier = 1.1; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
|
||||||
|
|
||||||
|
if (mods.Any(m => m is ModNoFail))
|
||||||
|
multiplier *= 0.90;
|
||||||
|
|
||||||
|
if (mods.Any(m => m is ModHidden))
|
||||||
|
multiplier *= 1.10;
|
||||||
|
|
||||||
|
double strainValue = computeStrainValue();
|
||||||
|
double accuracyValue = computeAccuracyValue();
|
||||||
|
double totalValue =
|
||||||
|
Math.Pow(
|
||||||
|
Math.Pow(strainValue, 1.1) +
|
||||||
|
Math.Pow(accuracyValue, 1.1), 1.0 / 1.1
|
||||||
|
) * multiplier;
|
||||||
|
|
||||||
|
if (categoryDifficulty != null)
|
||||||
|
{
|
||||||
|
categoryDifficulty["Strain"] = strainValue;
|
||||||
|
categoryDifficulty["Accuracy"] = accuracyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeStrainValue()
|
||||||
|
{
|
||||||
|
double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes["Strain"] / 0.0075) - 4.0, 2.0) / 100000.0;
|
||||||
|
|
||||||
|
// Longer maps are worth more
|
||||||
|
double lengthBonus = 1 + 0.1f * Math.Min(1.0, totalHits / 1500.0);
|
||||||
|
strainValue *= lengthBonus;
|
||||||
|
|
||||||
|
// Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
|
||||||
|
strainValue *= Math.Pow(0.985, countMiss);
|
||||||
|
|
||||||
|
// Combo scaling
|
||||||
|
if (beatmapMaxCombo > 0)
|
||||||
|
strainValue *= Math.Min(Math.Pow(Score.MaxCombo, 0.5) / Math.Pow(beatmapMaxCombo, 0.5), 1.0);
|
||||||
|
|
||||||
|
if (mods.Any(m => m is ModHidden))
|
||||||
|
strainValue *= 1.025;
|
||||||
|
|
||||||
|
if (mods.Any(m => m is ModFlashlight))
|
||||||
|
// Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
|
||||||
|
strainValue *= 1.05 * lengthBonus;
|
||||||
|
|
||||||
|
// Scale the speed value with accuracy _slightly_
|
||||||
|
return strainValue * Score.Accuracy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeAccuracyValue()
|
||||||
|
{
|
||||||
|
double hitWindowGreat = (Beatmap.HitObjects.First().HitWindows.Great / 2 - 0.5) / TimeRate;
|
||||||
|
if (hitWindowGreat <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Lots of arbitrary values from testing.
|
||||||
|
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
|
||||||
|
double accValue = Math.Pow(150.0 / hitWindowGreat, 1.1) * Math.Pow(Score.Accuracy, 15) * 22.0;
|
||||||
|
|
||||||
|
// Bonus for many hitcircles - it's harder to keep good accuracy up for longer
|
||||||
|
return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int totalHits => countGreat + countGood + countMeh + countMiss;
|
||||||
|
}
|
||||||
|
}
|
@ -27,5 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
/// Strong hit objects give more points for hitting the hit object with both keys.
|
/// Strong hit objects give more points for hitting the hit object with both keys.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsStrong;
|
public bool IsStrong;
|
||||||
|
|
||||||
|
protected override HitWindows CreateHitWindows() => new TaikoHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
namespace osu.Game.Rulesets.Taiko.Objects
|
||||||
{
|
{
|
||||||
public class ConvertHitWindows : HitWindows
|
public class TaikoHitWindows : HitWindows
|
||||||
{
|
{
|
||||||
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
private static readonly IReadOnlyDictionary<HitResult, (double od0, double od5, double od10)> base_ranges = new Dictionary<HitResult, (double, double, double)>
|
||||||
{
|
{
|
@ -14,6 +14,7 @@ using osu.Game.Rulesets.Replays.Types;
|
|||||||
using osu.Game.Rulesets.Taiko.Replays;
|
using osu.Game.Rulesets.Taiko.Replays;
|
||||||
using osu.Game.Beatmaps.Legacy;
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Beatmaps;
|
using osu.Game.Rulesets.Taiko.Beatmaps;
|
||||||
using osu.Game.Rulesets.Taiko.Difficulty;
|
using osu.Game.Rulesets.Taiko.Difficulty;
|
||||||
|
|
||||||
@ -144,7 +145,9 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
|
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
|
||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IBeatmap beatmap, Mod[] mods = null) => new TaikoDifficultyCalculator(beatmap, mods);
|
||||||
|
|
||||||
|
public override PerformanceCalculator CreatePerformanceCalculator(IBeatmap beatmap, Score score) => new TaikoPerformanceCalculator(this, beatmap, score);
|
||||||
|
|
||||||
public override int? LegacyID => 1;
|
public override int? LegacyID => 1;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Multi.Components;
|
using osu.Game.Screens.Multi.Components;
|
||||||
@ -111,6 +112,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddStep(@"select", () => first.State = SelectionState.Selected);
|
||||||
AddStep(@"change title", () => first.Room.Name.Value = @"I Changed Name");
|
AddStep(@"change title", () => first.Room.Name.Value = @"I Changed Name");
|
||||||
AddStep(@"change host", () => first.Room.Host.Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } });
|
AddStep(@"change host", () => first.Room.Host.Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } });
|
||||||
AddStep(@"change status", () => first.Room.Status.Value = new RoomStatusPlaying());
|
AddStep(@"change status", () => first.Room.Status.Value = new RoomStatusPlaying());
|
||||||
@ -121,6 +123,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
new User { Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 1254 } } },
|
new User { Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 1254 } } },
|
||||||
new User { Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 123189 } } },
|
new User { Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 123189 } } },
|
||||||
});
|
});
|
||||||
|
AddStep(@"deselect", () => first.State = SelectionState.NotSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
27
osu.Game.Tests/Visual/TestCaseMultiHeader.cs
Normal file
27
osu.Game.Tests/Visual/TestCaseMultiHeader.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Screens.Multi;
|
||||||
|
using osu.Game.Screens.Multi.Screens;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestCaseMultiHeader : OsuTestCase
|
||||||
|
{
|
||||||
|
public TestCaseMultiHeader()
|
||||||
|
{
|
||||||
|
Lobby lobby;
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
lobby = new Lobby
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding { Top = Header.HEIGHT },
|
||||||
|
},
|
||||||
|
new Header(lobby),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
osu.Game.Tests/Visual/TestCaseMultiScreen.cs
Normal file
21
osu.Game.Tests/Visual/TestCaseMultiScreen.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 NUnit.Framework;
|
||||||
|
using osu.Game.Screens.Multi;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestCaseMultiScreen : OsuTestCase
|
||||||
|
{
|
||||||
|
public TestCaseMultiScreen()
|
||||||
|
{
|
||||||
|
Multiplayer multi = new Multiplayer();
|
||||||
|
|
||||||
|
AddStep(@"show", () => Add(multi));
|
||||||
|
AddWaitStep(5);
|
||||||
|
AddStep(@"exit", multi.Exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
var room = new Room
|
Room room = new Room
|
||||||
{
|
{
|
||||||
Name = { Value = @"My Awesome Room" },
|
Name = { Value = @"My Awesome Room" },
|
||||||
Host = { Value = new User { Username = @"flyte", Id = 3103765, Country = new Country { FlagName = @"JP" } } },
|
Host = { Value = new User { Username = @"flyte", Id = 3103765, Country = new Country { FlagName = @"JP" } } },
|
||||||
@ -71,9 +71,13 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Room = room,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 0.5f,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddStep(@"set room", () => inspector.Room = room);
|
||||||
|
AddStep(@"null room", () => inspector.Room = null);
|
||||||
|
AddStep(@"set room", () => inspector.Room = room);
|
||||||
AddStep(@"change title", () => room.Name.Value = @"A Better Room Than The Above");
|
AddStep(@"change title", () => room.Name.Value = @"A Better Room Than The Above");
|
||||||
AddStep(@"change host", () => room.Host.Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } });
|
AddStep(@"change host", () => room.Host.Value = new User { Username = @"DrabWeb", Id = 6946022, Country = new Country { FlagName = @"CA" } });
|
||||||
AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying());
|
AddStep(@"change status", () => room.Status.Value = new RoomStatusPlaying());
|
||||||
@ -88,7 +92,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
AddStep(@"change room", () =>
|
AddStep(@"change room", () =>
|
||||||
{
|
{
|
||||||
var newRoom = new Room
|
Room newRoom = new Room
|
||||||
{
|
{
|
||||||
Name = { Value = @"My New, Better Than Ever Room" },
|
Name = { Value = @"My New, Better Than Ever Room" },
|
||||||
Host = { Value = new User { Username = @"Angelsim", Id = 1777162, Country = new Country { FlagName = @"KR" } } },
|
Host = { Value = new User { Username = @"Angelsim", Id = 1777162, Country = new Country { FlagName = @"KR" } } },
|
||||||
|
145
osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs
Normal file
145
osu.Game.Tests/Visual/TestCaseScreenBreadcrumbControl.cs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Screens;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestCaseScreenBreadcrumbControl : OsuTestCase
|
||||||
|
{
|
||||||
|
private readonly ScreenBreadcrumbControl breadcrumbs;
|
||||||
|
private Screen currentScreen, changedScreen;
|
||||||
|
|
||||||
|
public TestCaseScreenBreadcrumbControl()
|
||||||
|
{
|
||||||
|
TestScreen startScreen;
|
||||||
|
OsuSpriteText titleText;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
currentScreen = startScreen = new TestScreenOne(),
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
breadcrumbs = new ScreenBreadcrumbControl(startScreen)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
},
|
||||||
|
titleText = new OsuSpriteText(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
breadcrumbs.Current.ValueChanged += s =>
|
||||||
|
{
|
||||||
|
titleText.Text = $"Changed to {s.ToString()}";
|
||||||
|
changedScreen = s;
|
||||||
|
};
|
||||||
|
|
||||||
|
breadcrumbs.Current.TriggerChange();
|
||||||
|
|
||||||
|
assertCurrent();
|
||||||
|
pushNext();
|
||||||
|
assertCurrent();
|
||||||
|
pushNext();
|
||||||
|
assertCurrent();
|
||||||
|
|
||||||
|
AddStep(@"make start current", () =>
|
||||||
|
{
|
||||||
|
startScreen.MakeCurrent();
|
||||||
|
currentScreen = startScreen;
|
||||||
|
});
|
||||||
|
|
||||||
|
assertCurrent();
|
||||||
|
pushNext();
|
||||||
|
AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2);
|
||||||
|
AddStep(@"exit current", () => changedScreen.Exit());
|
||||||
|
AddAssert(@"current screen is first", () => startScreen == changedScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
breadcrumbs.StripColour = colours.Blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pushNext() => AddStep(@"push next screen", () => currentScreen = ((TestScreen)currentScreen).PushNext());
|
||||||
|
private void assertCurrent() => AddAssert(@"changedScreen correct", () => currentScreen == changedScreen);
|
||||||
|
|
||||||
|
private abstract class TestScreen : OsuScreen
|
||||||
|
{
|
||||||
|
protected abstract string Title { get; }
|
||||||
|
protected abstract string NextTitle { get; }
|
||||||
|
protected abstract TestScreen CreateNextScreen();
|
||||||
|
|
||||||
|
public override string ToString() => Title;
|
||||||
|
|
||||||
|
public TestScreen PushNext()
|
||||||
|
{
|
||||||
|
TestScreen screen = CreateNextScreen();
|
||||||
|
Push(screen);
|
||||||
|
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TestScreen()
|
||||||
|
{
|
||||||
|
Child = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Text = Title,
|
||||||
|
},
|
||||||
|
new TriangleButton
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Width = 100,
|
||||||
|
Text = $"Push {NextTitle}",
|
||||||
|
Action = () => PushNext(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestScreenOne : TestScreen
|
||||||
|
{
|
||||||
|
protected override string Title => @"Screen One";
|
||||||
|
protected override string NextTitle => @"Two";
|
||||||
|
protected override TestScreen CreateNextScreen() => new TestScreenTwo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestScreenTwo : TestScreen
|
||||||
|
{
|
||||||
|
protected override string Title => @"Screen Two";
|
||||||
|
protected override string NextTitle => @"One";
|
||||||
|
protected override TestScreen CreateNextScreen() => new TestScreenOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.IO.Serialization;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Game.IO.Serialization.Converters;
|
using osu.Game.IO.Serialization.Converters;
|
||||||
|
|
||||||
@ -55,17 +54,11 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
IBeatmap IBeatmap.Clone() => Clone();
|
IBeatmap IBeatmap.Clone() => Clone();
|
||||||
|
|
||||||
public Beatmap<T> Clone()
|
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();
|
||||||
{
|
|
||||||
var newInstance = (Beatmap<T>)MemberwiseClone();
|
|
||||||
newInstance.BeatmapInfo = BeatmapInfo.DeepClone();
|
|
||||||
|
|
||||||
return newInstance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Beatmap : Beatmap<HitObject>
|
public class Beatmap : Beatmap<HitObject>
|
||||||
{
|
{
|
||||||
public Beatmap Clone() => (Beatmap)base.Clone();
|
public new Beatmap Clone() => (Beatmap)base.Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,6 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
var beatmap = CreateBeatmap();
|
var beatmap = CreateBeatmap();
|
||||||
|
|
||||||
// todo: this *must* share logic (or directly use) Beatmap<T>'s constructor.
|
|
||||||
// right now this isn't easily possible due to generic entanglement.
|
|
||||||
beatmap.BeatmapInfo = original.BeatmapInfo;
|
beatmap.BeatmapInfo = original.BeatmapInfo;
|
||||||
beatmap.ControlPointInfo = original.ControlPointInfo;
|
beatmap.ControlPointInfo = original.ControlPointInfo;
|
||||||
beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList();
|
beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList();
|
||||||
|
@ -32,6 +32,11 @@ namespace osu.Game.Beatmaps
|
|||||||
public double SliderMultiplier { get; set; } = 1;
|
public double SliderMultiplier { get; set; } = 1;
|
||||||
public double SliderTickRate { get; set; } = 1;
|
public double SliderTickRate { get; set; } = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a shallow-clone of this <see cref="BeatmapDifficulty"/>.
|
||||||
|
/// </summary>
|
||||||
|
public BeatmapDifficulty Clone() => (BeatmapDifficulty)MemberwiseClone();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a difficulty value [0, 10] to a two-piece linear range of values.
|
/// Maps a difficulty value [0, 10] to a two-piece linear range of values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -143,5 +143,10 @@ namespace osu.Game.Beatmaps
|
|||||||
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
public bool BackgroundEquals(BeatmapInfo other) => other != null && BeatmapSet != null && other.BeatmapSet != null &&
|
||||||
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
BeatmapSet.Hash == other.BeatmapSet.Hash &&
|
||||||
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
(Metadata ?? BeatmapSet.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSet.Metadata).BackgroundFile;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a shallow-clone of this <see cref="BeatmapInfo"/>.
|
||||||
|
/// </summary>
|
||||||
|
public BeatmapInfo Clone() => (BeatmapInfo)MemberwiseClone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,11 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
|
|
||||||
base.ParseStreamInto(stream, beatmap);
|
base.ParseStreamInto(stream, beatmap);
|
||||||
|
|
||||||
// objects may be out of order *only* if a user has manually edited an .osu file.
|
// Objects may be out of order *only* if a user has manually edited an .osu file.
|
||||||
// unfortunately there are ranked maps in this state (example: https://osu.ppy.sh/s/594828).
|
// Unfortunately there are ranked maps in this state (example: https://osu.ppy.sh/s/594828).
|
||||||
this.beatmap.HitObjects.Sort((x, y) => x.StartTime.CompareTo(y.StartTime));
|
// OrderBy is used to guarantee that the parsing order of hitobjects with equal start times is maintained (stably-sorted)
|
||||||
|
// The parsing order of hitobjects matters in mania difficulty calculation
|
||||||
|
this.beatmap.HitObjects = this.beatmap.HitObjects.OrderBy(h => h.StartTime).ToList();
|
||||||
|
|
||||||
foreach (var hitObject in this.beatmap.HitObjects)
|
foreach (var hitObject in this.beatmap.HitObjects)
|
||||||
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty);
|
hitObject.ApplyDefaults(this.beatmap.ControlPointInfo, this.beatmap.BeatmapInfo.BaseDifficulty);
|
||||||
|
@ -107,8 +107,14 @@ namespace osu.Game.Beatmaps
|
|||||||
IBeatmap converted = converter.Convert();
|
IBeatmap converted = converter.Convert();
|
||||||
|
|
||||||
// Apply difficulty mods
|
// Apply difficulty mods
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToDifficulty>())
|
if (Mods.Value.Any(m => m is IApplicableToDifficulty))
|
||||||
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
|
{
|
||||||
|
converted.BeatmapInfo = converted.BeatmapInfo.Clone();
|
||||||
|
converted.BeatmapInfo.BaseDifficulty = converted.BeatmapInfo.BaseDifficulty.Clone();
|
||||||
|
|
||||||
|
foreach (var mod in Mods.Value.OfType<IApplicableToDifficulty>())
|
||||||
|
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
|
||||||
|
}
|
||||||
|
|
||||||
// Post-process
|
// Post-process
|
||||||
rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess();
|
rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess();
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Audio.Sample;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Game.Graphics.Containers
|
namespace osu.Game.Graphics.Containers
|
||||||
{
|
{
|
||||||
@ -15,9 +16,14 @@ namespace osu.Game.Graphics.Containers
|
|||||||
private SampleChannel samplePopIn;
|
private SampleChannel samplePopIn;
|
||||||
private SampleChannel samplePopOut;
|
private SampleChannel samplePopOut;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
private readonly BindableBool allowOpeningOverlays = new BindableBool(true);
|
||||||
private void load(AudioManager audio)
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OsuGame osuGame, AudioManager audio)
|
||||||
{
|
{
|
||||||
|
if (osuGame != null)
|
||||||
|
allowOpeningOverlays.BindTo(osuGame.AllowOpeningOverlays);
|
||||||
|
|
||||||
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
|
samplePopIn = audio.Sample.Get(@"UI/overlay-pop-in");
|
||||||
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
|
samplePopOut = audio.Sample.Get(@"UI/overlay-pop-out");
|
||||||
|
|
||||||
@ -46,15 +52,20 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
private void onStateChanged(Visibility visibility)
|
private void onStateChanged(Visibility visibility)
|
||||||
{
|
{
|
||||||
switch (visibility)
|
if (allowOpeningOverlays)
|
||||||
{
|
{
|
||||||
case Visibility.Visible:
|
switch (visibility)
|
||||||
samplePopIn?.Play();
|
{
|
||||||
break;
|
case Visibility.Visible:
|
||||||
case Visibility.Hidden:
|
samplePopIn?.Play();
|
||||||
samplePopOut?.Play();
|
break;
|
||||||
break;
|
case Visibility.Hidden:
|
||||||
|
samplePopOut?.Play();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
State = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs
Normal file
54
osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="BreadcrumbControl"/> which follows the active screen (and allows navigation) in a <see cref="Screen"/> stack.
|
||||||
|
/// </summary>
|
||||||
|
public class ScreenBreadcrumbControl : BreadcrumbControl<Screen>
|
||||||
|
{
|
||||||
|
private Screen last;
|
||||||
|
|
||||||
|
public ScreenBreadcrumbControl(Screen initialScreen)
|
||||||
|
{
|
||||||
|
Current.ValueChanged += newScreen =>
|
||||||
|
{
|
||||||
|
if (last != newScreen && !newScreen.IsCurrentScreen)
|
||||||
|
newScreen.MakeCurrent();
|
||||||
|
};
|
||||||
|
|
||||||
|
onPushed(initialScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void screenChanged(Screen newScreen)
|
||||||
|
{
|
||||||
|
if (newScreen == null) return;
|
||||||
|
|
||||||
|
if (last != null)
|
||||||
|
{
|
||||||
|
last.Exited -= screenChanged;
|
||||||
|
last.ModePushed -= onPushed;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = newScreen;
|
||||||
|
|
||||||
|
newScreen.Exited += screenChanged;
|
||||||
|
newScreen.ModePushed += onPushed;
|
||||||
|
|
||||||
|
Current.Value = newScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPushed(Screen screen)
|
||||||
|
{
|
||||||
|
Items.ToList().SkipWhile(i => i != Current.Value).Skip(1).ForEach(RemoveItem);
|
||||||
|
AddItem(screen);
|
||||||
|
|
||||||
|
screenChanged(screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
osu.Game/Graphics/UserInterface/SelectionState.cs
Normal file
11
osu.Game/Graphics/UserInterface/SelectionState.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
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public enum SelectionState
|
||||||
|
{
|
||||||
|
NotSelected,
|
||||||
|
Selected
|
||||||
|
}
|
||||||
|
}
|
@ -18,8 +18,6 @@ namespace osu.Game.IO.Serialization
|
|||||||
|
|
||||||
public static void DeserializeInto<T>(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings());
|
public static void DeserializeInto<T>(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings());
|
||||||
|
|
||||||
public static T DeepClone<T>(this T obj) where T : IJsonSerializable => Deserialize<T>(Serialize(obj));
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the default <see cref="JsonSerializerSettings"/> that should be used for all <see cref="IJsonSerializable"/>s.
|
/// Creates the default <see cref="JsonSerializerSettings"/> that should be used for all <see cref="IJsonSerializable"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -37,6 +37,9 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(InputKey.Down, GlobalAction.DecreaseVolume),
|
new KeyBinding(InputKey.Down, GlobalAction.DecreaseVolume),
|
||||||
new KeyBinding(InputKey.MouseWheelDown, GlobalAction.DecreaseVolume),
|
new KeyBinding(InputKey.MouseWheelDown, GlobalAction.DecreaseVolume),
|
||||||
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
|
||||||
|
|
||||||
|
new KeyBinding(InputKey.Escape, GlobalAction.Back),
|
||||||
|
new KeyBinding(InputKey.MouseButton1, GlobalAction.Back)
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||||
@ -80,5 +83,8 @@ namespace osu.Game.Input.Bindings
|
|||||||
TakeScreenshot,
|
TakeScreenshot,
|
||||||
[Description("Toggle gameplay mouse buttons")]
|
[Description("Toggle gameplay mouse buttons")]
|
||||||
ToggleGameplayMouseButtons,
|
ToggleGameplayMouseButtons,
|
||||||
|
|
||||||
|
[Description("Go back")]
|
||||||
|
Back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
|
public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
|
||||||
|
|
||||||
public readonly BindableBool ShowOverlays = new BindableBool();
|
public readonly BindableBool HideOverlaysOnEnter = new BindableBool();
|
||||||
|
public readonly BindableBool AllowOpeningOverlays = new BindableBool(true);
|
||||||
|
|
||||||
private OsuScreen screenStack;
|
private OsuScreen screenStack;
|
||||||
|
|
||||||
@ -367,12 +368,12 @@ namespace osu.Game
|
|||||||
settings.StateChanged += _ => updateScreenOffset();
|
settings.StateChanged += _ => updateScreenOffset();
|
||||||
notifications.StateChanged += _ => updateScreenOffset();
|
notifications.StateChanged += _ => updateScreenOffset();
|
||||||
|
|
||||||
notifications.Enabled.BindTo(ShowOverlays);
|
notifications.Enabled.BindTo(AllowOpeningOverlays);
|
||||||
|
|
||||||
ShowOverlays.ValueChanged += show =>
|
HideOverlaysOnEnter.ValueChanged += hide =>
|
||||||
{
|
{
|
||||||
//central game screen change logic.
|
//central game screen change logic.
|
||||||
if (!show)
|
if (hide)
|
||||||
{
|
{
|
||||||
hideAllOverlays();
|
hideAllOverlays();
|
||||||
musicController.State = Visibility.Hidden;
|
musicController.State = Visibility.Hidden;
|
||||||
|
@ -6,9 +6,11 @@ using osu.Framework.Allocation;
|
|||||||
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.Input.Bindings;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Overlays.Settings.Sections;
|
using osu.Game.Overlays.Settings.Sections;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
@ -96,7 +98,7 @@ namespace osu.Game.Overlays
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BackButton : OsuClickableContainer
|
private class BackButton : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private AspectContainer aspect;
|
private AspectContainer aspect;
|
||||||
|
|
||||||
@ -146,6 +148,20 @@ namespace osu.Game.Overlays
|
|||||||
aspect.ScaleTo(1, 1000, Easing.OutElastic);
|
aspect.ScaleTo(1, 1000, Easing.OutElastic);
|
||||||
return base.OnMouseUp(state, args);
|
return base.OnMouseUp(state, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.Back:
|
||||||
|
TriggerOnClick();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
using OpenTK.Input;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -22,6 +24,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
private readonly Drawable modeButtonLine;
|
private readonly Drawable modeButtonLine;
|
||||||
private ToolbarModeButton activeButton;
|
private ToolbarModeButton activeButton;
|
||||||
|
|
||||||
|
private RulesetStore rulesets;
|
||||||
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
public ToolbarModeSelector()
|
public ToolbarModeSelector()
|
||||||
@ -67,26 +70,42 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(RulesetStore rulesets, OsuGame game)
|
private void load(RulesetStore rulesets, OsuGame game)
|
||||||
{
|
{
|
||||||
|
this.rulesets = rulesets;
|
||||||
foreach (var r in rulesets.AvailableRulesets)
|
foreach (var r in rulesets.AvailableRulesets)
|
||||||
{
|
{
|
||||||
modeButtons.Add(new ToolbarModeButton
|
modeButtons.Add(new ToolbarModeButton
|
||||||
{
|
{
|
||||||
Ruleset = r,
|
Ruleset = r,
|
||||||
Action = delegate
|
Action = delegate { ruleset.Value = r; }
|
||||||
{
|
|
||||||
ruleset.Value = r;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleset.ValueChanged += rulesetChanged;
|
ruleset.ValueChanged += rulesetChanged;
|
||||||
ruleset.DisabledChanged += disabledChanged;
|
ruleset.DisabledChanged += disabledChanged;
|
||||||
|
|
||||||
if (game != null)
|
if (game != null)
|
||||||
ruleset.BindTo(game.Ruleset);
|
ruleset.BindTo(game.Ruleset);
|
||||||
else
|
else
|
||||||
ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault();
|
ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
|
{
|
||||||
|
base.OnKeyDown(state, args);
|
||||||
|
|
||||||
|
if (state.Keyboard.ControlPressed && !args.Repeat && args.Key >= Key.Number1 && args.Key <= Key.Number9)
|
||||||
|
{
|
||||||
|
int requested = args.Key - Key.Number1;
|
||||||
|
|
||||||
|
RulesetInfo found = rulesets.AvailableRulesets.Skip(requested).FirstOrDefault();
|
||||||
|
if (found != null)
|
||||||
|
ruleset.Value = found;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool HandleKeyboardInput => !ruleset.Disabled && base.HandleKeyboardInput;
|
public override bool HandleKeyboardInput => !ruleset.Disabled && base.HandleKeyboardInput;
|
||||||
public override bool HandleMouseInput => !ruleset.Disabled && base.HandleMouseInput;
|
public override bool HandleMouseInput => !ruleset.Disabled && base.HandleMouseInput;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
private readonly Dictionary<string, double> attributes = new Dictionary<string, double>();
|
private readonly Dictionary<string, double> attributes = new Dictionary<string, double>();
|
||||||
protected IDictionary<string, double> Attributes => attributes;
|
protected IDictionary<string, double> Attributes => attributes;
|
||||||
|
|
||||||
|
protected readonly Ruleset Ruleset;
|
||||||
protected readonly IBeatmap Beatmap;
|
protected readonly IBeatmap Beatmap;
|
||||||
protected readonly Score Score;
|
protected readonly Score Score;
|
||||||
|
|
||||||
@ -23,9 +24,9 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
|
|
||||||
protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
protected PerformanceCalculator(Ruleset ruleset, IBeatmap beatmap, Score score)
|
||||||
{
|
{
|
||||||
Score = score;
|
Ruleset = ruleset;
|
||||||
|
|
||||||
Beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
|
Score = score;
|
||||||
|
|
||||||
var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods);
|
var diffCalc = ruleset.CreateDifficultyCalculator(beatmap, score.Mods);
|
||||||
diffCalc.Calculate(attributes);
|
diffCalc.Calculate(attributes);
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
@ -137,10 +138,4 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Quad SelectionQuad => ScreenSpaceDrawQuad;
|
public virtual Quad SelectionQuad => ScreenSpaceDrawQuad;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SelectionState
|
|
||||||
{
|
|
||||||
NotSelected,
|
|
||||||
Selected
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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 System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
@ -56,10 +57,10 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public HitWindows HitWindows { get; set; }
|
public HitWindows HitWindows { get; set; }
|
||||||
|
|
||||||
private readonly SortedList<HitObject> nestedHitObjects = new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
|
private readonly Lazy<SortedList<HitObject>> nestedHitObjects = new Lazy<SortedList<HitObject>>(() => new SortedList<HitObject>((h1, h2) => h1.StartTime.CompareTo(h2.StartTime)));
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IReadOnlyList<HitObject> NestedHitObjects => nestedHitObjects;
|
public IReadOnlyList<HitObject> NestedHitObjects => nestedHitObjects.Value;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies default values to this HitObject.
|
/// Applies default values to this HitObject.
|
||||||
@ -70,13 +71,19 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
{
|
{
|
||||||
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
nestedHitObjects.Clear();
|
if (nestedHitObjects.IsValueCreated)
|
||||||
|
nestedHitObjects.Value.Clear();
|
||||||
|
|
||||||
CreateNestedHitObjects();
|
CreateNestedHitObjects();
|
||||||
nestedHitObjects.ForEach(h =>
|
|
||||||
|
if (nestedHitObjects.IsValueCreated)
|
||||||
{
|
{
|
||||||
h.HitWindows = HitWindows;
|
nestedHitObjects.Value.ForEach(h =>
|
||||||
h.ApplyDefaults(controlPointInfo, difficulty);
|
{
|
||||||
});
|
h.HitWindows = HitWindows;
|
||||||
|
h.ApplyDefaults(controlPointInfo, difficulty);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected virtual void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
@ -96,7 +103,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject);
|
protected void AddNested(HitObject hitObject) => nestedHitObjects.Value.Add(hitObject);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
|
/// Creates the <see cref="HitWindows"/> for this <see cref="HitObject"/>.
|
||||||
|
@ -135,39 +135,5 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// <param name="timeOffset">The time offset.</param>
|
/// <param name="timeOffset">The time offset.</param>
|
||||||
/// <returns>Whether the <see cref="HitObject"/> can be hit at any point in the future from this time offset.</returns>
|
/// <returns>Whether the <see cref="HitObject"/> can be hit at any point in the future from this time offset.</returns>
|
||||||
public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(HitResult.Meh);
|
public bool CanBeHit(double timeOffset) => timeOffset <= HalfWindowFor(HitResult.Meh);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multiplies all hit windows by a value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="windows">The hit windows to multiply.</param>
|
|
||||||
/// <param name="value">The value to multiply each hit window by.</param>
|
|
||||||
public static HitWindows operator *(HitWindows windows, double value)
|
|
||||||
{
|
|
||||||
windows.Perfect *= value;
|
|
||||||
windows.Great *= value;
|
|
||||||
windows.Good *= value;
|
|
||||||
windows.Ok *= value;
|
|
||||||
windows.Meh *= value;
|
|
||||||
windows.Miss *= value;
|
|
||||||
|
|
||||||
return windows;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Divides all hit windows by a value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="windows">The hit windows to divide.</param>
|
|
||||||
/// <param name="value">The value to divide each hit window by.</param>
|
|
||||||
public static HitWindows operator /(HitWindows windows, double value)
|
|
||||||
{
|
|
||||||
windows.Perfect /= value;
|
|
||||||
windows.Great /= value;
|
|
||||||
windows.Good /= value;
|
|
||||||
windows.Ok /= value;
|
|
||||||
windows.Meh /= value;
|
|
||||||
windows.Miss /= value;
|
|
||||||
|
|
||||||
return windows;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
|
|
||||||
public float X { get; set; }
|
public float X { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
|
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
|
|
||||||
public float Y => Position.Y;
|
public float Y => Position.Y;
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
{
|
{
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
{
|
{
|
||||||
public bool NewCombo { get; set; }
|
public bool NewCombo { get; set; }
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
|
|
||||||
public double Duration => EndTime - StartTime;
|
public double Duration => EndTime - StartTime;
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => new ConvertHitWindows();
|
protected override HitWindows CreateHitWindows() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.Extensions.IEnumerableExtensions;
|
|||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.IO.Serialization;
|
|
||||||
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.Timing;
|
using osu.Game.Rulesets.Timing;
|
||||||
@ -104,7 +103,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
if (index < 0)
|
if (index < 0)
|
||||||
return new MultiplierControlPoint(time);
|
return new MultiplierControlPoint(time);
|
||||||
|
|
||||||
return new MultiplierControlPoint(time, DefaultControlPoints[index].DeepClone());
|
return new MultiplierControlPoint(time, DefaultControlPoints[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
|
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => false;
|
protected override bool HideOverlaysOnEnter => true;
|
||||||
public override bool AllowBeatmapRulesetChange => false;
|
public override bool AllowBeatmapRulesetChange => false;
|
||||||
|
|
||||||
private Box bottomBackground;
|
private Box bottomBackground;
|
||||||
|
@ -17,7 +17,9 @@ namespace osu.Game.Screens
|
|||||||
{
|
{
|
||||||
private bool showDisclaimer;
|
private bool showDisclaimer;
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => false;
|
protected override bool HideOverlaysOnEnter => true;
|
||||||
|
|
||||||
|
protected override bool AllowBackButton => false;
|
||||||
|
|
||||||
public Loader()
|
public Loader()
|
||||||
{
|
{
|
||||||
|
@ -6,26 +6,29 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Configuration;
|
|
||||||
using osu.Framework.Threading;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Menu
|
namespace osu.Game.Screens.Menu
|
||||||
{
|
{
|
||||||
public class ButtonSystem : Container, IStateful<MenuState>
|
public class ButtonSystem : Container, IStateful<MenuState>, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public event Action<MenuState> StateChanged;
|
public event Action<MenuState> StateChanged;
|
||||||
|
|
||||||
private readonly BindableBool showOverlays = new BindableBool();
|
private readonly BindableBool hideOverlaysOnEnter = new BindableBool();
|
||||||
|
private readonly BindableBool allowOpeningOverlays = new BindableBool();
|
||||||
|
|
||||||
public Action OnEdit;
|
public Action OnEdit;
|
||||||
public Action OnExit;
|
public Action OnExit;
|
||||||
@ -133,7 +136,12 @@ namespace osu.Game.Screens.Menu
|
|||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(AudioManager audio, OsuGame game)
|
private void load(AudioManager audio, OsuGame game)
|
||||||
{
|
{
|
||||||
if (game != null) showOverlays.BindTo(game.ShowOverlays);
|
if (game != null)
|
||||||
|
{
|
||||||
|
hideOverlaysOnEnter.BindTo(game.HideOverlaysOnEnter);
|
||||||
|
allowOpeningOverlays.BindTo(game.AllowOpeningOverlays);
|
||||||
|
}
|
||||||
|
|
||||||
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
|
sampleBack = audio.Sample.Get(@"Menu/button-back-select");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +154,16 @@ namespace osu.Game.Screens.Menu
|
|||||||
case Key.Space:
|
case Key.Space:
|
||||||
logo?.TriggerOnClick(state);
|
logo?.TriggerOnClick(state);
|
||||||
return true;
|
return true;
|
||||||
case Key.Escape:
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.Back:
|
||||||
switch (State)
|
switch (State)
|
||||||
{
|
{
|
||||||
case MenuState.TopLevel:
|
case MenuState.TopLevel:
|
||||||
@ -155,12 +172,23 @@ namespace osu.Game.Screens.Menu
|
|||||||
case MenuState.Play:
|
case MenuState.Play:
|
||||||
backButton.TriggerOnClick();
|
backButton.TriggerOnClick();
|
||||||
return true;
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
public bool OnReleased(GlobalAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case GlobalAction.Back:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPlay()
|
private void onPlay()
|
||||||
@ -300,8 +328,6 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
logoDelayedAction = Scheduler.AddDelayed(() =>
|
logoDelayedAction = Scheduler.AddDelayed(() =>
|
||||||
{
|
{
|
||||||
showOverlays.Value = false;
|
|
||||||
|
|
||||||
logo.ClearTransforms(targetMember: nameof(Position));
|
logo.ClearTransforms(targetMember: nameof(Position));
|
||||||
logo.RelativePositionAxes = Axes.Both;
|
logo.RelativePositionAxes = Axes.Both;
|
||||||
|
|
||||||
@ -329,7 +355,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
logoTracking = true;
|
logoTracking = true;
|
||||||
|
|
||||||
logo.Impact();
|
logo.Impact();
|
||||||
showOverlays.Value = true;
|
hideOverlaysOnEnter.Value = false;
|
||||||
|
allowOpeningOverlays.Value = true;
|
||||||
}, 200);
|
}, 200);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -337,6 +364,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
|
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case MenuState.EnteringMode:
|
case MenuState.EnteringMode:
|
||||||
logoTracking = true;
|
logoTracking = true;
|
||||||
|
@ -18,7 +18,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
private readonly SpriteIcon icon;
|
private readonly SpriteIcon icon;
|
||||||
private Color4 iconColour;
|
private Color4 iconColour;
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => false;
|
protected override bool HideOverlaysOnEnter => true;
|
||||||
|
|
||||||
public override bool CursorVisible => false;
|
public override bool CursorVisible => false;
|
||||||
|
|
||||||
public Disclaimer()
|
public Disclaimer()
|
||||||
|
@ -31,7 +31,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
private SampleChannel welcome;
|
private SampleChannel welcome;
|
||||||
private SampleChannel seeya;
|
private SampleChannel seeya;
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => false;
|
protected override bool HideOverlaysOnEnter => true;
|
||||||
|
protected override bool AllowOpeningOverlays => false;
|
||||||
|
|
||||||
public override bool CursorVisible => false;
|
public override bool CursorVisible => false;
|
||||||
|
|
||||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty();
|
protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty();
|
||||||
|
@ -14,7 +14,7 @@ using osu.Game.Screens.Backgrounds;
|
|||||||
using osu.Game.Screens.Charts;
|
using osu.Game.Screens.Charts;
|
||||||
using osu.Game.Screens.Direct;
|
using osu.Game.Screens.Direct;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Multi.Screens;
|
using osu.Game.Screens.Multi;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Screens.Tournament;
|
using osu.Game.Screens.Tournament;
|
||||||
|
|
||||||
@ -24,7 +24,10 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
private readonly ButtonSystem buttons;
|
private readonly ButtonSystem buttons;
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => buttons.State != MenuState.Initial;
|
protected override bool HideOverlaysOnEnter => buttons.State == MenuState.Initial;
|
||||||
|
protected override bool AllowOpeningOverlays => buttons.State != MenuState.Initial;
|
||||||
|
|
||||||
|
protected override bool AllowBackButton => buttons.State != MenuState.Initial;
|
||||||
|
|
||||||
private readonly BackgroundScreenDefault background;
|
private readonly BackgroundScreenDefault background;
|
||||||
private Screen songSelect;
|
private Screen songSelect;
|
||||||
@ -54,7 +57,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
OnDirect = delegate { Push(new OnlineListing()); },
|
OnDirect = delegate { Push(new OnlineListing()); },
|
||||||
OnEdit = delegate { Push(new Editor()); },
|
OnEdit = delegate { Push(new Editor()); },
|
||||||
OnSolo = delegate { Push(consumeSongSelect()); },
|
OnSolo = delegate { Push(consumeSongSelect()); },
|
||||||
OnMulti = delegate { Push(new Lobby()); },
|
OnMulti = delegate { Push(new Multiplayer()); },
|
||||||
OnExit = Exit,
|
OnExit = Exit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// 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.Framework;
|
||||||
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;
|
||||||
@ -13,6 +15,7 @@ using osu.Game.Beatmaps.Drawables;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -20,20 +23,17 @@ using OpenTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Multi.Components
|
namespace osu.Game.Screens.Multi.Components
|
||||||
{
|
{
|
||||||
public class DrawableRoom : OsuClickableContainer
|
public class DrawableRoom : OsuClickableContainer, IStateful<SelectionState>
|
||||||
{
|
{
|
||||||
|
private const float corner_radius = 5;
|
||||||
|
private const float selection_border_width = 4;
|
||||||
private const float transition_duration = 100;
|
private const float transition_duration = 100;
|
||||||
private const float content_padding = 10;
|
private const float content_padding = 10;
|
||||||
private const float height = 100;
|
private const float height = 100;
|
||||||
private const float side_strip_width = 5;
|
private const float side_strip_width = 5;
|
||||||
private const float cover_width = 145;
|
private const float cover_width = 145;
|
||||||
|
|
||||||
private readonly Box sideStrip;
|
private readonly Box selectionBox;
|
||||||
private readonly Container coverContainer;
|
|
||||||
private readonly OsuSpriteText name, status, beatmapTitle, beatmapDash, beatmapArtist;
|
|
||||||
private readonly FillFlowContainer<OsuSpriteText> beatmapInfoFlow;
|
|
||||||
private readonly ParticipantInfo participantInfo;
|
|
||||||
private readonly ModeTypeInfo modeTypeInfo;
|
|
||||||
|
|
||||||
private readonly Bindable<string> nameBind = new Bindable<string>();
|
private readonly Bindable<string> nameBind = new Bindable<string>();
|
||||||
private readonly Bindable<User> hostBind = new Bindable<User>();
|
private readonly Bindable<User> hostBind = new Bindable<User>();
|
||||||
@ -42,136 +42,228 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
|
private readonly Bindable<BeatmapInfo> beatmapBind = new Bindable<BeatmapInfo>();
|
||||||
private readonly Bindable<User[]> participantsBind = new Bindable<User[]>();
|
private readonly Bindable<User[]> participantsBind = new Bindable<User[]>();
|
||||||
|
|
||||||
private OsuColour colours;
|
|
||||||
private LocalisationEngine localisation;
|
|
||||||
|
|
||||||
public readonly Room Room;
|
public readonly Room Room;
|
||||||
|
|
||||||
|
private SelectionState state;
|
||||||
|
public SelectionState State
|
||||||
|
{
|
||||||
|
get { return state; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == state) return;
|
||||||
|
state = value;
|
||||||
|
|
||||||
|
if (state == SelectionState.Selected)
|
||||||
|
selectionBox.FadeIn(transition_duration);
|
||||||
|
else
|
||||||
|
selectionBox.FadeOut(transition_duration);
|
||||||
|
|
||||||
|
StateChanged?.Invoke(State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<SelectionState> StateChanged;
|
||||||
|
|
||||||
public DrawableRoom(Room room)
|
public DrawableRoom(Room room)
|
||||||
{
|
{
|
||||||
Room = room;
|
Room = room;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = height;
|
Height = height + selection_border_width * 2;
|
||||||
CornerRadius = 5;
|
CornerRadius = corner_radius + selection_border_width / 2;
|
||||||
Masking = true;
|
Masking = true;
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
|
// create selectionBox here so State can be set before being loaded
|
||||||
|
selectionBox = new Box
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Shadow,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black.Opacity(40),
|
Alpha = 0f,
|
||||||
Radius = 5,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Action += () => State = SelectionState.Selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, LocalisationEngine localisation)
|
||||||
|
{
|
||||||
|
Box sideStrip;
|
||||||
|
Container coverContainer;
|
||||||
|
OsuSpriteText name, status, beatmapTitle, beatmapDash, beatmapArtist;
|
||||||
|
ParticipantInfo participantInfo;
|
||||||
|
ModeTypeInfo modeTypeInfo;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
selectionBox,
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = OsuColour.FromHex(@"212121"),
|
|
||||||
},
|
|
||||||
sideStrip = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Width = side_strip_width,
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Width = cover_width,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Masking = true,
|
|
||||||
Margin = new MarginPadding { Left = side_strip_width },
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = Color4.Black,
|
|
||||||
},
|
|
||||||
coverContainer = new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding(selection_border_width),
|
||||||
|
Child = new Container
|
||||||
{
|
{
|
||||||
Vertical = content_padding,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Left = side_strip_width + cover_width + content_padding,
|
Masking = true,
|
||||||
Right = content_padding,
|
CornerRadius = corner_radius,
|
||||||
},
|
EdgeEffect = new EdgeEffectParameters
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
Type = EdgeEffectType.Shadow,
|
||||||
AutoSizeAxes = Axes.Y,
|
Colour = Color4.Black.Opacity(40),
|
||||||
Direction = FillDirection.Vertical,
|
Radius = 5,
|
||||||
Spacing = new Vector2(5f),
|
},
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
{
|
{
|
||||||
name = new OsuSpriteText
|
RelativeSizeAxes = Axes.Both,
|
||||||
{
|
Colour = OsuColour.FromHex(@"212121"),
|
||||||
TextSize = 18,
|
|
||||||
},
|
|
||||||
participantInfo = new ParticipantInfo(),
|
|
||||||
},
|
},
|
||||||
},
|
sideStrip = new Box
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
status = new OsuSpriteText
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = side_strip_width,
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Width = cover_width,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Masking = true,
|
||||||
|
Margin = new MarginPadding { Left = side_strip_width },
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
TextSize = 14,
|
new Box
|
||||||
Font = @"Exo2.0-Bold",
|
|
||||||
},
|
|
||||||
beatmapInfoFlow = new FillFlowContainer<OsuSpriteText>
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
AutoSizeAxes = Axes.Y,
|
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Children = new[]
|
|
||||||
{
|
{
|
||||||
beatmapTitle = new OsuSpriteText
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
},
|
||||||
|
coverContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding
|
||||||
|
{
|
||||||
|
Vertical = content_padding,
|
||||||
|
Left = side_strip_width + cover_width + content_padding,
|
||||||
|
Right = content_padding,
|
||||||
|
},
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Spacing = new Vector2(5f),
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
TextSize = 14,
|
name = new OsuSpriteText
|
||||||
Font = @"Exo2.0-BoldItalic",
|
{
|
||||||
|
TextSize = 18,
|
||||||
|
},
|
||||||
|
participantInfo = new ParticipantInfo(),
|
||||||
},
|
},
|
||||||
beatmapDash = new OsuSpriteText
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
TextSize = 14,
|
status = new OsuSpriteText
|
||||||
Font = @"Exo2.0-BoldItalic",
|
{
|
||||||
},
|
TextSize = 14,
|
||||||
beatmapArtist = new OsuSpriteText
|
Font = @"Exo2.0-Bold",
|
||||||
{
|
},
|
||||||
TextSize = 14,
|
new FillFlowContainer<OsuSpriteText>
|
||||||
Font = @"Exo2.0-RegularItalic",
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Colour = colours.Gray9,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
beatmapTitle = new OsuSpriteText
|
||||||
|
{
|
||||||
|
TextSize = 14,
|
||||||
|
Font = @"Exo2.0-BoldItalic",
|
||||||
|
},
|
||||||
|
beatmapDash = new OsuSpriteText
|
||||||
|
{
|
||||||
|
TextSize = 14,
|
||||||
|
Font = @"Exo2.0-BoldItalic",
|
||||||
|
},
|
||||||
|
beatmapArtist = new OsuSpriteText
|
||||||
|
{
|
||||||
|
TextSize = 14,
|
||||||
|
Font = @"Exo2.0-RegularItalic",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
modeTypeInfo = new ModeTypeInfo
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomRight,
|
||||||
|
Origin = Anchor.BottomRight,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
modeTypeInfo = new ModeTypeInfo
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
nameBind.ValueChanged += displayName;
|
nameBind.ValueChanged += n => name.Text = n;
|
||||||
hostBind.ValueChanged += displayUser;
|
hostBind.ValueChanged += h => participantInfo.Host = h;
|
||||||
typeBind.ValueChanged += displayGameType;
|
typeBind.ValueChanged += m => modeTypeInfo.Type = m;
|
||||||
participantsBind.ValueChanged += displayParticipants;
|
participantsBind.ValueChanged += p => participantInfo.Participants = p;
|
||||||
|
|
||||||
|
statusBind.ValueChanged += s =>
|
||||||
|
{
|
||||||
|
status.Text = s.Message;
|
||||||
|
|
||||||
|
foreach (Drawable d in new Drawable[] { selectionBox, sideStrip, status })
|
||||||
|
d.FadeColour(s.GetAppropriateColour(colours), 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
beatmapBind.ValueChanged += b =>
|
||||||
|
{
|
||||||
|
modeTypeInfo.Beatmap = b;
|
||||||
|
|
||||||
|
if (b != null)
|
||||||
|
{
|
||||||
|
coverContainer.FadeIn(transition_duration);
|
||||||
|
|
||||||
|
LoadComponentAsync(new BeatmapSetCover(b.BeatmapSet)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
FillMode = FillMode.Fill,
|
||||||
|
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
||||||
|
}, coverContainer.Add);
|
||||||
|
|
||||||
|
beatmapTitle.Current = localisation.GetUnicodePreference(b.Metadata.TitleUnicode, b.Metadata.Title);
|
||||||
|
beatmapDash.Text = @" - ";
|
||||||
|
beatmapArtist.Current = localisation.GetUnicodePreference(b.Metadata.ArtistUnicode, b.Metadata.Artist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coverContainer.FadeOut(transition_duration);
|
||||||
|
|
||||||
|
beatmapTitle.Current = null;
|
||||||
|
beatmapArtist.Current = null;
|
||||||
|
|
||||||
|
beatmapTitle.Text = "Changing map";
|
||||||
|
beatmapDash.Text = beatmapArtist.Text = string.Empty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
nameBind.BindTo(Room.Name);
|
nameBind.BindTo(Room.Name);
|
||||||
hostBind.BindTo(Room.Host);
|
hostBind.BindTo(Room.Host);
|
||||||
@ -180,83 +272,5 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
beatmapBind.BindTo(Room.Beatmap);
|
beatmapBind.BindTo(Room.Beatmap);
|
||||||
participantsBind.BindTo(Room.Participants);
|
participantsBind.BindTo(Room.Participants);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours, LocalisationEngine localisation)
|
|
||||||
{
|
|
||||||
this.localisation = localisation;
|
|
||||||
this.colours = colours;
|
|
||||||
|
|
||||||
beatmapInfoFlow.Colour = colours.Gray9;
|
|
||||||
|
|
||||||
//binded here instead of ctor because dependencies are needed
|
|
||||||
statusBind.ValueChanged += displayStatus;
|
|
||||||
beatmapBind.ValueChanged += displayBeatmap;
|
|
||||||
|
|
||||||
statusBind.TriggerChange();
|
|
||||||
beatmapBind.TriggerChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayName(string value)
|
|
||||||
{
|
|
||||||
name.Text = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayUser(User value)
|
|
||||||
{
|
|
||||||
participantInfo.Host = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayStatus(RoomStatus value)
|
|
||||||
{
|
|
||||||
if (value == null) return;
|
|
||||||
status.Text = value.Message;
|
|
||||||
|
|
||||||
foreach (Drawable d in new Drawable[] { sideStrip, status })
|
|
||||||
d.FadeColour(value.GetAppropriateColour(colours), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayGameType(GameType value)
|
|
||||||
{
|
|
||||||
modeTypeInfo.Type = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayBeatmap(BeatmapInfo value)
|
|
||||||
{
|
|
||||||
modeTypeInfo.Beatmap = value;
|
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
coverContainer.FadeIn(transition_duration);
|
|
||||||
|
|
||||||
LoadComponentAsync(new BeatmapSetCover(value.BeatmapSet)
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
FillMode = FillMode.Fill,
|
|
||||||
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
|
||||||
},
|
|
||||||
coverContainer.Add);
|
|
||||||
|
|
||||||
beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title);
|
|
||||||
beatmapDash.Text = @" - ";
|
|
||||||
beatmapArtist.Current = localisation.GetUnicodePreference(value.Metadata.ArtistUnicode, value.Metadata.Artist);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
coverContainer.FadeOut(transition_duration);
|
|
||||||
|
|
||||||
beatmapTitle.Current = null;
|
|
||||||
beatmapArtist.Current = null;
|
|
||||||
|
|
||||||
beatmapTitle.Text = "Changing map";
|
|
||||||
beatmapDash.Text = beatmapArtist.Text = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayParticipants(User[] value)
|
|
||||||
{
|
|
||||||
participantInfo.Participants = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,17 +25,9 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
{
|
{
|
||||||
public class RoomInspector : Container
|
public class RoomInspector : Container
|
||||||
{
|
{
|
||||||
private readonly MarginPadding contentPadding = new MarginPadding { Horizontal = 20, Vertical = 10 };
|
|
||||||
private const float transition_duration = 100;
|
private const float transition_duration = 100;
|
||||||
|
|
||||||
private readonly Box statusStrip;
|
private readonly MarginPadding contentPadding = new MarginPadding { Horizontal = 20, Vertical = 10 };
|
||||||
private readonly Container coverContainer;
|
|
||||||
private readonly FillFlowContainer topFlow, participantsFlow;
|
|
||||||
private readonly ModeTypeInfo modeTypeInfo;
|
|
||||||
private readonly OsuSpriteText participants, participantsSlash, maxParticipants, name, status, beatmapTitle, beatmapDash, beatmapArtist, beatmapAuthor;
|
|
||||||
private readonly ParticipantInfo participantInfo;
|
|
||||||
private readonly ScrollContainer participantsScroll;
|
|
||||||
|
|
||||||
private readonly Bindable<string> nameBind = new Bindable<string>();
|
private readonly Bindable<string> nameBind = new Bindable<string>();
|
||||||
private readonly Bindable<User> hostBind = new Bindable<User>();
|
private readonly Bindable<User> hostBind = new Bindable<User>();
|
||||||
private readonly Bindable<RoomStatus> statusBind = new Bindable<RoomStatus>();
|
private readonly Bindable<RoomStatus> statusBind = new Bindable<RoomStatus>();
|
||||||
@ -45,10 +37,14 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
private readonly Bindable<User[]> participantsBind = new Bindable<User[]>();
|
private readonly Bindable<User[]> participantsBind = new Bindable<User[]>();
|
||||||
|
|
||||||
private OsuColour colours;
|
private OsuColour colours;
|
||||||
private LocalisationEngine localisation;
|
private Box statusStrip;
|
||||||
|
private Container coverContainer;
|
||||||
|
private FillFlowContainer topFlow, participantsFlow, participantNumbersFlow, infoPanelFlow;
|
||||||
|
private OsuSpriteText name, status;
|
||||||
|
private ScrollContainer participantsScroll;
|
||||||
|
private ParticipantInfo participantInfo;
|
||||||
|
|
||||||
private Room room;
|
private Room room;
|
||||||
|
|
||||||
public Room Room
|
public Room Room
|
||||||
{
|
{
|
||||||
get { return room; }
|
get { return room; }
|
||||||
@ -57,20 +53,36 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
if (value == room) return;
|
if (value == room) return;
|
||||||
room = value;
|
room = value;
|
||||||
|
|
||||||
nameBind.BindTo(Room.Name);
|
nameBind.UnbindBindings();
|
||||||
hostBind.BindTo(Room.Host);
|
hostBind.UnbindBindings();
|
||||||
statusBind.BindTo(Room.Status);
|
statusBind.UnbindBindings();
|
||||||
typeBind.BindTo(Room.Type);
|
typeBind.UnbindBindings();
|
||||||
beatmapBind.BindTo(Room.Beatmap);
|
beatmapBind.UnbindBindings();
|
||||||
maxParticipantsBind.BindTo(Room.MaxParticipants);
|
maxParticipantsBind.UnbindBindings();
|
||||||
participantsBind.BindTo(Room.Participants);
|
participantsBind.UnbindBindings();
|
||||||
|
|
||||||
|
if (room != null)
|
||||||
|
{
|
||||||
|
nameBind.BindTo(room.Name);
|
||||||
|
hostBind.BindTo(room.Host);
|
||||||
|
statusBind.BindTo(room.Status);
|
||||||
|
typeBind.BindTo(room.Type);
|
||||||
|
beatmapBind.BindTo(room.Beatmap);
|
||||||
|
maxParticipantsBind.BindTo(room.MaxParticipants);
|
||||||
|
participantsBind.BindTo(room.Participants);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public RoomInspector()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours, LocalisationEngine localisation)
|
||||||
{
|
{
|
||||||
Width = 520;
|
this.colours = colours;
|
||||||
RelativeSizeAxes = Axes.Y;
|
|
||||||
|
ModeTypeInfo modeTypeInfo;
|
||||||
|
OsuSpriteText participants, participantsSlash, maxParticipants, beatmapTitle, beatmapDash, beatmapArtist, beatmapAuthor;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -120,7 +132,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
Padding = new MarginPadding(20),
|
Padding = new MarginPadding(20),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
participantNumbersFlow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
@ -178,6 +190,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
|
LayoutDuration = transition_duration,
|
||||||
Padding = contentPadding,
|
Padding = contentPadding,
|
||||||
Spacing = new Vector2(0f, 5f),
|
Spacing = new Vector2(0f, 5f),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -187,7 +200,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
TextSize = 14,
|
TextSize = 14,
|
||||||
Font = @"Exo2.0-Bold",
|
Font = @"Exo2.0-Bold",
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
infoPanelFlow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Height = 30,
|
Height = 30,
|
||||||
@ -229,6 +242,7 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
TextSize = 14,
|
TextSize = 14,
|
||||||
|
Colour = colours.Gray9,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -269,27 +283,68 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
nameBind.ValueChanged += displayName;
|
nameBind.ValueChanged += n => name.Text = n;
|
||||||
hostBind.ValueChanged += displayUser;
|
hostBind.ValueChanged += h => participantInfo.Host = h;
|
||||||
typeBind.ValueChanged += displayGameType;
|
typeBind.ValueChanged += t => modeTypeInfo.Type = t;
|
||||||
maxParticipantsBind.ValueChanged += displayMaxParticipants;
|
|
||||||
participantsBind.ValueChanged += displayParticipants;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours, LocalisationEngine localisation)
|
|
||||||
{
|
|
||||||
this.localisation = localisation;
|
|
||||||
this.colours = colours;
|
|
||||||
|
|
||||||
beatmapAuthor.Colour = colours.Gray9;
|
|
||||||
|
|
||||||
//binded here instead of ctor because dependencies are needed
|
|
||||||
statusBind.ValueChanged += displayStatus;
|
statusBind.ValueChanged += displayStatus;
|
||||||
beatmapBind.ValueChanged += displayBeatmap;
|
|
||||||
|
|
||||||
statusBind.TriggerChange();
|
beatmapBind.ValueChanged += b =>
|
||||||
beatmapBind.TriggerChange();
|
{
|
||||||
|
modeTypeInfo.Beatmap = b;
|
||||||
|
|
||||||
|
if (b != null)
|
||||||
|
{
|
||||||
|
coverContainer.FadeIn(transition_duration);
|
||||||
|
|
||||||
|
LoadComponentAsync(new BeatmapSetCover(b.BeatmapSet)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
FillMode = FillMode.Fill,
|
||||||
|
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
||||||
|
}, coverContainer.Add);
|
||||||
|
|
||||||
|
beatmapTitle.Current = localisation.GetUnicodePreference(b.Metadata.TitleUnicode, b.Metadata.Title);
|
||||||
|
beatmapDash.Text = @" - ";
|
||||||
|
beatmapArtist.Current = localisation.GetUnicodePreference(b.Metadata.ArtistUnicode, b.Metadata.Artist);
|
||||||
|
beatmapAuthor.Text = $"mapped by {b.Metadata.Author}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
coverContainer.FadeOut(transition_duration);
|
||||||
|
|
||||||
|
beatmapTitle.Current = null;
|
||||||
|
beatmapArtist.Current = null;
|
||||||
|
|
||||||
|
beatmapTitle.Text = "Changing map";
|
||||||
|
beatmapDash.Text = beatmapArtist.Text = beatmapAuthor.Text = string.Empty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
maxParticipantsBind.ValueChanged += m =>
|
||||||
|
{
|
||||||
|
if (m == null)
|
||||||
|
{
|
||||||
|
participantsSlash.FadeOut(transition_duration);
|
||||||
|
maxParticipants.FadeOut(transition_duration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
participantsSlash.FadeIn(transition_duration);
|
||||||
|
maxParticipants.FadeIn(transition_duration);
|
||||||
|
maxParticipants.Text = m.ToString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
participantsBind.ValueChanged += p =>
|
||||||
|
{
|
||||||
|
participants.Text = p.Length.ToString();
|
||||||
|
participantInfo.Participants = p;
|
||||||
|
participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u));
|
||||||
|
};
|
||||||
|
|
||||||
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
@ -299,84 +354,39 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
participantsScroll.Height = DrawHeight - topFlow.DrawHeight;
|
participantsScroll.Height = DrawHeight - topFlow.DrawHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayName(string value)
|
private void displayStatus(RoomStatus s)
|
||||||
{
|
{
|
||||||
name.Text = value;
|
status.Text = s.Message;
|
||||||
|
|
||||||
|
Color4 c = s.GetAppropriateColour(colours);
|
||||||
|
statusStrip.FadeColour(c, transition_duration);
|
||||||
|
status.FadeColour(c, transition_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayUser(User value)
|
private void updateState()
|
||||||
{
|
{
|
||||||
participantInfo.Host = value;
|
if (Room == null)
|
||||||
}
|
|
||||||
|
|
||||||
private void displayStatus(RoomStatus value)
|
|
||||||
{
|
|
||||||
status.Text = value.Message;
|
|
||||||
|
|
||||||
foreach (Drawable d in new Drawable[] { statusStrip, status })
|
|
||||||
d.FadeColour(value.GetAppropriateColour(colours), transition_duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayGameType(GameType value)
|
|
||||||
{
|
|
||||||
modeTypeInfo.Type = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayBeatmap(BeatmapInfo value)
|
|
||||||
{
|
|
||||||
modeTypeInfo.Beatmap = value;
|
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
coverContainer.FadeIn(transition_duration);
|
|
||||||
|
|
||||||
LoadComponentAsync(new BeatmapSetCover(value.BeatmapSet)
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
FillMode = FillMode.Fill,
|
|
||||||
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
|
||||||
},
|
|
||||||
coverContainer.Add);
|
|
||||||
|
|
||||||
beatmapTitle.Current = localisation.GetUnicodePreference(value.Metadata.TitleUnicode, value.Metadata.Title);
|
|
||||||
beatmapDash.Text = @" - ";
|
|
||||||
beatmapArtist.Current = localisation.GetUnicodePreference(value.Metadata.ArtistUnicode, value.Metadata.Artist);
|
|
||||||
beatmapAuthor.Text = $"mapped by {value.Metadata.Author}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
coverContainer.FadeOut(transition_duration);
|
coverContainer.FadeOut(transition_duration);
|
||||||
|
participantsFlow.FadeOut(transition_duration);
|
||||||
|
participantNumbersFlow.FadeOut(transition_duration);
|
||||||
|
infoPanelFlow.FadeOut(transition_duration);
|
||||||
|
name.FadeOut(transition_duration);
|
||||||
|
participantInfo.FadeOut(transition_duration);
|
||||||
|
|
||||||
beatmapTitle.Current = null;
|
displayStatus(new RoomStatusNoneSelected());
|
||||||
beatmapArtist.Current = null;
|
|
||||||
|
|
||||||
beatmapTitle.Text = "Changing map";
|
|
||||||
beatmapDash.Text = beatmapArtist.Text = beatmapAuthor.Text = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayMaxParticipants(int? value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
participantsSlash.FadeOut(transition_duration);
|
|
||||||
maxParticipants.FadeOut(transition_duration);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
participantsSlash.FadeIn(transition_duration);
|
participantsFlow.FadeIn(transition_duration);
|
||||||
maxParticipants.FadeIn(transition_duration);
|
participantNumbersFlow.FadeIn(transition_duration);
|
||||||
maxParticipants.Text = value.ToString();
|
infoPanelFlow.FadeIn(transition_duration);
|
||||||
}
|
name.FadeIn(transition_duration);
|
||||||
}
|
participantInfo.FadeIn(transition_duration);
|
||||||
|
|
||||||
private void displayParticipants(User[] value)
|
statusBind.TriggerChange();
|
||||||
{
|
beatmapBind.TriggerChange();
|
||||||
participants.Text = value.Length.ToString();
|
}
|
||||||
participantInfo.Participants = value;
|
|
||||||
participantsFlow.ChildrenEnumerable = value.Select(u => new UserTile(u));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UserTile : Container, IHasTooltip
|
private class UserTile : Container, IHasTooltip
|
||||||
@ -407,5 +417,11 @@ namespace osu.Game.Screens.Multi.Components
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RoomStatusNoneSelected : RoomStatus
|
||||||
|
{
|
||||||
|
public override string Message => @"No Room Selected";
|
||||||
|
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
112
osu.Game/Screens/Multi/Header.cs
Normal file
112
osu.Game/Screens/Multi/Header.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays.SearchableList;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Multi
|
||||||
|
{
|
||||||
|
public class Header : Container
|
||||||
|
{
|
||||||
|
public const float HEIGHT = 121;
|
||||||
|
|
||||||
|
private readonly OsuSpriteText screenTitle;
|
||||||
|
private readonly HeaderBreadcrumbControl breadcrumbs;
|
||||||
|
|
||||||
|
public Header(Screen initialScreen)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = HEIGHT;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuColour.FromHex(@"2f2043"),
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING },
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Position = new Vector2(-35f, 5f),
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10f, 0f),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SpriteIcon
|
||||||
|
{
|
||||||
|
Size = new Vector2(25),
|
||||||
|
Icon = FontAwesome.fa_osu_multi,
|
||||||
|
},
|
||||||
|
new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "multiplayer ",
|
||||||
|
TextSize = 25,
|
||||||
|
},
|
||||||
|
screenTitle = new OsuSpriteText
|
||||||
|
{
|
||||||
|
TextSize = 25,
|
||||||
|
Font = @"Exo2.0-Light",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
breadcrumbs = new HeaderBreadcrumbControl(initialScreen)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
breadcrumbs.Current.ValueChanged += s => screenTitle.Text = s.ToString();
|
||||||
|
breadcrumbs.Current.TriggerChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
screenTitle.Colour = colours.Yellow;
|
||||||
|
breadcrumbs.StripColour = colours.Green;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class HeaderBreadcrumbControl : ScreenBreadcrumbControl
|
||||||
|
{
|
||||||
|
public HeaderBreadcrumbControl(Screen initialScreen) : base(initialScreen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
AccentColour = Color4.White;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
osu.Game/Screens/Multi/Multiplayer.cs
Normal file
100
osu.Game/Screens/Multi/Multiplayer.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Screens;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Backgrounds;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Screens.Multi.Screens;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Multi
|
||||||
|
{
|
||||||
|
public class Multiplayer : OsuScreen
|
||||||
|
{
|
||||||
|
private readonly MultiplayerWaveContainer waves;
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => waves;
|
||||||
|
|
||||||
|
public Multiplayer()
|
||||||
|
{
|
||||||
|
InternalChild = waves = new MultiplayerWaveContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
|
||||||
|
Lobby lobby;
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuColour.FromHex(@"3e3a44"),
|
||||||
|
},
|
||||||
|
new Triangles
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
ColourLight = OsuColour.FromHex(@"3c3842"),
|
||||||
|
ColourDark = OsuColour.FromHex(@"393540"),
|
||||||
|
TriangleScale = 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Top = Header.HEIGHT },
|
||||||
|
Child = lobby = new Lobby(),
|
||||||
|
},
|
||||||
|
new Header(lobby),
|
||||||
|
};
|
||||||
|
|
||||||
|
lobby.Exited += s => Exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnEntering(Screen last)
|
||||||
|
{
|
||||||
|
base.OnEntering(last);
|
||||||
|
waves.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnExiting(Screen next)
|
||||||
|
{
|
||||||
|
waves.Hide();
|
||||||
|
return base.OnExiting(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResuming(Screen last)
|
||||||
|
{
|
||||||
|
base.OnResuming(last);
|
||||||
|
waves.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSuspending(Screen next)
|
||||||
|
{
|
||||||
|
base.OnSuspending(next);
|
||||||
|
waves.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MultiplayerWaveContainer : WaveContainer
|
||||||
|
{
|
||||||
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
|
public MultiplayerWaveContainer()
|
||||||
|
{
|
||||||
|
FirstWaveColour = OsuColour.FromHex(@"654d8c");
|
||||||
|
SecondWaveColour = OsuColour.FromHex(@"554075");
|
||||||
|
ThirdWaveColour = OsuColour.FromHex(@"44325e");
|
||||||
|
FourthWaveColour = OsuColour.FromHex(@"392850");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,37 +3,48 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Audio;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using OpenTK;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Audio;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
using osu.Framework.Input;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Screens
|
namespace osu.Game.Screens
|
||||||
{
|
{
|
||||||
public abstract class OsuScreen : Screen
|
public abstract class OsuScreen : Screen, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public BackgroundScreen Background { get; private set; }
|
public BackgroundScreen Background { get; private set; }
|
||||||
|
|
||||||
|
protected virtual bool AllowBackButton => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override to create a BackgroundMode for the current screen.
|
/// Override to create a BackgroundMode for the current screen.
|
||||||
/// Note that the instance created may not be the used instance if it matches the BackgroundMode equality clause.
|
/// Note that the instance created may not be the used instance if it matches the BackgroundMode equality clause.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual BackgroundScreen CreateBackground() => null;
|
protected virtual BackgroundScreen CreateBackground() => null;
|
||||||
|
|
||||||
protected BindableBool ShowOverlays = new BindableBool();
|
private readonly BindableBool hideOverlaysOnEnter = new BindableBool();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether overlays should be shown when this screen is entered or resumed.
|
/// Whether overlays should be hidden when this screen is entered or resumed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool ShowOverlaysOnEnter => true;
|
protected virtual bool HideOverlaysOnEnter => hideOverlaysOnEnter;
|
||||||
|
|
||||||
|
private readonly BindableBool allowOpeningOverlays = new BindableBool();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether overlays should be able to be opened while this screen is active.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool AllowOpeningOverlays => allowOpeningOverlays;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="OsuScreen"/> allows the cursor to be displayed.
|
/// Whether this <see cref="OsuScreen"/> allows the cursor to be displayed.
|
||||||
@ -84,12 +95,26 @@ namespace osu.Game.Screens
|
|||||||
if (osuGame != null)
|
if (osuGame != null)
|
||||||
{
|
{
|
||||||
Ruleset.BindTo(osuGame.Ruleset);
|
Ruleset.BindTo(osuGame.Ruleset);
|
||||||
ShowOverlays.BindTo(osuGame.ShowOverlays);
|
hideOverlaysOnEnter.BindTo(osuGame.HideOverlaysOnEnter);
|
||||||
|
allowOpeningOverlays.BindTo(osuGame.AllowOpeningOverlays);
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleExit = audio.Sample.Get(@"UI/screen-back");
|
sampleExit = audio.Sample.Get(@"UI/screen-back");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action == GlobalAction.Back && AllowBackButton)
|
||||||
|
{
|
||||||
|
Exit();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
|
||||||
|
|
||||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.Repeat || !IsCurrentScreen) return false;
|
if (args.Repeat || !IsCurrentScreen) return false;
|
||||||
@ -203,7 +228,8 @@ namespace osu.Game.Screens
|
|||||||
if (backgroundParallaxContainer != null)
|
if (backgroundParallaxContainer != null)
|
||||||
backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount;
|
backgroundParallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * BackgroundParallaxAmount;
|
||||||
|
|
||||||
ShowOverlays.Value = ShowOverlaysOnEnter;
|
hideOverlaysOnEnter.Value = HideOverlaysOnEnter;
|
||||||
|
allowOpeningOverlays.Value = AllowOpeningOverlays;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExitingLogo()
|
private void onExitingLogo()
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
protected override float BackgroundParallaxAmount => 0.1f;
|
protected override float BackgroundParallaxAmount => 0.1f;
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => false;
|
protected override bool HideOverlaysOnEnter => true;
|
||||||
|
|
||||||
public Action RestartRequested;
|
public Action RestartRequested;
|
||||||
|
|
||||||
@ -45,6 +45,8 @@ namespace osu.Game.Screens.Play
|
|||||||
public bool AllowLeadIn { get; set; } = true;
|
public bool AllowLeadIn { get; set; } = true;
|
||||||
public bool AllowResults { get; set; } = true;
|
public bool AllowResults { get; set; } = true;
|
||||||
|
|
||||||
|
protected override bool AllowBackButton => false;
|
||||||
|
|
||||||
private Bindable<bool> mouseWheelDisabled;
|
private Bindable<bool> mouseWheelDisabled;
|
||||||
private Bindable<double> userAudioOffset;
|
private Bindable<double> userAudioOffset;
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private BeatmapMetadataDisplay info;
|
private BeatmapMetadataDisplay info;
|
||||||
|
|
||||||
private bool showOverlays = true;
|
private bool hideOverlays;
|
||||||
public override bool ShowOverlaysOnEnter => showOverlays;
|
protected override bool HideOverlaysOnEnter => hideOverlays;
|
||||||
|
|
||||||
private Task loadTask;
|
private Task loadTask;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
player.RestartRequested = () =>
|
player.RestartRequested = () =>
|
||||||
{
|
{
|
||||||
showOverlays = false;
|
hideOverlays = true;
|
||||||
ValidForResume = true;
|
ValidForResume = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,5 @@ namespace osu.Game.Screens.Select
|
|||||||
protected override bool OnMouseMove(InputState state) => true;
|
protected override bool OnMouseMove(InputState state) => true;
|
||||||
|
|
||||||
protected override bool OnClick(InputState state) => true;
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state) => true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,5 @@ namespace osu.Game.Screens.Select
|
|||||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
|
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
|
||||||
|
|
||||||
protected override bool OnClick(InputState state) => true;
|
protected override bool OnClick(InputState state) => true;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state) => true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,12 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
protected override bool OnSelectionFinalised()
|
protected override bool OnSelectionFinalised()
|
||||||
{
|
{
|
||||||
Exit();
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
// needs to be scheduled else we enter an infinite feedback loop.
|
||||||
|
if (IsCurrentScreen) Exit();
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Screens.Tournament
|
|||||||
{
|
{
|
||||||
private const string results_filename = "drawings_results.txt";
|
private const string results_filename = "drawings_results.txt";
|
||||||
|
|
||||||
public override bool ShowOverlaysOnEnter => false;
|
protected override bool HideOverlaysOnEnter => true;
|
||||||
|
|
||||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
|
protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user