mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 16:52:54 +08:00
Merge branch 'master' into ismaskedaway-input-fix
This commit is contained in:
commit
9d4ec6f8b5
@ -1 +1 @@
|
|||||||
Subproject commit 266965f0d795b94a126e2da302bd2c10eadd642a
|
Subproject commit 92ec3d10b12c5e9bfc1d3b05d3db174a506efd6d
|
@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
{
|
{
|
||||||
if (CheckPosition == null) return;
|
if (CheckPosition == null) return;
|
||||||
|
|
||||||
if (timeOffset > 0)
|
if (timeOffset >= 0)
|
||||||
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
|
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
|||||||
AddNested(getVisualRepresentation?.Invoke(o));
|
AddNested(getVisualRepresentation?.Invoke(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool ProvidesJudgement => false;
|
||||||
|
|
||||||
protected override void AddNested(DrawableHitObject h)
|
protected override void AddNested(DrawableHitObject h)
|
||||||
{
|
{
|
||||||
var catchObject = (DrawableCatchHitObject)h;
|
var catchObject = (DrawableCatchHitObject)h;
|
||||||
|
@ -24,17 +24,13 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
|||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case JuiceStream stream:
|
case JuiceStream stream:
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
|
||||||
|
|
||||||
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
|
foreach (var _ in stream.NestedHitObjects.Cast<CatchHitObject>())
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||||
break;
|
break;
|
||||||
case BananaShower shower:
|
case BananaShower shower:
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
|
||||||
|
|
||||||
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
|
foreach (var _ in shower.NestedHitObjects.Cast<CatchHitObject>())
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||||
|
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||||
break;
|
break;
|
||||||
case Fruit _:
|
case Fruit _:
|
||||||
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
AddJudgement(new CatchJudgement { Result = HitResult.Perfect });
|
||||||
|
13
osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
Normal file
13
osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.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.Osu.Judgements
|
||||||
|
{
|
||||||
|
public class OsuSliderTailJudgement : OsuJudgement
|
||||||
|
{
|
||||||
|
public override bool AffectsCombo => false;
|
||||||
|
protected override int NumericResultFor(HitResult result) => 0;
|
||||||
|
}
|
||||||
|
}
|
@ -18,14 +18,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
|
public class DrawableSlider : DrawableOsuHitObject, IDrawableHitObjectWithProxiedApproach
|
||||||
{
|
{
|
||||||
private readonly Slider slider;
|
private readonly Slider slider;
|
||||||
|
|
||||||
public readonly DrawableHitCircle InitialCircle;
|
|
||||||
|
|
||||||
private readonly List<Drawable> components = new List<Drawable>();
|
private readonly List<Drawable> components = new List<Drawable>();
|
||||||
|
|
||||||
private readonly Container<DrawableSliderTick> ticks;
|
public readonly DrawableHitCircle HeadCircle;
|
||||||
private readonly Container<DrawableRepeatPoint> repeatPoints;
|
|
||||||
|
|
||||||
public readonly SliderBody Body;
|
public readonly SliderBody Body;
|
||||||
public readonly SliderBall Ball;
|
public readonly SliderBall Ball;
|
||||||
|
|
||||||
@ -34,6 +29,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
slider = s;
|
slider = s;
|
||||||
|
|
||||||
|
DrawableSliderTail tail;
|
||||||
|
Container<DrawableSliderTick> ticks;
|
||||||
|
Container<DrawableRepeatPoint> repeatPoints;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Body = new SliderBody(s)
|
Body = new SliderBody(s)
|
||||||
@ -51,42 +50,27 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
AlwaysPresent = true,
|
AlwaysPresent = true,
|
||||||
Alpha = 0
|
Alpha = 0
|
||||||
},
|
},
|
||||||
InitialCircle = new DrawableHitCircle(new HitCircle
|
HeadCircle = new DrawableHitCircle(s.HeadCircle),
|
||||||
{
|
tail = new DrawableSliderTail(s.TailCircle)
|
||||||
StartTime = s.StartTime,
|
|
||||||
Position = s.StackedPosition,
|
|
||||||
IndexInCurrentCombo = s.IndexInCurrentCombo,
|
|
||||||
Scale = s.Scale,
|
|
||||||
ComboColour = s.ComboColour,
|
|
||||||
Samples = s.Samples,
|
|
||||||
SampleControlPoint = s.SampleControlPoint,
|
|
||||||
TimePreempt = s.TimePreempt,
|
|
||||||
TimeFadein = s.TimeFadein,
|
|
||||||
HitWindow300 = s.HitWindow300,
|
|
||||||
HitWindow100 = s.HitWindow100,
|
|
||||||
HitWindow50 = s.HitWindow50
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
components.Add(Body);
|
components.Add(Body);
|
||||||
components.Add(Ball);
|
components.Add(Ball);
|
||||||
|
|
||||||
AddNested(InitialCircle);
|
AddNested(HeadCircle);
|
||||||
|
|
||||||
|
AddNested(tail);
|
||||||
|
components.Add(tail);
|
||||||
|
|
||||||
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
|
foreach (var tick in s.NestedHitObjects.OfType<SliderTick>())
|
||||||
{
|
{
|
||||||
var spanStartTime = s.StartTime + tick.SpanIndex * s.SpanDuration;
|
|
||||||
var fadeInTime = spanStartTime + (tick.StartTime - spanStartTime) / 2 - (tick.SpanIndex == 0 ? HitObject.TimeFadein : HitObject.TimeFadein / 2);
|
|
||||||
var fadeOutTime = spanStartTime + s.SpanDuration;
|
|
||||||
|
|
||||||
var drawableTick = new DrawableSliderTick(tick)
|
var drawableTick = new DrawableSliderTick(tick)
|
||||||
{
|
{
|
||||||
FadeInTime = fadeInTime,
|
Position = tick.Position
|
||||||
FadeOutTime = fadeOutTime,
|
|
||||||
Position = tick.Position,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ticks.Add(drawableTick);
|
ticks.Add(drawableTick);
|
||||||
|
components.Add(drawableTick);
|
||||||
AddNested(drawableTick);
|
AddNested(drawableTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,27 +105,25 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
currentSpan = span;
|
currentSpan = span;
|
||||||
|
|
||||||
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
|
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
|
||||||
if (!InitialCircle.Judgements.Any(j => j.IsHit))
|
if (!HeadCircle.IsHit)
|
||||||
InitialCircle.Position = slider.Curve.PositionAt(progress);
|
HeadCircle.Position = slider.Curve.PositionAt(progress);
|
||||||
|
|
||||||
foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(progress, span);
|
foreach (var c in components.OfType<ISliderProgress>()) c.UpdateProgress(progress, span);
|
||||||
foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
|
foreach (var c in components.OfType<ITrackSnaking>()) c.UpdateSnakingPosition(slider.Curve.PositionAt(Body.SnakedStart ?? 0), slider.Curve.PositionAt(Body.SnakedEnd ?? 0));
|
||||||
foreach (var t in ticks.Children) t.Tracking = Ball.Tracking;
|
foreach (var t in components.OfType<IRequireTracking>()) t.Tracking = Ball.Tracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered && Time.Current >= slider.EndTime)
|
if (!userTriggered && Time.Current >= slider.EndTime)
|
||||||
{
|
{
|
||||||
var judgementsCount = ticks.Children.Count + repeatPoints.Children.Count + 1;
|
var judgementsCount = NestedHitObjects.Count;
|
||||||
var judgementsHit = ticks.Children.Count(t => t.Judgements.Any(j => j.IsHit)) + repeatPoints.Children.Count(t => t.Judgements.Any(j => j.IsHit));
|
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
|
||||||
if (InitialCircle.Judgements.Any(j => j.IsHit))
|
|
||||||
judgementsHit++;
|
|
||||||
|
|
||||||
var hitFraction = (double)judgementsHit / judgementsCount;
|
var hitFraction = (double)judgementsHit / judgementsCount;
|
||||||
if (hitFraction == 1 && InitialCircle.Judgements.Any(j => j.Result == HitResult.Great))
|
if (hitFraction == 1 && HeadCircle.Judgements.Any(j => j.Result == HitResult.Great))
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
AddJudgement(new OsuJudgement { Result = HitResult.Great });
|
||||||
else if (hitFraction >= 0.5 && InitialCircle.Judgements.Any(j => j.Result >= HitResult.Good))
|
else if (hitFraction >= 0.5 && HeadCircle.Judgements.Any(j => j.Result >= HitResult.Good))
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
AddJudgement(new OsuJudgement { Result = HitResult.Good });
|
||||||
else if (hitFraction > 0)
|
else if (hitFraction > 0)
|
||||||
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
AddJudgement(new OsuJudgement { Result = HitResult.Meh });
|
||||||
@ -173,7 +155,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable ProxiedLayer => InitialCircle.ApproachCircle;
|
public Drawable ProxiedLayer => HeadCircle.ApproachCircle;
|
||||||
|
|
||||||
public override Vector2 SelectionPoint => ToScreenSpace(Body.Position);
|
public override Vector2 SelectionPoint => ToScreenSpace(Body.Position);
|
||||||
public override Quad SelectionQuad => Body.PathDrawQuad;
|
public override Quad SelectionQuad => Body.PathDrawQuad;
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
// 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.Game.Rulesets.Osu.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
|
{
|
||||||
|
public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The judgement text is provided by the <see cref="DrawableSlider"/>.
|
||||||
|
/// </summary>
|
||||||
|
public override bool DisplayJudgement => false;
|
||||||
|
|
||||||
|
public bool Tracking { get; set; }
|
||||||
|
|
||||||
|
public DrawableSliderTail(HitCircle hitCircle)
|
||||||
|
: base(hitCircle)
|
||||||
|
{
|
||||||
|
AlwaysPresent = true;
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||||
|
{
|
||||||
|
if (!userTriggered && timeOffset >= 0)
|
||||||
|
AddJudgement(new OsuSliderTailJudgement { Result = Tracking ? HitResult.Great : HitResult.Miss });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
@ -12,21 +11,16 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableSliderTick : DrawableOsuHitObject
|
public class DrawableSliderTick : DrawableOsuHitObject, IRequireTracking
|
||||||
{
|
{
|
||||||
private readonly SliderTick sliderTick;
|
private const double anim_duration = 150;
|
||||||
|
|
||||||
public double FadeInTime;
|
public bool Tracking { get; set; }
|
||||||
public double FadeOutTime;
|
|
||||||
|
|
||||||
public bool Tracking;
|
|
||||||
|
|
||||||
public override bool DisplayJudgement => false;
|
public override bool DisplayJudgement => false;
|
||||||
|
|
||||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||||
{
|
{
|
||||||
this.sliderTick = sliderTick;
|
|
||||||
|
|
||||||
Size = new Vector2(16) * sliderTick.Scale;
|
Size = new Vector2(16) * sliderTick.Scale;
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
@ -56,13 +50,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
protected override void UpdatePreemptState()
|
protected override void UpdatePreemptState()
|
||||||
{
|
{
|
||||||
var animIn = Math.Min(150, sliderTick.StartTime - FadeInTime);
|
|
||||||
|
|
||||||
this.Animate(
|
this.Animate(
|
||||||
d => d.FadeIn(animIn),
|
d => d.FadeIn(anim_duration),
|
||||||
d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn)
|
d => d.ScaleTo(0.5f).ScaleTo(1.2f, anim_duration / 2)
|
||||||
).Then(
|
).Then(
|
||||||
d => d.ScaleTo(1, 150, Easing.Out)
|
d => d.ScaleTo(1, anim_duration / 2, Easing.Out)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,15 +63,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case ArmedState.Idle:
|
case ArmedState.Idle:
|
||||||
this.Delay(FadeOutTime - sliderTick.StartTime).FadeOut();
|
this.Delay(HitObject.TimePreempt).FadeOut();
|
||||||
break;
|
break;
|
||||||
case ArmedState.Miss:
|
case ArmedState.Miss:
|
||||||
this.FadeOut(160)
|
this.FadeOut(anim_duration)
|
||||||
.FadeColour(Color4.Red, 80);
|
.FadeColour(Color4.Red, anim_duration / 2);
|
||||||
break;
|
break;
|
||||||
case ArmedState.Hit:
|
case ArmedState.Hit:
|
||||||
this.FadeOut(120, Easing.OutQuint)
|
this.FadeOut(anim_duration, Easing.OutQuint)
|
||||||
.ScaleTo(Scale * 1.5f, 120, Easing.OutQuint);
|
.ScaleTo(Scale * 1.5f, anim_duration, Easing.OutQuint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
osu.Game.Rulesets.Osu/Objects/Drawables/IRequireTracking.cs
Normal file
13
osu.Game.Rulesets.Osu/Objects/Drawables/IRequireTracking.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
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
|
{
|
||||||
|
public interface IRequireTracking
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the <see cref="DrawableSlider"/> is currently being tracked by the user.
|
||||||
|
/// </summary>
|
||||||
|
bool Tracking { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -80,6 +80,9 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public double Velocity;
|
public double Velocity;
|
||||||
public double TickDistance;
|
public double TickDistance;
|
||||||
|
|
||||||
|
public HitCircle HeadCircle;
|
||||||
|
public HitCircle TailCircle;
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
@ -97,10 +100,37 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
base.CreateNestedHitObjects();
|
base.CreateNestedHitObjects();
|
||||||
|
|
||||||
|
createSliderEnds();
|
||||||
createTicks();
|
createTicks();
|
||||||
createRepeatPoints();
|
createRepeatPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createSliderEnds()
|
||||||
|
{
|
||||||
|
HeadCircle = new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = StartTime,
|
||||||
|
Position = StackedPosition,
|
||||||
|
IndexInCurrentCombo = IndexInCurrentCombo,
|
||||||
|
ComboColour = ComboColour,
|
||||||
|
Samples = Samples,
|
||||||
|
SampleControlPoint = SampleControlPoint
|
||||||
|
};
|
||||||
|
|
||||||
|
TailCircle = new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = EndTime,
|
||||||
|
Position = StackedEndPosition,
|
||||||
|
IndexInCurrentCombo = IndexInCurrentCombo,
|
||||||
|
ComboColour = ComboColour,
|
||||||
|
Samples = Samples,
|
||||||
|
SampleControlPoint = SampleControlPoint
|
||||||
|
};
|
||||||
|
|
||||||
|
AddNested(HeadCircle);
|
||||||
|
AddNested(TailCircle);
|
||||||
|
}
|
||||||
|
|
||||||
private void createTicks()
|
private void createTicks()
|
||||||
{
|
{
|
||||||
if (TickDistance == 0) return;
|
if (TickDistance == 0) return;
|
||||||
@ -137,6 +167,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
AddNested(new SliderTick
|
AddNested(new SliderTick
|
||||||
{
|
{
|
||||||
SpanIndex = span,
|
SpanIndex = span,
|
||||||
|
SpanStartTime = spanStartTime,
|
||||||
StartTime = spanStartTime + timeProgress * SpanDuration,
|
StartTime = spanStartTime + timeProgress * SpanDuration,
|
||||||
Position = Curve.PositionAt(distanceProgress),
|
Position = Curve.PositionAt(distanceProgress),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
|
@ -1,10 +1,30 @@
|
|||||||
// 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;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects
|
namespace osu.Game.Rulesets.Osu.Objects
|
||||||
{
|
{
|
||||||
public class SliderTick : OsuHitObject
|
public class SliderTick : OsuHitObject
|
||||||
{
|
{
|
||||||
public int SpanIndex { get; set; }
|
public int SpanIndex { get; set; }
|
||||||
|
public double SpanStartTime { get; set; }
|
||||||
|
|
||||||
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
|
{
|
||||||
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
|
|
||||||
|
double offset;
|
||||||
|
|
||||||
|
if (SpanIndex > 0)
|
||||||
|
// Adding 200 to include the offset stable used.
|
||||||
|
// This is so on repeats ticks don't appear too late to be visually processed by the player.
|
||||||
|
offset = 200;
|
||||||
|
else
|
||||||
|
offset = TimeFadein * 0.66f;
|
||||||
|
|
||||||
|
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@ using OpenTK;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Tests
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
@ -27,7 +30,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
typeof(SliderBall),
|
typeof(SliderBall),
|
||||||
typeof(SliderBody),
|
typeof(SliderBody),
|
||||||
|
typeof(SliderTick),
|
||||||
typeof(DrawableSlider),
|
typeof(DrawableSlider),
|
||||||
|
typeof(DrawableSliderTick),
|
||||||
typeof(DrawableRepeatPoint),
|
typeof(DrawableRepeatPoint),
|
||||||
typeof(DrawableOsuHitObject)
|
typeof(DrawableOsuHitObject)
|
||||||
};
|
};
|
||||||
@ -131,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
var cpi = new ControlPointInfo();
|
var cpi = new ControlPointInfo();
|
||||||
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
|
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
|
||||||
|
|
||||||
slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize });
|
slider.ApplyDefaults(cpi, new BeatmapDifficulty { CircleSize = circleSize, SliderTickRate = 3 });
|
||||||
|
|
||||||
var drawable = new DrawableSlider(slider)
|
var drawable = new DrawableSlider(slider)
|
||||||
{
|
{
|
||||||
@ -142,7 +147,34 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
|
foreach (var mod in Mods.OfType<IApplicableToDrawableHitObjects>())
|
||||||
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
mod.ApplyToDrawableHitObjects(new[] { drawable });
|
||||||
|
|
||||||
|
drawable.OnJudgement += onJudgement;
|
||||||
|
|
||||||
Add(drawable);
|
Add(drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float judgementOffsetDirection = 1;
|
||||||
|
private void onJudgement(DrawableHitObject judgedObject, Judgement judgement)
|
||||||
|
{
|
||||||
|
var osuObject = judgedObject as DrawableOsuHitObject;
|
||||||
|
if (osuObject == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
OsuSpriteText text;
|
||||||
|
Add(text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Text = judgement.IsHit ? "Hit!" : "Miss!",
|
||||||
|
Colour = judgement.IsHit ? Color4.Green : Color4.Red,
|
||||||
|
TextSize = 30,
|
||||||
|
Position = osuObject.HitObject.StackedEndPosition + judgementOffsetDirection * new Vector2(0, 45)
|
||||||
|
});
|
||||||
|
|
||||||
|
text.Delay(150)
|
||||||
|
.Then().FadeOut(200)
|
||||||
|
.Then().Expire();
|
||||||
|
|
||||||
|
judgementOffsetDirection *= -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
<Compile Include="Edit\OsuEditPlayfield.cs" />
|
<Compile Include="Edit\OsuEditPlayfield.cs" />
|
||||||
<Compile Include="Edit\OsuEditRulesetContainer.cs" />
|
<Compile Include="Edit\OsuEditRulesetContainer.cs" />
|
||||||
<Compile Include="Edit\OsuHitObjectComposer.cs" />
|
<Compile Include="Edit\OsuHitObjectComposer.cs" />
|
||||||
|
<Compile Include="Judgements\OsuSliderTailJudgement.cs" />
|
||||||
<Compile Include="Mods\OsuModAutopilot.cs" />
|
<Compile Include="Mods\OsuModAutopilot.cs" />
|
||||||
<Compile Include="Mods\OsuModAutoplay.cs" />
|
<Compile Include="Mods\OsuModAutoplay.cs" />
|
||||||
<Compile Include="Mods\OsuModDaycore.cs" />
|
<Compile Include="Mods\OsuModDaycore.cs" />
|
||||||
@ -75,6 +76,8 @@
|
|||||||
<Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
|
<Compile Include="Objects\Drawables\Connections\FollowPointRenderer.cs" />
|
||||||
<Compile Include="Judgements\OsuJudgement.cs" />
|
<Compile Include="Judgements\OsuJudgement.cs" />
|
||||||
<Compile Include="Objects\Drawables\DrawableRepeatPoint.cs" />
|
<Compile Include="Objects\Drawables\DrawableRepeatPoint.cs" />
|
||||||
|
<Compile Include="Objects\Drawables\DrawableSliderTail.cs" />
|
||||||
|
<Compile Include="Objects\Drawables\IRequireTracking.cs" />
|
||||||
<Compile Include="Objects\Drawables\ITrackSnaking.cs" />
|
<Compile Include="Objects\Drawables\ITrackSnaking.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
|
<Compile Include="Objects\Drawables\Pieces\ApproachCircle.cs" />
|
||||||
<Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
|
<Compile Include="Objects\Drawables\Pieces\SpinnerBackground.cs" />
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Taiko fails at the end of the map if the player has not half-filled their HP bar.
|
/// Taiko fails at the end of the map if the player has not half-filled their HP bar.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected override bool DefaultFailCondition => Hits == MaxHits && Health.Value <= 0.5;
|
protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5;
|
||||||
|
|
||||||
private double hpIncreaseTick;
|
private double hpIncreaseTick;
|
||||||
private double hpIncreaseGreat;
|
private double hpIncreaseGreat;
|
||||||
|
247
osu.Game.Tests/Chat/MessageFormatterTests.cs
Normal file
247
osu.Game.Tests/Chat/MessageFormatterTests.cs
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
// 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.Online.Chat;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Chat
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class MessageFormatterTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestBareLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a http://www.basic-link.com/?test=test." });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("http://www.basic-link.com/?test=test", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(36, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleComplexLinks()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a http://test.io/link#fragment. (see https://twitter.com). Also, This string should not be altered. http://example.com/" });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(3, result.Links.Count);
|
||||||
|
|
||||||
|
Assert.AreEqual("http://test.io/link#fragment", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(28, result.Links[0].Length);
|
||||||
|
|
||||||
|
Assert.AreEqual("https://twitter.com", result.Links[1].Url);
|
||||||
|
Assert.AreEqual(45, result.Links[1].Index);
|
||||||
|
Assert.AreEqual(19, result.Links[1].Length);
|
||||||
|
|
||||||
|
Assert.AreEqual("http://example.com/", result.Links[2].Url);
|
||||||
|
Assert.AreEqual(108, result.Links[2].Index);
|
||||||
|
Assert.AreEqual(19, result.Links[2].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAjaxLinks()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "https://twitter.com/#!/hashbanglinks" });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(result.Content, result.Links[0].Url);
|
||||||
|
Assert.AreEqual(0, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(36, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUnixHomeLinks()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "http://www.chiark.greenend.org.uk/~sgtatham/putty/" });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(result.Content, result.Links[0].Url);
|
||||||
|
Assert.AreEqual(0, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(50, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCaseInsensitiveLinks()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "look: http://puu.sh/7Ggh8xcC6/asf0asd9876.NEF" });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(6, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(39, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestWikiLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [[Wiki Link]]." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a Wiki Link.", result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(9, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultiWikiLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [[Wiki Link]] [[Wiki:Link]][[Wiki.Link]]." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent);
|
||||||
|
Assert.AreEqual(3, result.Links.Count);
|
||||||
|
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(9, result.Links[0].Length);
|
||||||
|
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki:Link", result.Links[1].Url);
|
||||||
|
Assert.AreEqual(20, result.Links[1].Index);
|
||||||
|
Assert.AreEqual(9, result.Links[1].Length);
|
||||||
|
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh/wiki/Wiki.Link", result.Links[2].Url);
|
||||||
|
Assert.AreEqual(29, result.Links[2].Index);
|
||||||
|
Assert.AreEqual(9, result.Links[2].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOldFormatLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a (simple test)[https://osu.ppy.sh] of links." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a simple test of links.", result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(11, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNewFormatLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh simple test]." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a simple test.", result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(11, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMarkdownFormatLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [simple test](https://osu.ppy.sh)." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a simple test.", result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(11, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChannelLink()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is an #english and #japanese." });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(2, result.Links.Count);
|
||||||
|
Assert.AreEqual("osu://chan/#english", result.Links[0].Url);
|
||||||
|
Assert.AreEqual("osu://chan/#japanese", result.Links[1].Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOsuProtocol()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a custom protocol osu://chan/#english." });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("osu://chan/#english", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(26, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(19, result.Links[0].Length);
|
||||||
|
|
||||||
|
result = MessageFormatter.FormatMessage(new Message { Content = "This is a [custom protocol](osu://chan/#english)." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a custom protocol.", result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("osu://chan/#english", result.Links[0].Url);
|
||||||
|
Assert.AreEqual("#english", result.Links[0].Argument);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(15, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestOsuMpProtocol()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "Join my multiplayer game osump://12346." });
|
||||||
|
|
||||||
|
Assert.AreEqual(result.Content, result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("osump://12346", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(25, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(13, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestRecursiveBreaking()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [https://osu.ppy.sh [[simple test]]]." });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a [[simple test]].", result.DisplayContent);
|
||||||
|
Assert.AreEqual(1, result.Links.Count);
|
||||||
|
Assert.AreEqual("https://osu.ppy.sh", result.Links[0].Url);
|
||||||
|
Assert.AreEqual(10, result.Links[0].Index);
|
||||||
|
Assert.AreEqual(15, result.Links[0].Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLinkComplex()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a [http://www.simple-test.com simple test] with some [traps] and [[wiki links]]. Don't forget to visit https://osu.ppy.sh (now!)[http://google.com]\uD83D\uDE12" });
|
||||||
|
|
||||||
|
Assert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now!\0\0\0", result.DisplayContent);
|
||||||
|
Assert.AreEqual(5, result.Links.Count);
|
||||||
|
|
||||||
|
Link f = result.Links.Find(l => l.Url == "https://osu.ppy.sh/wiki/wiki links");
|
||||||
|
Assert.AreEqual(44, f.Index);
|
||||||
|
Assert.AreEqual(10, f.Length);
|
||||||
|
|
||||||
|
f = result.Links.Find(l => l.Url == "http://www.simple-test.com");
|
||||||
|
Assert.AreEqual(10, f.Index);
|
||||||
|
Assert.AreEqual(11, f.Length);
|
||||||
|
|
||||||
|
f = result.Links.Find(l => l.Url == "http://google.com");
|
||||||
|
Assert.AreEqual(97, f.Index);
|
||||||
|
Assert.AreEqual(4, f.Length);
|
||||||
|
|
||||||
|
f = result.Links.Find(l => l.Url == "https://osu.ppy.sh");
|
||||||
|
Assert.AreEqual(78, f.Index);
|
||||||
|
Assert.AreEqual(18, f.Length);
|
||||||
|
|
||||||
|
f = result.Links.Find(l => l.Url == "\uD83D\uDE12");
|
||||||
|
Assert.AreEqual(101, f.Index);
|
||||||
|
Assert.AreEqual(3, f.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestEmoji()
|
||||||
|
{
|
||||||
|
Message result = MessageFormatter.FormatMessage(new Message { Content = "Hello world\uD83D\uDE12<--This is an emoji,There are more:\uD83D\uDE10\uD83D\uDE00,\uD83D\uDE20" });
|
||||||
|
Assert.AreEqual("Hello world\0\0\0<--This is an emoji,There are more:\0\0\0\0\0\0,\0\0\0", result.DisplayContent);
|
||||||
|
Assert.AreEqual(result.Links.Count, 4);
|
||||||
|
Assert.AreEqual(result.Links[0].Index, 11);
|
||||||
|
Assert.AreEqual(result.Links[1].Index, 49);
|
||||||
|
Assert.AreEqual(result.Links[2].Index, 52);
|
||||||
|
Assert.AreEqual(result.Links[3].Index, 56);
|
||||||
|
Assert.AreEqual(result.Links[0].Url, "\uD83D\uDE12");
|
||||||
|
Assert.AreEqual(result.Links[1].Url, "\uD83D\uDE10");
|
||||||
|
Assert.AreEqual(result.Links[2].Url, "\uD83D\uDE00");
|
||||||
|
Assert.AreEqual(result.Links[3].Url, "\uD83D\uDE20");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
217
osu.Game.Tests/Visual/TestCaseChatLink.cs
Normal file
217
osu.Game.Tests/Visual/TestCaseChatLink.cs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Overlays.Chat;
|
||||||
|
using osu.Game.Users;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual
|
||||||
|
{
|
||||||
|
public class TestCaseChatLink : OsuTestCase
|
||||||
|
{
|
||||||
|
private readonly TestChatLineContainer textContainer;
|
||||||
|
private Color4 linkColour;
|
||||||
|
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(ChatLine),
|
||||||
|
typeof(Message),
|
||||||
|
typeof(LinkFlowContainer),
|
||||||
|
typeof(DummyEchoMessage),
|
||||||
|
typeof(LocalEchoMessage),
|
||||||
|
typeof(MessageFormatter)
|
||||||
|
};
|
||||||
|
|
||||||
|
private DependencyContainer dependencies;
|
||||||
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) => dependencies = new DependencyContainer(parent);
|
||||||
|
|
||||||
|
public TestCaseChatLink()
|
||||||
|
{
|
||||||
|
Add(textContainer = new TestChatLineContainer
|
||||||
|
{
|
||||||
|
Padding = new MarginPadding { Left = 20, Right = 20 },
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
linkColour = colours.Blue;
|
||||||
|
dependencies.Cache(new ChatOverlay
|
||||||
|
{
|
||||||
|
AvailableChannels =
|
||||||
|
{
|
||||||
|
new Channel { Name = "#english" },
|
||||||
|
new Channel { Name = "#japanese" }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testLinksGeneral();
|
||||||
|
testEcho();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clear() => AddStep("clear messages", textContainer.Clear);
|
||||||
|
|
||||||
|
private void addMessageWithChecks(string text, int linkAmount = 0, bool isAction = false, bool isImportant = false, params LinkAction[] expectedActions)
|
||||||
|
{
|
||||||
|
int index = textContainer.Count + 1;
|
||||||
|
var newLine = new ChatLine(new DummyMessage(text, isAction, isImportant, index));
|
||||||
|
textContainer.Add(newLine);
|
||||||
|
|
||||||
|
AddAssert($"msg #{index} has {linkAmount} link(s)", () => newLine.Message.Links.Count == linkAmount);
|
||||||
|
AddAssert($"msg #{index} has the right action", hasExpectedActions);
|
||||||
|
AddAssert($"msg #{index} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic());
|
||||||
|
AddAssert($"msg #{index} shows {linkAmount} link(s)", isShowingLinks);
|
||||||
|
|
||||||
|
bool hasExpectedActions()
|
||||||
|
{
|
||||||
|
var expectedActionsList = expectedActions.ToList();
|
||||||
|
|
||||||
|
if (expectedActionsList.Count != newLine.Message.Links.Count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < newLine.Message.Links.Count; i++)
|
||||||
|
{
|
||||||
|
var action = newLine.Message.Links[i].Action;
|
||||||
|
if (action != expectedActions[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast<OsuSpriteText>().All(sprite => sprite.Font == "Exo2.0-MediumItalic");
|
||||||
|
|
||||||
|
bool isShowingLinks()
|
||||||
|
{
|
||||||
|
bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
|
||||||
|
|
||||||
|
Color4 textColour = isAction && hasBackground ? OsuColour.FromHex(newLine.Message.Sender.Colour) : Color4.White;
|
||||||
|
|
||||||
|
var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
|
||||||
|
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
|
||||||
|
|
||||||
|
return linkSprites.All(d => d.Colour == linkColour)
|
||||||
|
&& newLine.ContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testLinksGeneral()
|
||||||
|
{
|
||||||
|
addMessageWithChecks("test!");
|
||||||
|
addMessageWithChecks("osu.ppy.sh!");
|
||||||
|
addMessageWithChecks("https://osu.ppy.sh!", 1, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("00:12:345 (1,2) - Test?", 1, expectedActions: LinkAction.OpenEditorTimestamp);
|
||||||
|
addMessageWithChecks("Wiki link for tasty [[Performance Points]]", 1, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("(osu forums)[https://osu.ppy.sh/forum] (old link format)", 1, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("[https://osu.ppy.sh/home New site] (new link format)", 1, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("[osu forums](https://osu.ppy.sh/forum) (new link format 2)", 1, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("[https://osu.ppy.sh/home This is only a link to the new osu webpage but this is supposed to test word wrap.]", 1, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("is now listening to [https://osu.ppy.sh/s/93523 IMAGE -MATERIAL- <Version 0>]", 1, true, expectedActions: LinkAction.OpenBeatmapSet);
|
||||||
|
addMessageWithChecks("is now playing [https://osu.ppy.sh/b/252238 IMAGE -MATERIAL- <Version 0>]", 1, true, expectedActions: LinkAction.OpenBeatmap);
|
||||||
|
addMessageWithChecks("Let's (try)[https://osu.ppy.sh/home] [https://osu.ppy.sh/b/252238 multiple links] https://osu.ppy.sh/home", 3,
|
||||||
|
expectedActions: new[] { LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External });
|
||||||
|
// note that there's 0 links here (they get removed if a channel is not found)
|
||||||
|
addMessageWithChecks("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).");
|
||||||
|
addMessageWithChecks("I am important!", 0, false, true);
|
||||||
|
addMessageWithChecks("feels important", 0, true, true);
|
||||||
|
addMessageWithChecks("likes to post this [https://osu.ppy.sh/home link].", 1, true, true, expectedActions: LinkAction.External);
|
||||||
|
addMessageWithChecks("Join my multiplayer game osump://12346.", 1, expectedActions: LinkAction.JoinMultiplayerMatch);
|
||||||
|
addMessageWithChecks("Join my [multiplayer game](osump://12346).", 1, expectedActions: LinkAction.JoinMultiplayerMatch);
|
||||||
|
addMessageWithChecks("Join my [#english](osu://chan/#english).", 1, expectedActions: LinkAction.OpenChannel);
|
||||||
|
addMessageWithChecks("Join my osu://chan/#english.", 1, expectedActions: LinkAction.OpenChannel);
|
||||||
|
addMessageWithChecks("Join my #english or #japanese channels.", 2, expectedActions: new[] { LinkAction.OpenChannel, LinkAction.OpenChannel });
|
||||||
|
addMessageWithChecks("Join my #english or #nonexistent #hashtag channels.", 1, expectedActions: LinkAction.OpenChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testEcho()
|
||||||
|
{
|
||||||
|
int echoCounter = 0;
|
||||||
|
|
||||||
|
addEchoWithWait("sent!", "received!");
|
||||||
|
addEchoWithWait("https://osu.ppy.sh/home", null, 500);
|
||||||
|
addEchoWithWait("[https://osu.ppy.sh/forum let's try multiple words too!]");
|
||||||
|
addEchoWithWait("(long loading times! clickable while loading?)[https://osu.ppy.sh/home]", null, 5000);
|
||||||
|
|
||||||
|
void addEchoWithWait(string text, string completeText = null, double delay = 250)
|
||||||
|
{
|
||||||
|
var newLine = new ChatLine(new DummyEchoMessage(text));
|
||||||
|
|
||||||
|
AddStep($"send msg #{++echoCounter} after {delay}ms", () =>
|
||||||
|
{
|
||||||
|
textContainer.Add(newLine);
|
||||||
|
Scheduler.AddDelayed(() => newLine.Message = new DummyMessage(completeText ?? text), delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep(() => textContainer.All(line => line.Message is DummyMessage), $"wait for msg #{echoCounter}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DummyEchoMessage : LocalEchoMessage
|
||||||
|
{
|
||||||
|
public DummyEchoMessage(string text)
|
||||||
|
{
|
||||||
|
Content = text;
|
||||||
|
Timestamp = DateTimeOffset.Now;
|
||||||
|
Sender = DummyMessage.TEST_SENDER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DummyMessage : Message
|
||||||
|
{
|
||||||
|
private static long messageCounter;
|
||||||
|
|
||||||
|
internal static readonly User TEST_SENDER_BACKGROUND = new User
|
||||||
|
{
|
||||||
|
Username = @"i-am-important",
|
||||||
|
Id = 42,
|
||||||
|
Colour = "#250cc9",
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static readonly User TEST_SENDER = new User
|
||||||
|
{
|
||||||
|
Username = @"Somebody",
|
||||||
|
Id = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
public new DateTimeOffset Timestamp = DateTimeOffset.Now;
|
||||||
|
|
||||||
|
public DummyMessage(string text, bool isAction = false, bool isImportant = false, int number = 0)
|
||||||
|
: base(messageCounter++)
|
||||||
|
{
|
||||||
|
Content = text;
|
||||||
|
IsAction = isAction;
|
||||||
|
Sender = new User
|
||||||
|
{
|
||||||
|
Username = $"User {number}",
|
||||||
|
Id = number,
|
||||||
|
Colour = isImportant ? "#250cc9" : null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestChatLineContainer : FillFlowContainer<ChatLine>
|
||||||
|
{
|
||||||
|
protected override int Compare(Drawable x, Drawable y)
|
||||||
|
{
|
||||||
|
var xC = (ChatLine)x;
|
||||||
|
var yC = (ChatLine)y;
|
||||||
|
|
||||||
|
return xC.Message.CompareTo(yC.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,8 @@ using OpenTK;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Edit.Layers.Selection;
|
using osu.Game.Rulesets.Edit.Layers.Selection;
|
||||||
using osu.Game.Rulesets.Osu.Edit;
|
using osu.Game.Rulesets.Osu.Edit;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -35,9 +37,9 @@ namespace osu.Game.Tests.Visual
|
|||||||
new SelectionLayer(playfield)
|
new SelectionLayer(playfield)
|
||||||
};
|
};
|
||||||
|
|
||||||
playfield.Add(new DrawableHitCircle(new HitCircle { Position = new Vector2(256, 192), Scale = 0.5f }));
|
var hitCircle1 = new HitCircle { Position = new Vector2(256, 192), Scale = 0.5f };
|
||||||
playfield.Add(new DrawableHitCircle(new HitCircle { Position = new Vector2(344, 148), Scale = 0.5f }));
|
var hitCircle2 = new HitCircle { Position = new Vector2(344, 148), Scale = 0.5f };
|
||||||
playfield.Add(new DrawableSlider(new Slider
|
var slider = new Slider
|
||||||
{
|
{
|
||||||
ControlPoints = new List<Vector2>
|
ControlPoints = new List<Vector2>
|
||||||
{
|
{
|
||||||
@ -48,8 +50,16 @@ namespace osu.Game.Tests.Visual
|
|||||||
Position = new Vector2(128, 256),
|
Position = new Vector2(128, 256),
|
||||||
Velocity = 1,
|
Velocity = 1,
|
||||||
TickDistance = 100,
|
TickDistance = 100,
|
||||||
Scale = 0.5f
|
Scale = 0.5f,
|
||||||
}));
|
};
|
||||||
|
|
||||||
|
hitCircle1.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
hitCircle2.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
playfield.Add(new DrawableHitCircle(hitCircle1));
|
||||||
|
playfield.Add(new DrawableHitCircle(hitCircle2));
|
||||||
|
playfield.Add(new DrawableSlider(slider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Screens.Play.ReplaySettings;
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
{
|
{
|
||||||
@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
{
|
{
|
||||||
ExampleContainer container;
|
ExampleContainer container;
|
||||||
|
|
||||||
Add(new ReplaySettingsOverlay
|
Add(new PlayerSettingsOverlay
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
Text = @"Button",
|
Text = @"Button",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep(@"Add checkbox", () => container.Add(new ReplayCheckbox
|
AddStep(@"Add checkbox", () => container.Add(new PlayerCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Checkbox",
|
LabelText = "Checkbox",
|
||||||
}));
|
}));
|
||||||
@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExampleContainer : ReplayGroup
|
private class ExampleContainer : PlayerSettingsGroup
|
||||||
{
|
{
|
||||||
protected override string Title => @"example";
|
protected override string Title => @"example";
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,7 @@
|
|||||||
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoderTest.cs" />
|
<Compile Include="Beatmaps\Formats\LegacyStoryboardDecoderTest.cs" />
|
||||||
<Compile Include="Beatmaps\IO\OszArchiveReaderTest.cs" />
|
<Compile Include="Beatmaps\IO\OszArchiveReaderTest.cs" />
|
||||||
<Compile Include="Beatmaps\IO\ImportBeatmapTest.cs" />
|
<Compile Include="Beatmaps\IO\ImportBeatmapTest.cs" />
|
||||||
|
<Compile Include="Chat\MessageFormatterTests.cs" />
|
||||||
<Compile Include="Resources\Resource.cs" />
|
<Compile Include="Resources\Resource.cs" />
|
||||||
<Compile Include="Beatmaps\Formats\LegacyBeatmapDecoderTest.cs" />
|
<Compile Include="Beatmaps\Formats\LegacyBeatmapDecoderTest.cs" />
|
||||||
<Compile Include="Visual\TestCaseBeatmapCarousel.cs" />
|
<Compile Include="Visual\TestCaseBeatmapCarousel.cs" />
|
||||||
@ -137,6 +138,7 @@
|
|||||||
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
|
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
|
||||||
<Compile Include="Visual\TestCaseAllPlayers.cs" />
|
<Compile Include="Visual\TestCaseAllPlayers.cs" />
|
||||||
<Compile Include="Visual\TestCaseOsuGame.cs" />
|
<Compile Include="Visual\TestCaseOsuGame.cs" />
|
||||||
|
<Compile Include="Visual\TestCaseChatLink.cs" />
|
||||||
<Compile Include="Visual\TestCasePlaybackControl.cs" />
|
<Compile Include="Visual\TestCasePlaybackControl.cs" />
|
||||||
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
||||||
<Compile Include="Visual\TestCasePopupDialog.cs" />
|
<Compile Include="Visual\TestCasePopupDialog.cs" />
|
||||||
|
@ -39,6 +39,8 @@ namespace osu.Game.Configuration
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
|
Set(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
||||||
|
|
||||||
Set(OsuSetting.MenuVoice, true);
|
Set(OsuSetting.MenuVoice, true);
|
||||||
Set(OsuSetting.MenuMusic, true);
|
Set(OsuSetting.MenuMusic, true);
|
||||||
|
|
||||||
@ -101,6 +103,7 @@ namespace osu.Game.Configuration
|
|||||||
MouseDisableButtons,
|
MouseDisableButtons,
|
||||||
MouseDisableWheel,
|
MouseDisableWheel,
|
||||||
AudioOffset,
|
AudioOffset,
|
||||||
|
VolumeInactive,
|
||||||
MenuMusic,
|
MenuMusic,
|
||||||
MenuVoice,
|
MenuVoice,
|
||||||
CursorRotation,
|
CursorRotation,
|
||||||
|
100
osu.Game/Graphics/Containers/LinkFlowContainer.cs
Normal file
100
osu.Game/Graphics/Containers/LinkFlowContainer.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.Game.Online.Chat;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.Containers
|
||||||
|
{
|
||||||
|
public class LinkFlowContainer : OsuTextFlowContainer
|
||||||
|
{
|
||||||
|
public LinkFlowContainer(Action<SpriteText> defaultCreationParameters = null)
|
||||||
|
: base(defaultCreationParameters)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HandleMouseInput => true;
|
||||||
|
|
||||||
|
private OsuGame game;
|
||||||
|
|
||||||
|
private Action showNotImplementedError;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OsuGame game, NotificationOverlay notifications)
|
||||||
|
{
|
||||||
|
// will be null in tests
|
||||||
|
this.game = game;
|
||||||
|
|
||||||
|
showNotImplementedError = () => notifications?.Post(new SimpleNotification
|
||||||
|
{
|
||||||
|
Text = @"This link type is not yet supported!",
|
||||||
|
Icon = FontAwesome.fa_life_saver,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddLinks(string text, List<Link> links)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text) || links == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (links.Count == 0)
|
||||||
|
{
|
||||||
|
AddText(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int previousLinkEnd = 0;
|
||||||
|
foreach (var link in links)
|
||||||
|
{
|
||||||
|
AddText(text.Substring(previousLinkEnd, link.Index - previousLinkEnd));
|
||||||
|
AddLink(text.Substring(link.Index, link.Length), link.Url, link.Action, link.Argument);
|
||||||
|
previousLinkEnd = link.Index + link.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddText(text.Substring(previousLinkEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddLink(string text, string url, LinkAction linkType = LinkAction.External, string linkArgument = null, string tooltipText = null)
|
||||||
|
{
|
||||||
|
AddInternal(new DrawableLinkCompiler(AddText(text).ToList())
|
||||||
|
{
|
||||||
|
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
switch (linkType)
|
||||||
|
{
|
||||||
|
case LinkAction.OpenBeatmap:
|
||||||
|
// todo: replace this with overlay.ShowBeatmap(id) once an appropriate API call is implemented.
|
||||||
|
if (int.TryParse(linkArgument, out int beatmapId))
|
||||||
|
Process.Start($"https://osu.ppy.sh/b/{beatmapId}");
|
||||||
|
break;
|
||||||
|
case LinkAction.OpenBeatmapSet:
|
||||||
|
if (int.TryParse(linkArgument, out int setId))
|
||||||
|
game?.ShowBeatmapSet(setId);
|
||||||
|
break;
|
||||||
|
case LinkAction.OpenChannel:
|
||||||
|
game?.OpenChannel(linkArgument);
|
||||||
|
break;
|
||||||
|
case LinkAction.OpenEditorTimestamp:
|
||||||
|
case LinkAction.JoinMultiplayerMatch:
|
||||||
|
case LinkAction.Spectate:
|
||||||
|
showNotImplementedError?.Invoke();
|
||||||
|
break;
|
||||||
|
case LinkAction.External:
|
||||||
|
Process.Start(url);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException($"This {nameof(LinkAction)} ({linkType.ToString()}) is missing an associated action.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,8 @@ namespace osu.Game.Graphics.Containers
|
|||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
|
||||||
|
|
||||||
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal)
|
||||||
{
|
{
|
||||||
this.sampleSet = sampleSet;
|
this.sampleSet = sampleSet;
|
||||||
@ -33,7 +35,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
content,
|
content,
|
||||||
new HoverClickSounds(sampleSet)
|
CreateHoverClickSounds(sampleSet)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
|
||||||
@ -10,24 +12,34 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
public class OsuHoverContainer : OsuClickableContainer
|
public class OsuHoverContainer : OsuClickableContainer
|
||||||
{
|
{
|
||||||
private Color4 hoverColour;
|
protected Color4 HoverColour;
|
||||||
|
|
||||||
|
protected Color4 IdleColour = Color4.White;
|
||||||
|
|
||||||
|
protected virtual IEnumerable<Drawable> EffectTargets => new[] { Content };
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
this.FadeColour(hoverColour, 500, Easing.OutQuint);
|
EffectTargets.ForEach(d => d.FadeColour(HoverColour, 500, Easing.OutQuint));
|
||||||
return base.OnHover(state);
|
return base.OnHover(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
this.FadeColour(Color4.White, 500, Easing.OutQuint);
|
EffectTargets.ForEach(d => d.FadeColour(IdleColour, 500, Easing.OutQuint));
|
||||||
base.OnHoverLost(state);
|
base.OnHoverLost(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
hoverColour = colours.Yellow;
|
HoverColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
EffectTargets.ForEach(d => d.FadeColour(IdleColour));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
osu.Game/Online/Chat/DrawableLinkCompiler.cs
Normal file
59
osu.Game/Online/Chat/DrawableLinkCompiler.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// 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.Cursor;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.Chat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An invisible drawable that brings multiple <see cref="SpriteText"/> pieces together to form a consumable clickable link.
|
||||||
|
/// </summary>
|
||||||
|
public class DrawableLinkCompiler : OsuHoverContainer, IHasTooltip
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Each word part of a chat link (split for word-wrap support).
|
||||||
|
/// </summary>
|
||||||
|
public List<SpriteText> Parts;
|
||||||
|
|
||||||
|
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceiveMouseInputAt(screenSpacePos));
|
||||||
|
|
||||||
|
protected override HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts);
|
||||||
|
|
||||||
|
public DrawableLinkCompiler(IEnumerable<SpriteText> parts)
|
||||||
|
{
|
||||||
|
Parts = parts.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
IdleColour = colours.Blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Drawable> EffectTargets => Parts;
|
||||||
|
|
||||||
|
public string TooltipText { get; set; }
|
||||||
|
|
||||||
|
private class LinkHoverSounds : HoverClickSounds
|
||||||
|
{
|
||||||
|
private readonly List<SpriteText> parts;
|
||||||
|
|
||||||
|
public LinkHoverSounds(HoverSampleSet sampleSet, List<SpriteText> parts)
|
||||||
|
: base(sampleSet)
|
||||||
|
{
|
||||||
|
this.parts = parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => parts.Any(d => d.ReceiveMouseInputAt(screenSpacePos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -40,6 +41,17 @@ namespace osu.Game.Online.Chat
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The text that is displayed in chat.
|
||||||
|
/// </summary>
|
||||||
|
public string DisplayContent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The links found in this message.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The <see cref="Link"/>s' <see cref="Link.Index"/> and <see cref="Link.Length"/>s are according to <see cref="DisplayContent"/></remarks>
|
||||||
|
public List<Link> Links;
|
||||||
|
|
||||||
public Message(long? id)
|
public Message(long? id)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
|
263
osu.Game/Online/Chat/MessageFormatter.cs
Normal file
263
osu.Game/Online/Chat/MessageFormatter.cs
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
// 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.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.Chat
|
||||||
|
{
|
||||||
|
public static class MessageFormatter
|
||||||
|
{
|
||||||
|
// [[Performance Points]] -> wiki:Performance Points (https://osu.ppy.sh/wiki/Performance_Points)
|
||||||
|
private static readonly Regex wiki_regex = new Regex(@"\[\[([^\]]+)\]\]");
|
||||||
|
|
||||||
|
// (test)[https://osu.ppy.sh/b/1234] -> test (https://osu.ppy.sh/b/1234)
|
||||||
|
private static readonly Regex old_link_regex = new Regex(@"\(([^\)]*)\)\[([a-z]+://[^ ]+)\]");
|
||||||
|
|
||||||
|
// [https://osu.ppy.sh/b/1234 Beatmap [Hard] (poop)] -> Beatmap [hard] (poop) (https://osu.ppy.sh/b/1234)
|
||||||
|
private static readonly Regex new_link_regex = new Regex(@"\[([a-z]+://[^ ]+) ([^\[\]]*(((?<open>\[)[^\[\]]*)+((?<close-open>\])[^\[\]]*)+)*(?(open)(?!)))\]");
|
||||||
|
|
||||||
|
// [test](https://osu.ppy.sh/b/1234) -> test (https://osu.ppy.sh/b/1234) aka correct markdown format
|
||||||
|
private static readonly Regex markdown_link_regex = new Regex(@"\[([^\]]*)\]\(([a-z]+://[^ ]+)\)");
|
||||||
|
|
||||||
|
// advanced, RFC-compatible regular expression that matches any possible URL, *but* allows certain invalid characters that are widely used
|
||||||
|
// This is in the format (<required>, [optional]):
|
||||||
|
// http[s]://<domain>.<tld>[:port][/path][?query][#fragment]
|
||||||
|
private static readonly Regex advanced_link_regex = new Regex(
|
||||||
|
// protocol
|
||||||
|
@"(?<link>[a-z]*?:\/\/" +
|
||||||
|
// domain + tld
|
||||||
|
@"(?<domain>(?:[a-z0-9]\.|[a-z0-9][a-z0-9-]*[a-z0-9]\.)*[a-z0-9-]*[a-z0-9]" +
|
||||||
|
// port (optional)
|
||||||
|
@"(?::\d+)?)" +
|
||||||
|
// path (optional)
|
||||||
|
@"(?<path>(?:(?:\/+(?:[a-z0-9$_\.\+!\*\',;:\(\)@&~=-]|%[0-9a-f]{2})*)*" +
|
||||||
|
// query (optional)
|
||||||
|
@"(?:\?(?:[a-z0-9$_\+!\*\',;:\(\)@&=\/~-]|%[0-9a-f]{2})*)?)?" +
|
||||||
|
// fragment (optional)
|
||||||
|
@"(?:#(?:[a-z0-9$_\+!\*\',;:\(\)@&=\/~-]|%[0-9a-f]{2})*)?)?)",
|
||||||
|
RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
// 00:00:000 (1,2,3) - test
|
||||||
|
private static readonly Regex time_regex = new Regex(@"\d\d:\d\d:\d\d\d? [^-]*");
|
||||||
|
|
||||||
|
// #osu
|
||||||
|
private static readonly Regex channel_regex = new Regex(@"(#[a-zA-Z]+[a-zA-Z0-9]+)");
|
||||||
|
|
||||||
|
// Unicode emojis
|
||||||
|
private static readonly Regex emoji_regex = new Regex(@"(\uD83D[\uDC00-\uDE4F])");
|
||||||
|
|
||||||
|
private static void handleMatches(Regex regex, string display, string link, MessageFormatterResult result, int startIndex = 0, LinkAction? linkActionOverride = null)
|
||||||
|
{
|
||||||
|
int captureOffset = 0;
|
||||||
|
foreach (Match m in regex.Matches(result.Text, startIndex))
|
||||||
|
{
|
||||||
|
var index = m.Index - captureOffset;
|
||||||
|
|
||||||
|
var displayText = string.Format(display,
|
||||||
|
m.Groups[0],
|
||||||
|
m.Groups.Count > 1 ? m.Groups[1].Value : "",
|
||||||
|
m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim();
|
||||||
|
|
||||||
|
var linkText = string.Format(link,
|
||||||
|
m.Groups[0],
|
||||||
|
m.Groups.Count > 1 ? m.Groups[1].Value : "",
|
||||||
|
m.Groups.Count > 2 ? m.Groups[2].Value : "").Trim();
|
||||||
|
|
||||||
|
if (displayText.Length == 0 || linkText.Length == 0) continue;
|
||||||
|
|
||||||
|
// Check for encapsulated links
|
||||||
|
if (result.Links.Find(l => l.Index <= index && l.Index + l.Length >= index + m.Length || index <= l.Index && index + m.Length >= l.Index + l.Length) == null)
|
||||||
|
{
|
||||||
|
result.Text = result.Text.Remove(index, m.Length).Insert(index, displayText);
|
||||||
|
|
||||||
|
//since we just changed the line display text, offset any already processed links.
|
||||||
|
result.Links.ForEach(l => l.Index -= l.Index > index ? m.Length - displayText.Length : 0);
|
||||||
|
|
||||||
|
var details = getLinkDetails(linkText);
|
||||||
|
result.Links.Add(new Link(linkText, index, displayText.Length, linkActionOverride ?? details.Action, details.Argument));
|
||||||
|
|
||||||
|
//adjust the offset for processing the current matches group.
|
||||||
|
captureOffset += m.Length - displayText.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleAdvanced(Regex regex, MessageFormatterResult result, int startIndex = 0)
|
||||||
|
{
|
||||||
|
foreach (Match m in regex.Matches(result.Text, startIndex))
|
||||||
|
{
|
||||||
|
var index = m.Index;
|
||||||
|
var link = m.Groups["link"].Value;
|
||||||
|
var indexLength = link.Length;
|
||||||
|
|
||||||
|
var details = getLinkDetails(link);
|
||||||
|
result.Links.Add(new Link(link, index, indexLength, details.Action, details.Argument));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LinkDetails getLinkDetails(string url)
|
||||||
|
{
|
||||||
|
var args = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
args[0] = args[0].TrimEnd(':');
|
||||||
|
|
||||||
|
switch (args[0])
|
||||||
|
{
|
||||||
|
case "http":
|
||||||
|
case "https":
|
||||||
|
// length > 3 since all these links need another argument to work
|
||||||
|
if (args.Length > 3 && (args[1] == "osu.ppy.sh" || args[1] == "new.ppy.sh"))
|
||||||
|
{
|
||||||
|
switch (args[2])
|
||||||
|
{
|
||||||
|
case "b":
|
||||||
|
case "beatmaps":
|
||||||
|
return new LinkDetails(LinkAction.OpenBeatmap, args[3]);
|
||||||
|
case "s":
|
||||||
|
case "beatmapsets":
|
||||||
|
case "d":
|
||||||
|
return new LinkDetails(LinkAction.OpenBeatmapSet, args[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LinkDetails(LinkAction.External, null);
|
||||||
|
case "osu":
|
||||||
|
// every internal link also needs some kind of argument
|
||||||
|
if (args.Length < 3)
|
||||||
|
return new LinkDetails(LinkAction.External, null);
|
||||||
|
|
||||||
|
LinkAction linkType;
|
||||||
|
switch (args[1])
|
||||||
|
{
|
||||||
|
case "chan":
|
||||||
|
linkType = LinkAction.OpenChannel;
|
||||||
|
break;
|
||||||
|
case "edit":
|
||||||
|
linkType = LinkAction.OpenEditorTimestamp;
|
||||||
|
break;
|
||||||
|
case "b":
|
||||||
|
linkType = LinkAction.OpenBeatmap;
|
||||||
|
break;
|
||||||
|
case "s":
|
||||||
|
case "dl":
|
||||||
|
linkType = LinkAction.OpenBeatmapSet;
|
||||||
|
break;
|
||||||
|
case "spectate":
|
||||||
|
linkType = LinkAction.Spectate;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
linkType = LinkAction.External;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LinkDetails(linkType, args[2]);
|
||||||
|
case "osump":
|
||||||
|
return new LinkDetails(LinkAction.JoinMultiplayerMatch, args[1]);
|
||||||
|
default:
|
||||||
|
return new LinkDetails(LinkAction.External, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MessageFormatterResult format(string toFormat, int startIndex = 0, int space = 3)
|
||||||
|
{
|
||||||
|
var result = new MessageFormatterResult(toFormat);
|
||||||
|
|
||||||
|
// handle the [link display] format
|
||||||
|
handleMatches(new_link_regex, "{2}", "{1}", result, startIndex);
|
||||||
|
|
||||||
|
// handle the standard markdown []() format
|
||||||
|
handleMatches(markdown_link_regex, "{1}", "{2}", result, startIndex);
|
||||||
|
|
||||||
|
// handle the ()[] link format
|
||||||
|
handleMatches(old_link_regex, "{1}", "{2}", result, startIndex);
|
||||||
|
|
||||||
|
// handle wiki links
|
||||||
|
handleMatches(wiki_regex, "{1}", "https://osu.ppy.sh/wiki/{1}", result, startIndex);
|
||||||
|
|
||||||
|
// handle bare links
|
||||||
|
handleAdvanced(advanced_link_regex, result, startIndex);
|
||||||
|
|
||||||
|
// handle editor times
|
||||||
|
handleMatches(time_regex, "{0}", "osu://edit/{0}", result, startIndex, LinkAction.OpenEditorTimestamp);
|
||||||
|
|
||||||
|
// handle channels
|
||||||
|
handleMatches(channel_regex, "{0}", "osu://chan/{0}", result, startIndex, LinkAction.OpenChannel);
|
||||||
|
|
||||||
|
var empty = "";
|
||||||
|
while (space-- > 0)
|
||||||
|
empty += "\0";
|
||||||
|
|
||||||
|
handleMatches(emoji_regex, empty, "{0}", result, startIndex);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Message FormatMessage(Message inputMessage)
|
||||||
|
{
|
||||||
|
var result = format(inputMessage.Content);
|
||||||
|
|
||||||
|
inputMessage.DisplayContent = result.Text;
|
||||||
|
|
||||||
|
// Sometimes, regex matches are not in order
|
||||||
|
result.Links.Sort();
|
||||||
|
inputMessage.Links = result.Links;
|
||||||
|
return inputMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessageFormatterResult
|
||||||
|
{
|
||||||
|
public List<Link> Links = new List<Link>();
|
||||||
|
public string Text;
|
||||||
|
public string OriginalText;
|
||||||
|
|
||||||
|
public MessageFormatterResult(string text)
|
||||||
|
{
|
||||||
|
OriginalText = Text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LinkDetails
|
||||||
|
{
|
||||||
|
public LinkAction Action;
|
||||||
|
public string Argument;
|
||||||
|
|
||||||
|
public LinkDetails(LinkAction action, string argument)
|
||||||
|
{
|
||||||
|
Action = action;
|
||||||
|
Argument = argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LinkAction
|
||||||
|
{
|
||||||
|
External,
|
||||||
|
OpenBeatmap,
|
||||||
|
OpenBeatmapSet,
|
||||||
|
OpenChannel,
|
||||||
|
OpenEditorTimestamp,
|
||||||
|
JoinMultiplayerMatch,
|
||||||
|
Spectate,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Link : IComparable<Link>
|
||||||
|
{
|
||||||
|
public string Url;
|
||||||
|
public int Index;
|
||||||
|
public int Length;
|
||||||
|
public LinkAction Action;
|
||||||
|
public string Argument;
|
||||||
|
|
||||||
|
public Link(string url, int startIndex, int length, LinkAction action, string argument)
|
||||||
|
{
|
||||||
|
Url = url;
|
||||||
|
Index = startIndex;
|
||||||
|
Length = length;
|
||||||
|
Action = action;
|
||||||
|
Argument = argument;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ using OpenTK;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
@ -121,10 +122,24 @@ namespace osu.Game
|
|||||||
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
configRuleset = LocalConfig.GetBindable<int>(OsuSetting.Ruleset);
|
||||||
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
|
Ruleset.Value = RulesetStore.GetRuleset(configRuleset.Value) ?? RulesetStore.AvailableRulesets.First();
|
||||||
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
|
Ruleset.ValueChanged += r => configRuleset.Value = r.ID ?? 0;
|
||||||
|
|
||||||
|
LocalConfig.BindWith(OsuSetting.VolumeInactive, inactiveVolumeAdjust);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledDelegate scoreLoad;
|
private ScheduledDelegate scoreLoad;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open chat to a channel matching the provided name, if present.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="channelName">The name of the channel.</param>
|
||||||
|
public void OpenChannel(string channelName) => chat.OpenChannel(chat.AvailableChannels.Find(c => c.Name == channelName));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show a beatmap set as an overlay.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="setId">The set to display.</param>
|
||||||
|
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.ShowBeatmapSet(setId);
|
||||||
|
|
||||||
protected void LoadScore(Score s)
|
protected void LoadScore(Score s)
|
||||||
{
|
{
|
||||||
scoreLoad?.Cancel();
|
scoreLoad?.Cancel();
|
||||||
@ -398,6 +413,20 @@ namespace osu.Game
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly BindableDouble inactiveVolumeAdjust = new BindableDouble();
|
||||||
|
|
||||||
|
protected override void OnDeactivated()
|
||||||
|
{
|
||||||
|
base.OnDeactivated();
|
||||||
|
Audio.AddAdjustment(AdjustableProperty.Volume, inactiveVolumeAdjust);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnActivated()
|
||||||
|
{
|
||||||
|
base.OnActivated();
|
||||||
|
Audio.RemoveAdjustment(AdjustableProperty.Volume, inactiveVolumeAdjust);
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnReleased(GlobalAction action) => false;
|
public bool OnReleased(GlobalAction action) => false;
|
||||||
|
|
||||||
private Container mainContent;
|
private Container mainContent;
|
||||||
|
@ -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.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -82,16 +83,18 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
private Message message;
|
private Message message;
|
||||||
private OsuSpriteText username;
|
private OsuSpriteText username;
|
||||||
private OsuTextFlowContainer contentFlow;
|
private LinkFlowContainer contentFlow;
|
||||||
|
|
||||||
|
public LinkFlowContainer ContentFlow => contentFlow;
|
||||||
|
|
||||||
public Message Message
|
public Message Message
|
||||||
{
|
{
|
||||||
get { return message; }
|
get => message;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (message == value) return;
|
if (message == value) return;
|
||||||
|
|
||||||
message = value;
|
message = MessageFormatter.FormatMessage(value);
|
||||||
|
|
||||||
if (!IsLoaded)
|
if (!IsLoaded)
|
||||||
return;
|
return;
|
||||||
@ -101,8 +104,9 @@ namespace osu.Game.Overlays.Chat
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours, ChatOverlay chat)
|
||||||
{
|
{
|
||||||
|
this.chat = chat;
|
||||||
customUsernameColour = colours.ChatBlue;
|
customUsernameColour = colours.ChatBlue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +191,18 @@ namespace osu.Game.Overlays.Chat
|
|||||||
Padding = new MarginPadding { Left = message_padding + padding },
|
Padding = new MarginPadding { Left = message_padding + padding },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
contentFlow = new OsuTextFlowContainer(t => { t.TextSize = text_size; })
|
contentFlow = new LinkFlowContainer(t =>
|
||||||
|
{
|
||||||
|
if (Message.IsAction)
|
||||||
|
{
|
||||||
|
t.Font = @"Exo2.0-MediumItalic";
|
||||||
|
|
||||||
|
if (senderHasBackground)
|
||||||
|
t.Colour = OsuColour.FromHex(message.Sender.Colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.TextSize = text_size;
|
||||||
|
})
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -195,30 +210,26 @@ namespace osu.Game.Overlays.Chat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (message.IsAction && senderHasBackground)
|
|
||||||
contentFlow.Colour = OsuColour.FromHex(message.Sender.Colour);
|
|
||||||
|
|
||||||
updateMessageContent();
|
updateMessageContent();
|
||||||
FinishTransforms(true);
|
FinishTransforms(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ChatOverlay chat;
|
||||||
|
|
||||||
private void updateMessageContent()
|
private void updateMessageContent()
|
||||||
{
|
{
|
||||||
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
|
this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint);
|
||||||
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
|
timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint);
|
||||||
|
|
||||||
timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}";
|
timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}";
|
||||||
username.Text = $@"{message.Sender.Username}" + (senderHasBackground ? "" : ":");
|
username.Text = $@"{message.Sender.Username}" + (senderHasBackground || message.IsAction ? "" : ":");
|
||||||
|
|
||||||
if (message.IsAction)
|
// remove non-existent channels from the link list
|
||||||
{
|
message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chat?.AvailableChannels.Any(c => c.Name == link.Argument) != true);
|
||||||
contentFlow.Clear();
|
|
||||||
contentFlow.AddText("[", sprite => sprite.Padding = new MarginPadding { Right = action_padding });
|
contentFlow.Clear();
|
||||||
contentFlow.AddText(message.Content, sprite => sprite.Font = @"Exo2.0-MediumItalic");
|
contentFlow.AddLinks(message.DisplayContent, message.Links);
|
||||||
contentFlow.AddText("]", sprite => sprite.Padding = new MarginPadding { Left = action_padding });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
contentFlow.Text = message.Content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MessageSender : OsuClickableContainer, IHasContextMenu
|
private class MessageSender : OsuClickableContainer, IHasContextMenu
|
||||||
|
@ -60,6 +60,7 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public Bindable<double> ChatHeight { get; set; }
|
public Bindable<double> ChatHeight { get; set; }
|
||||||
|
|
||||||
|
public List<Channel> AvailableChannels { get; private set; } = new List<Channel>();
|
||||||
private readonly Container channelSelectionContainer;
|
private readonly Container channelSelectionContainer;
|
||||||
private readonly ChannelSelectionOverlay channelSelection;
|
private readonly ChannelSelectionOverlay channelSelection;
|
||||||
|
|
||||||
@ -190,6 +191,8 @@ namespace osu.Game.Overlays
|
|||||||
private double startDragChatHeight;
|
private double startDragChatHeight;
|
||||||
private bool isDragging;
|
private bool isDragging;
|
||||||
|
|
||||||
|
public void OpenChannel(Channel channel) => addChannel(channel);
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
protected override bool OnDragStart(InputState state)
|
||||||
{
|
{
|
||||||
isDragging = tabsArea.IsHovered;
|
isDragging = tabsArea.IsHovered;
|
||||||
@ -298,6 +301,8 @@ namespace osu.Game.Overlays
|
|||||||
ListChannelsRequest req = new ListChannelsRequest();
|
ListChannelsRequest req = new ListChannelsRequest();
|
||||||
req.Success += delegate (List<Channel> channels)
|
req.Success += delegate (List<Channel> channels)
|
||||||
{
|
{
|
||||||
|
AvailableChannels = channels;
|
||||||
|
|
||||||
Scheduler.Add(delegate
|
Scheduler.Add(delegate
|
||||||
{
|
{
|
||||||
addChannel(channels.Find(c => c.Name == @"#lazer"));
|
addChannel(channels.Find(c => c.Name == @"#lazer"));
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -9,6 +10,7 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
@ -16,9 +18,6 @@ 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.Users;
|
using osu.Game.Users;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using osu.Framework.Graphics.Cursor;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Profile
|
namespace osu.Game.Overlays.Profile
|
||||||
{
|
{
|
||||||
@ -103,7 +102,7 @@ namespace osu.Game.Overlays.Profile
|
|||||||
Y = -75,
|
Y = -75,
|
||||||
Size = new Vector2(25, 25)
|
Size = new Vector2(25, 25)
|
||||||
},
|
},
|
||||||
new LinkFlowContainer.ProfileLink(user)
|
new ProfileLink(user)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
@ -329,12 +328,14 @@ namespace osu.Game.Overlays.Profile
|
|||||||
{
|
{
|
||||||
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
|
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.Country != null)
|
if (user.Country != null)
|
||||||
{
|
{
|
||||||
infoTextLeft.AddText("from ");
|
infoTextLeft.AddText("from ");
|
||||||
infoTextLeft.AddText(user.Country.FullName, boldItalic);
|
infoTextLeft.AddText(user.Country.FullName, boldItalic);
|
||||||
countryFlag.Country = user.Country;
|
countryFlag.Country = user.Country;
|
||||||
}
|
}
|
||||||
|
|
||||||
infoTextLeft.NewParagraph();
|
infoTextLeft.NewParagraph();
|
||||||
|
|
||||||
if (user.JoinDate.ToUniversalTime().Year < 2008)
|
if (user.JoinDate.ToUniversalTime().Year < 2008)
|
||||||
@ -346,6 +347,7 @@ namespace osu.Game.Overlays.Profile
|
|||||||
infoTextLeft.AddText("Joined ");
|
infoTextLeft.AddText("Joined ");
|
||||||
infoTextLeft.AddText(user.JoinDate.LocalDateTime.ToShortDateString(), boldItalic);
|
infoTextLeft.AddText(user.JoinDate.LocalDateTime.ToShortDateString(), boldItalic);
|
||||||
}
|
}
|
||||||
|
|
||||||
infoTextLeft.NewLine();
|
infoTextLeft.NewLine();
|
||||||
infoTextLeft.AddText("Last seen ");
|
infoTextLeft.AddText("Last seen ");
|
||||||
infoTextLeft.AddText(user.LastVisit.LocalDateTime.ToShortDateString(), boldItalic);
|
infoTextLeft.AddText(user.LastVisit.LocalDateTime.ToShortDateString(), boldItalic);
|
||||||
@ -434,6 +436,28 @@ namespace osu.Game.Overlays.Profile
|
|||||||
infoTextRight.NewLine();
|
infoTextRight.NewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ProfileLink : OsuHoverContainer, IHasTooltip
|
||||||
|
{
|
||||||
|
public string TooltipText => "View Profile in Browser";
|
||||||
|
|
||||||
|
public override bool HandleMouseInput => true;
|
||||||
|
|
||||||
|
public ProfileLink(User user)
|
||||||
|
{
|
||||||
|
Action = () => Process.Start($@"https://osu.ppy.sh/users/{user.Id}");
|
||||||
|
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Child = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = user.Username,
|
||||||
|
Font = @"Exo2.0-RegularItalic",
|
||||||
|
TextSize = 30,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private class GradeBadge : Container
|
private class GradeBadge : Container
|
||||||
{
|
{
|
||||||
private const float width = 50;
|
private const float width = 50;
|
||||||
@ -471,61 +495,5 @@ namespace osu.Game.Overlays.Profile
|
|||||||
badge.Texture = textures.Get($"Grades/{grade}");
|
badge.Texture = textures.Get($"Grades/{grade}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LinkFlowContainer : OsuTextFlowContainer
|
|
||||||
{
|
|
||||||
public override bool HandleKeyboardInput => true;
|
|
||||||
public override bool HandleMouseInput => true;
|
|
||||||
|
|
||||||
public LinkFlowContainer(Action<SpriteText> defaultCreationParameters = null) : base(defaultCreationParameters)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override SpriteText CreateSpriteText() => new LinkText();
|
|
||||||
|
|
||||||
public void AddLink(string text, string url) => AddText(text, link => ((LinkText)link).Url = url);
|
|
||||||
|
|
||||||
public class LinkText : OsuSpriteText
|
|
||||||
{
|
|
||||||
private readonly OsuHoverContainer content;
|
|
||||||
|
|
||||||
public override bool HandleKeyboardInput => content.Action != null;
|
|
||||||
public override bool HandleMouseInput => content.Action != null;
|
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content ?? (Container<Drawable>)this;
|
|
||||||
|
|
||||||
protected override IEnumerable<Drawable> FlowingChildren => Children;
|
|
||||||
|
|
||||||
public string Url
|
|
||||||
{
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value != null)
|
|
||||||
content.Action = () => Process.Start(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinkText()
|
|
||||||
{
|
|
||||||
AddInternal(content = new OsuHoverContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ProfileLink : LinkText, IHasTooltip
|
|
||||||
{
|
|
||||||
public string TooltipText => "View Profile in Browser";
|
|
||||||
|
|
||||||
public ProfileLink(User user)
|
|
||||||
{
|
|
||||||
Text = user.Username;
|
|
||||||
Url = $@"https://osu.ppy.sh/users/{user.Id}";
|
|
||||||
Font = @"Exo2.0-RegularItalic";
|
|
||||||
TextSize = 30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.Audio
|
namespace osu.Game.Overlays.Settings.Sections.Audio
|
||||||
{
|
{
|
||||||
@ -12,11 +13,12 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
|
|||||||
protected override string Header => "Volume";
|
protected override string Header => "Volume";
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio, OsuConfigManager config)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SettingsSlider<double> { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.1f },
|
new SettingsSlider<double> { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.1f },
|
||||||
|
new SettingsSlider<double> { LabelText = "Master (Window Inactive)", Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive), KeyboardStep = 0.1f },
|
||||||
new SettingsSlider<double> { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.1f },
|
new SettingsSlider<double> { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.1f },
|
||||||
new SettingsSlider<double> { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.1f },
|
new SettingsSlider<double> { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.1f },
|
||||||
};
|
};
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Screens.Play.ReplaySettings;
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Edit
|
namespace osu.Game.Rulesets.Edit
|
||||||
{
|
{
|
||||||
public class ToolboxGroup : ReplayGroup
|
public class ToolboxGroup : PlayerSettingsGroup
|
||||||
{
|
{
|
||||||
protected override string Title => "toolbox";
|
protected override string Title => "toolbox";
|
||||||
|
|
||||||
|
@ -171,10 +171,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
|
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
|
||||||
|
|
||||||
protected sealed override bool HasCompleted => Hits == MaxHits;
|
protected sealed override bool HasCompleted => JudgedHits == MaxHits;
|
||||||
|
|
||||||
protected int MaxHits { get; private set; }
|
protected int MaxHits { get; private set; }
|
||||||
protected int Hits { get; private set; }
|
protected int JudgedHits { get; private set; }
|
||||||
|
|
||||||
private double maxHighestCombo;
|
private double maxHighestCombo;
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
baseScore += judgement.NumericResult;
|
baseScore += judgement.NumericResult;
|
||||||
rollingMaxBaseScore += judgement.MaxNumericResult;
|
rollingMaxBaseScore += judgement.MaxNumericResult;
|
||||||
|
|
||||||
Hits++;
|
JudgedHits++;
|
||||||
}
|
}
|
||||||
else if (judgement.IsHit)
|
else if (judgement.IsHit)
|
||||||
bonusScore += judgement.NumericResult;
|
bonusScore += judgement.NumericResult;
|
||||||
@ -279,7 +279,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
baseScore -= judgement.NumericResult;
|
baseScore -= judgement.NumericResult;
|
||||||
rollingMaxBaseScore -= judgement.MaxNumericResult;
|
rollingMaxBaseScore -= judgement.MaxNumericResult;
|
||||||
|
|
||||||
Hits--;
|
JudgedHits--;
|
||||||
}
|
}
|
||||||
else if (judgement.IsHit)
|
else if (judgement.IsHit)
|
||||||
bonusScore -= judgement.NumericResult;
|
bonusScore -= judgement.NumericResult;
|
||||||
@ -305,14 +305,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
{
|
{
|
||||||
if (storeResults)
|
if (storeResults)
|
||||||
{
|
{
|
||||||
MaxHits = Hits;
|
MaxHits = JudgedHits;
|
||||||
maxHighestCombo = HighestCombo;
|
maxHighestCombo = HighestCombo;
|
||||||
maxBaseScore = baseScore;
|
maxBaseScore = baseScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Reset(storeResults);
|
base.Reset(storeResults);
|
||||||
|
|
||||||
Hits = 0;
|
JudgedHits = 0;
|
||||||
baseScore = 0;
|
baseScore = 0;
|
||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
|
@ -240,13 +240,13 @@ namespace osu.Game.Rulesets.UI
|
|||||||
foreach (var mod in Mods.OfType<IApplicableToDifficulty>())
|
foreach (var mod in Mods.OfType<IApplicableToDifficulty>())
|
||||||
mod.ApplyToDifficulty(Beatmap.BeatmapInfo.BaseDifficulty);
|
mod.ApplyToDifficulty(Beatmap.BeatmapInfo.BaseDifficulty);
|
||||||
|
|
||||||
|
// Post-process the beatmap
|
||||||
|
processor.PostProcess(Beatmap);
|
||||||
|
|
||||||
// Apply defaults
|
// Apply defaults
|
||||||
foreach (var h in Beatmap.HitObjects)
|
foreach (var h in Beatmap.HitObjects)
|
||||||
h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty);
|
h.ApplyDefaults(Beatmap.ControlPointInfo, Beatmap.BeatmapInfo.BaseDifficulty);
|
||||||
|
|
||||||
// Post-process the beatmap
|
|
||||||
processor.PostProcess(Beatmap);
|
|
||||||
|
|
||||||
KeyBindingInputManager = CreateInputManager();
|
KeyBindingInputManager = CreateInputManager();
|
||||||
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
@ -3,29 +3,30 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Screens.Play.ReplaySettings;
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
{
|
{
|
||||||
public class ReplaySettingsOverlay : VisibilityContainer
|
public class PlayerSettingsOverlay : VisibilityContainer
|
||||||
{
|
{
|
||||||
private const int fade_duration = 200;
|
private const int fade_duration = 200;
|
||||||
|
|
||||||
public bool ReplayLoaded;
|
public bool ReplayLoaded;
|
||||||
|
|
||||||
public readonly PlaybackSettings PlaybackSettings;
|
public readonly PlaybackSettings PlaybackSettings;
|
||||||
|
public readonly VisualSettings VisualSettings;
|
||||||
//public readonly CollectionSettings CollectionSettings;
|
//public readonly CollectionSettings CollectionSettings;
|
||||||
//public readonly DiscussionSettings DiscussionSettings;
|
//public readonly DiscussionSettings DiscussionSettings;
|
||||||
|
|
||||||
public ReplaySettingsOverlay()
|
public PlayerSettingsOverlay()
|
||||||
{
|
{
|
||||||
AlwaysPresent = true;
|
AlwaysPresent = true;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Child = new FillFlowContainer<ReplayGroup>
|
Child = new FillFlowContainer<PlayerSettingsGroup>
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
@ -33,11 +34,12 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 20),
|
Spacing = new Vector2(0, 20),
|
||||||
Margin = new MarginPadding { Top = 100, Right = 10 },
|
Margin = new MarginPadding { Top = 100, Right = 10 },
|
||||||
Children = new[]
|
Children = new PlayerSettingsGroup[]
|
||||||
{
|
{
|
||||||
//CollectionSettings = new CollectionSettings(),
|
//CollectionSettings = new CollectionSettings(),
|
||||||
//DiscussionSettings = new DiscussionSettings(),
|
//DiscussionSettings = new DiscussionSettings(),
|
||||||
PlaybackSettings = new PlaybackSettings(),
|
PlaybackSettings = new PlaybackSettings(),
|
||||||
|
VisualSettings = new VisualSettings()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -34,7 +34,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public readonly HealthDisplay HealthDisplay;
|
public readonly HealthDisplay HealthDisplay;
|
||||||
public readonly SongProgress Progress;
|
public readonly SongProgress Progress;
|
||||||
public readonly ModDisplay ModDisplay;
|
public readonly ModDisplay ModDisplay;
|
||||||
public readonly ReplaySettingsOverlay ReplaySettingsOverlay;
|
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
|
||||||
|
|
||||||
private Bindable<bool> showHud;
|
private Bindable<bool> showHud;
|
||||||
private readonly BindableBool replayLoaded = new BindableBool();
|
private readonly BindableBool replayLoaded = new BindableBool();
|
||||||
@ -58,7 +58,7 @@ namespace osu.Game.Screens.Play
|
|||||||
HealthDisplay = CreateHealthDisplay(),
|
HealthDisplay = CreateHealthDisplay(),
|
||||||
Progress = CreateProgress(),
|
Progress = CreateProgress(),
|
||||||
ModDisplay = CreateModsContainer(),
|
ModDisplay = CreateModsContainer(),
|
||||||
ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
PlayerSettingsOverlay = CreatePlayerSettingsOverlay()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
ModDisplay.Current.BindTo(working.Mods);
|
ModDisplay.Current.BindTo(working.Mods);
|
||||||
|
|
||||||
ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
PlayerSettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
@ -115,16 +115,16 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private void replayLoadedValueChanged(bool loaded)
|
private void replayLoadedValueChanged(bool loaded)
|
||||||
{
|
{
|
||||||
ReplaySettingsOverlay.ReplayLoaded = loaded;
|
PlayerSettingsOverlay.ReplayLoaded = loaded;
|
||||||
|
|
||||||
if (loaded)
|
if (loaded)
|
||||||
{
|
{
|
||||||
ReplaySettingsOverlay.Show();
|
PlayerSettingsOverlay.Show();
|
||||||
ModDisplay.FadeIn(200);
|
ModDisplay.FadeIn(200);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReplaySettingsOverlay.Hide();
|
PlayerSettingsOverlay.Hide();
|
||||||
ModDisplay.Delay(2000).FadeOut(200);
|
ModDisplay.Delay(2000).FadeOut(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ namespace osu.Game.Screens.Play
|
|||||||
Margin = new MarginPadding { Top = 20, Right = 10 },
|
Margin = new MarginPadding { Top = 20, Right = 10 },
|
||||||
};
|
};
|
||||||
|
|
||||||
protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay();
|
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
|
||||||
|
|
||||||
protected virtual void BindProcessor(ScoreProcessor processor)
|
protected virtual void BindProcessor(ScoreProcessor processor)
|
||||||
{
|
{
|
||||||
|
@ -13,6 +13,7 @@ using osu.Game.Screens.Backgrounds;
|
|||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play
|
namespace osu.Game.Screens.Play
|
||||||
{
|
{
|
||||||
@ -21,6 +22,7 @@ namespace osu.Game.Screens.Play
|
|||||||
private Player player;
|
private Player player;
|
||||||
|
|
||||||
private BeatmapMetadataDisplay info;
|
private BeatmapMetadataDisplay info;
|
||||||
|
private VisualSettings visualSettings;
|
||||||
|
|
||||||
private bool showOverlays = true;
|
private bool showOverlays = true;
|
||||||
public override bool ShowOverlaysOnEnter => showOverlays;
|
public override bool ShowOverlaysOnEnter => showOverlays;
|
||||||
@ -49,6 +51,12 @@ namespace osu.Game.Screens.Play
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
});
|
});
|
||||||
|
Add(visualSettings = new VisualSettings
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Margin = new MarginPadding(25)
|
||||||
|
});
|
||||||
|
|
||||||
LoadComponentAsync(player);
|
LoadComponentAsync(player);
|
||||||
}
|
}
|
||||||
@ -110,7 +118,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private void pushWhenLoaded()
|
private void pushWhenLoaded()
|
||||||
{
|
{
|
||||||
if (player.LoadState != LoadState.Ready)
|
if (player.LoadState != LoadState.Ready || visualSettings.IsHovered)
|
||||||
{
|
{
|
||||||
Schedule(pushWhenLoaded);
|
Schedule(pushWhenLoaded);
|
||||||
return;
|
return;
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Overlays.Music;
|
using osu.Game.Overlays.Music;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.ReplaySettings
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
{
|
{
|
||||||
public class CollectionSettings : ReplayGroup
|
public class CollectionSettings : PlayerSettingsGroup
|
||||||
{
|
{
|
||||||
protected override string Title => @"collections";
|
protected override string Title => @"collections";
|
||||||
|
|
@ -6,9 +6,9 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.ReplaySettings
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
{
|
{
|
||||||
public class DiscussionSettings : ReplayGroup
|
public class DiscussionSettings : PlayerSettingsGroup
|
||||||
{
|
{
|
||||||
protected override string Title => @"discussions";
|
protected override string Title => @"discussions";
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play.ReplaySettings
|
|||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new ReplayCheckbox
|
new PlayerCheckbox
|
||||||
{
|
{
|
||||||
LabelText = "Show floating comments",
|
LabelText = "Show floating comments",
|
||||||
Bindable = config.GetBindable<bool>(OsuSetting.FloatingComments)
|
Bindable = config.GetBindable<bool>(OsuSetting.FloatingComments)
|
@ -1,15 +1,15 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Framework.Configuration;
|
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.Timing;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.ReplaySettings
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
{
|
{
|
||||||
public class PlaybackSettings : ReplayGroup
|
public class PlaybackSettings : PlayerSettingsGroup
|
||||||
{
|
{
|
||||||
private const int padding = 10;
|
private const int padding = 10;
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play.ReplaySettings
|
|||||||
|
|
||||||
public IAdjustableClock AdjustableClock { set; get; }
|
public IAdjustableClock AdjustableClock { set; get; }
|
||||||
|
|
||||||
private readonly ReplaySliderBar<double> sliderbar;
|
private readonly PlayerSliderBar<double> sliderbar;
|
||||||
|
|
||||||
public PlaybackSettings()
|
public PlaybackSettings()
|
||||||
{
|
{
|
||||||
@ -47,7 +47,7 @@ namespace osu.Game.Screens.Play.ReplaySettings
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
sliderbar = new ReplaySliderBar<double>
|
sliderbar = new PlayerSliderBar<double>
|
||||||
{
|
{
|
||||||
Bindable = new BindableDouble(1)
|
Bindable = new BindableDouble(1)
|
||||||
{
|
{
|
@ -5,9 +5,9 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.ReplaySettings
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
{
|
{
|
||||||
public class ReplayCheckbox : OsuCheckbox
|
public class PlayerCheckbox : OsuCheckbox
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
@ -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 OpenTK;
|
|
||||||
using OpenTK.Graphics;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -10,10 +8,12 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.ReplaySettings
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
{
|
{
|
||||||
public abstract class ReplayGroup : Container
|
public abstract class PlayerSettingsGroup : Container
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The title to be displayed in the header of this group.
|
/// The title to be displayed in the header of this group.
|
||||||
@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play.ReplaySettings
|
|||||||
|
|
||||||
private Color4 buttonActiveColour;
|
private Color4 buttonActiveColour;
|
||||||
|
|
||||||
protected ReplayGroup()
|
protected PlayerSettingsGroup()
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
Width = container_width;
|
Width = container_width;
|
@ -1,16 +1,16 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Game.Graphics;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.ReplaySettings
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
{
|
{
|
||||||
public class ReplaySliderBar<T> : SettingsSlider<T>
|
public class PlayerSliderBar<T> : SettingsSlider<T>
|
||||||
where T : struct, IEquatable<T>, IComparable, IConvertible
|
where T : struct, IEquatable<T>, IComparable, IConvertible
|
||||||
{
|
{
|
||||||
protected override Drawable CreateControl() => new Sliderbar
|
protected override Drawable CreateControl() => new Sliderbar
|
52
osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs
Normal file
52
osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// 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.Game.Configuration;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play.PlayerSettings
|
||||||
|
{
|
||||||
|
public class VisualSettings : PlayerSettingsGroup
|
||||||
|
{
|
||||||
|
protected override string Title => "Visual settings";
|
||||||
|
|
||||||
|
private readonly PlayerSliderBar<double> dimSliderBar;
|
||||||
|
private readonly PlayerSliderBar<double> blurSliderBar;
|
||||||
|
private readonly PlayerCheckbox showStoryboardToggle;
|
||||||
|
private readonly PlayerCheckbox mouseWheelDisabledToggle;
|
||||||
|
|
||||||
|
public VisualSettings()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Background dim:"
|
||||||
|
},
|
||||||
|
dimSliderBar = new PlayerSliderBar<double>(),
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Background blur:"
|
||||||
|
},
|
||||||
|
blurSliderBar = new PlayerSliderBar<double>(),
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = "Toggles:"
|
||||||
|
},
|
||||||
|
showStoryboardToggle = new PlayerCheckbox { LabelText = "Storyboards" },
|
||||||
|
mouseWheelDisabledToggle = new PlayerCheckbox { LabelText = "Disable mouse wheel" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
dimSliderBar.Bindable = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||||
|
blurSliderBar.Bindable = config.GetBindable<double>(OsuSetting.BlurLevel);
|
||||||
|
showStoryboardToggle.Bindable = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||||
|
mouseWheelDisabledToggle.Bindable = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -275,7 +275,9 @@
|
|||||||
<Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
|
<Compile Include="Configuration\SpeedChangeVisualisationMethod.cs" />
|
||||||
<Compile Include="Database\DatabaseContextFactory.cs" />
|
<Compile Include="Database\DatabaseContextFactory.cs" />
|
||||||
<Compile Include="Database\IHasPrimaryKey.cs" />
|
<Compile Include="Database\IHasPrimaryKey.cs" />
|
||||||
|
<Compile Include="Graphics\Containers\LinkFlowContainer.cs" />
|
||||||
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
|
<Compile Include="Graphics\Textures\LargeTextureStore.cs" />
|
||||||
|
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
||||||
<Compile Include="Migrations\20180125143340_Settings.cs" />
|
<Compile Include="Migrations\20180125143340_Settings.cs" />
|
||||||
<Compile Include="Migrations\20180125143340_Settings.Designer.cs">
|
<Compile Include="Migrations\20180125143340_Settings.Designer.cs">
|
||||||
<DependentUpon>20180125143340_Settings.cs</DependentUpon>
|
<DependentUpon>20180125143340_Settings.cs</DependentUpon>
|
||||||
@ -306,6 +308,8 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Migrations\OsuDbContextModelSnapshot.cs" />
|
<Compile Include="Migrations\OsuDbContextModelSnapshot.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" />
|
<Compile Include="Online\API\Requests\GetBeatmapSetRequest.cs" />
|
||||||
|
<Compile Include="Online\Chat\DrawableLinkCompiler.cs" />
|
||||||
|
<Compile Include="Online\Chat\MessageFormatter.cs" />
|
||||||
<Compile Include="Online\API\Requests\APIResponseBeatmapSet.cs" />
|
<Compile Include="Online\API\Requests\APIResponseBeatmapSet.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetUserMostPlayedBeatmapsRequest.cs" />
|
<Compile Include="Online\API\Requests\GetUserMostPlayedBeatmapsRequest.cs" />
|
||||||
<Compile Include="Overlays\BeatmapSet\Scores\ClickableUsername.cs" />
|
<Compile Include="Overlays\BeatmapSet\Scores\ClickableUsername.cs" />
|
||||||
@ -335,6 +339,7 @@
|
|||||||
<Compile Include="Overlays\Social\SocialListPanel.cs" />
|
<Compile Include="Overlays\Social\SocialListPanel.cs" />
|
||||||
<Compile Include="Overlays\Social\SocialPanel.cs" />
|
<Compile Include="Overlays\Social\SocialPanel.cs" />
|
||||||
<Compile Include="Rulesets\Mods\IApplicableToDrawableHitObject.cs" />
|
<Compile Include="Rulesets\Mods\IApplicableToDrawableHitObject.cs" />
|
||||||
|
<Compile Include="Screens\Play\PlayerSettings\VisualSettings.cs" />
|
||||||
<Compile Include="Rulesets\UI\HitObjectContainer.cs" />
|
<Compile Include="Rulesets\UI\HitObjectContainer.cs" />
|
||||||
<Compile Include="Rulesets\UI\Scrolling\Visualisers\SequentialSpeedChangeVisualiser.cs" />
|
<Compile Include="Rulesets\UI\Scrolling\Visualisers\SequentialSpeedChangeVisualiser.cs" />
|
||||||
<Compile Include="Rulesets\UI\Scrolling\Visualisers\ISpeedChangeVisualiser.cs" />
|
<Compile Include="Rulesets\UI\Scrolling\Visualisers\ISpeedChangeVisualiser.cs" />
|
||||||
@ -471,7 +476,6 @@
|
|||||||
<Compile Include="Online\API\Requests\SearchBeatmapSetsRequest.cs" />
|
<Compile Include="Online\API\Requests\SearchBeatmapSetsRequest.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetMessagesRequest.cs" />
|
<Compile Include="Online\API\Requests\GetMessagesRequest.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetScoresRequest.cs" />
|
<Compile Include="Online\API\Requests\GetScoresRequest.cs" />
|
||||||
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
|
|
||||||
<Compile Include="Online\API\Requests\GetUsersRequest.cs" />
|
<Compile Include="Online\API\Requests\GetUsersRequest.cs" />
|
||||||
<Compile Include="Online\API\Requests\ListChannelsRequest.cs" />
|
<Compile Include="Online\API\Requests\ListChannelsRequest.cs" />
|
||||||
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
|
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
|
||||||
@ -766,13 +770,13 @@
|
|||||||
<Compile Include="Screens\Play\Player.cs" />
|
<Compile Include="Screens\Play\Player.cs" />
|
||||||
<Compile Include="Screens\Play\PlayerLoader.cs" />
|
<Compile Include="Screens\Play\PlayerLoader.cs" />
|
||||||
<Compile Include="Screens\Play\ReplayPlayer.cs" />
|
<Compile Include="Screens\Play\ReplayPlayer.cs" />
|
||||||
<Compile Include="Screens\Play\HUD\ReplaySettingsOverlay.cs" />
|
<Compile Include="Screens\Play\HUD\PlayerSettingsOverlay.cs" />
|
||||||
<Compile Include="Screens\Play\ReplaySettings\CollectionSettings.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\CollectionSettings.cs" />
|
||||||
<Compile Include="Screens\Play\ReplaySettings\DiscussionSettings.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\DiscussionSettings.cs" />
|
||||||
<Compile Include="Screens\Play\ReplaySettings\PlaybackSettings.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\PlaybackSettings.cs" />
|
||||||
<Compile Include="Screens\Play\ReplaySettings\ReplayCheckbox.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\PlayerCheckbox.cs" />
|
||||||
<Compile Include="Screens\Play\ReplaySettings\ReplayGroup.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\PlayerSettingsGroup.cs" />
|
||||||
<Compile Include="Screens\Play\ReplaySettings\ReplaySliderBar.cs" />
|
<Compile Include="Screens\Play\PlayerSettings\PlayerSliderBar.cs" />
|
||||||
<Compile Include="Screens\Play\SkipButton.cs" />
|
<Compile Include="Screens\Play\SkipButton.cs" />
|
||||||
<Compile Include="Screens\Play\SongProgress.cs" />
|
<Compile Include="Screens\Play\SongProgress.cs" />
|
||||||
<Compile Include="Screens\Play\SongProgressBar.cs" />
|
<Compile Include="Screens\Play\SongProgressBar.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user