mirror of
https://github.com/ppy/osu.git
synced 2026-05-15 13:23:18 +08:00
Compare commits
274 Commits
+1
-1
Submodule osu-framework updated: 5986f21268...36fad894f0
+1
-1
Submodule osu-resources updated: a4418111f8...1750ab8f67
@@ -390,7 +390,7 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
public static void AuthenticatedBlockingPerform(this WebRequest r)
|
||||
{
|
||||
r.Headers.Add("Authorization", $"token {GitHubAccessToken}");
|
||||
r.AddHeader("Authorization", $"token {GitHubAccessToken}");
|
||||
r.Perform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace osu.Desktop
|
||||
var filePaths = new [] { e.FileName };
|
||||
|
||||
if (filePaths.All(f => Path.GetExtension(f) == @".osz"))
|
||||
Task.Run(() => BeatmapManager.Import(filePaths));
|
||||
Task.Factory.StartNew(() => BeatmapManager.Import(filePaths), TaskCreationOptions.LongRunning);
|
||||
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
|
||||
protected override void UpdateState(ArmedState state)
|
||||
{
|
||||
switch (State)
|
||||
switch (State.Value)
|
||||
{
|
||||
case ArmedState.Hit:
|
||||
AccentColour = Color4.Green;
|
||||
|
||||
@@ -57,8 +57,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500).Expire();
|
||||
this.ScaleTo(2f, 600, Easing.OutQuint).FadeOut(500);
|
||||
inner.FadeOut(250);
|
||||
|
||||
Expire(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
{
|
||||
private const float width = 8;
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
public FollowPoint()
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
@@ -52,9 +52,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
private void update()
|
||||
{
|
||||
Clear();
|
||||
|
||||
if (hitObjects == null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
},
|
||||
ApproachCircle = new ApproachCircle
|
||||
{
|
||||
Alpha = 0,
|
||||
Scale = new Vector2(4),
|
||||
Colour = AccentColour,
|
||||
}
|
||||
};
|
||||
@@ -82,21 +84,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
});
|
||||
}
|
||||
|
||||
protected override void UpdateInitialState()
|
||||
{
|
||||
base.UpdateInitialState();
|
||||
|
||||
// sane defaults
|
||||
ring.Show();
|
||||
circle.Show();
|
||||
number.Show();
|
||||
glow.Show();
|
||||
|
||||
ApproachCircle.Hide();
|
||||
ApproachCircle.ScaleTo(new Vector2(4));
|
||||
explode.Hide();
|
||||
}
|
||||
|
||||
protected override void UpdatePreemptState()
|
||||
{
|
||||
base.UpdatePreemptState();
|
||||
|
||||
@@ -23,12 +23,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
protected sealed override void UpdateState(ArmedState state)
|
||||
{
|
||||
FinishTransforms();
|
||||
double transformTime = HitObject.StartTime - TIME_PREEMPT;
|
||||
|
||||
using (BeginAbsoluteSequence(HitObject.StartTime - TIME_PREEMPT, true))
|
||||
base.ApplyTransformsAt(transformTime, true);
|
||||
base.ClearTransformsAfter(transformTime, true);
|
||||
|
||||
using (BeginAbsoluteSequence(transformTime, true))
|
||||
{
|
||||
UpdateInitialState();
|
||||
|
||||
UpdatePreemptState();
|
||||
|
||||
using (BeginDelayedSequence(TIME_PREEMPT + (Judgements.FirstOrDefault()?.TimeOffset ?? 0), true))
|
||||
@@ -36,11 +37,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateInitialState()
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
protected virtual void UpdatePreemptState()
|
||||
{
|
||||
this.FadeIn(TIME_FADEIN);
|
||||
@@ -50,6 +46,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
}
|
||||
|
||||
// Todo: At some point we need to move these to DrawableHitObject after ensuring that all other Rulesets apply
|
||||
// transforms in the same way and don't rely on them not being cleared
|
||||
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { }
|
||||
public override void ApplyTransformsAt(double time, bool propagateChildren = false) { }
|
||||
|
||||
private OsuInputManager osuActionInputManager;
|
||||
internal OsuInputManager OsuActionInputManager => osuActionInputManager ?? (osuActionInputManager = GetContainingInputManager() as OsuInputManager);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
public double FadeInTime;
|
||||
public double FadeOutTime;
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider) : base(repeatPoint)
|
||||
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
|
||||
: base(repeatPoint)
|
||||
{
|
||||
this.repeatPoint = repeatPoint;
|
||||
this.drawableSlider = drawableSlider;
|
||||
@@ -28,6 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Blending = BlendingMode.Additive;
|
||||
Origin = Anchor.Centre;
|
||||
Scale = new Vector2(0.5f);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@@ -51,12 +51,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
var animIn = Math.Min(150, repeatPoint.StartTime - FadeInTime);
|
||||
|
||||
this.Animate(
|
||||
d => d.FadeIn(animIn),
|
||||
d => d.ScaleTo(0.5f).ScaleTo(1.2f, animIn)
|
||||
).Then(
|
||||
d => d.ScaleTo(1, 150, Easing.Out)
|
||||
);
|
||||
this.FadeIn(animIn).ScaleTo(1.2f, animIn)
|
||||
.Then()
|
||||
.ScaleTo(1, 150, Easing.Out);
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
|
||||
@@ -43,7 +43,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ball = new SliderBall(s)
|
||||
{
|
||||
Scale = new Vector2(s.Scale),
|
||||
AccentColour = AccentColour
|
||||
AccentColour = AccentColour,
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0
|
||||
},
|
||||
initialCircle = new DrawableHitCircle(new HitCircle
|
||||
{
|
||||
@@ -148,16 +150,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateInitialState()
|
||||
{
|
||||
base.UpdateInitialState();
|
||||
body.Alpha = 1;
|
||||
|
||||
//we need to be present to handle input events. note that we still don't get enough events (we don't get a position if the mouse hasn't moved since the slider appeared).
|
||||
ball.AlwaysPresent = true;
|
||||
ball.Alpha = 0;
|
||||
}
|
||||
|
||||
protected override void UpdateCurrentState(ArmedState state)
|
||||
{
|
||||
ball.FadeIn();
|
||||
|
||||
@@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
|
||||
public bool Tracking;
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
public override bool DisplayJudgement => false;
|
||||
|
||||
public DrawableSliderTick(SliderTick sliderTick) : base(sliderTick)
|
||||
|
||||
@@ -101,14 +101,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
// If the current time is between the start and end of the slider, we should track mouse input regardless of the cursor position.
|
||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => canCurrentlyTrack || base.ReceiveMouseInputAt(screenSpacePos);
|
||||
|
||||
public override void ClearTransforms(bool propagateChildren = false, string targetMember = null)
|
||||
{
|
||||
// Consider the case of rewinding - children's transforms are handled internally, so propagating down
|
||||
// any further will cause weirdness with the Tracking bool below. Let's not propagate further at this point.
|
||||
base.ClearTransforms(false, targetMember);
|
||||
}
|
||||
|
||||
private bool tracking;
|
||||
public bool Tracking
|
||||
{
|
||||
get { return tracking; }
|
||||
private set
|
||||
{
|
||||
if (value == tracking) return;
|
||||
|
||||
if (value == tracking)
|
||||
return;
|
||||
tracking = value;
|
||||
|
||||
follow.ScaleTo(tracking ? 2.8f : 1, 300, Easing.OutQuint);
|
||||
@@ -123,8 +130,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
base.Update();
|
||||
|
||||
// Make sure to use the base version of ReceiveMouseInputAt so that we correctly check the position.
|
||||
if (Time.Current < slider.EndTime)
|
||||
Tracking = canCurrentlyTrack && lastState != null && base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position) && ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false);
|
||||
Tracking = canCurrentlyTrack
|
||||
&& lastState != null
|
||||
&& base.ReceiveMouseInputAt(lastState.Mouse.NativeState.Position)
|
||||
&& ((Parent as DrawableSlider)?.OsuActionInputManager?.PressedActions.Any(x => x == OsuAction.LeftButton || x == OsuAction.RightButton) ?? false);
|
||||
}
|
||||
|
||||
public void UpdateProgress(double progress, int repeat)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@@ -61,6 +62,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||
|
||||
public void SetRotation(float currentRotation)
|
||||
{
|
||||
// If we've gone back in time, it's fine to work with a fresh set of records for now
|
||||
if (records.Count > 0 && Time.Current < records.Last().Time)
|
||||
records.Clear();
|
||||
|
||||
if (records.Count > 0)
|
||||
{
|
||||
var record = records.Peek();
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
h.Depth = depth++;
|
||||
|
||||
if (auto)
|
||||
h.State = ArmedState.Hit;
|
||||
h.State.Value = ArmedState.Hit;
|
||||
|
||||
playfieldContainer.Add(h);
|
||||
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
{
|
||||
public class TaikoStrongHitJudgement : TaikoJudgement
|
||||
@@ -11,9 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
||||
|
||||
public TaikoStrongHitJudgement()
|
||||
{
|
||||
base.Result = HitResult.Perfect;
|
||||
Final = true;
|
||||
}
|
||||
|
||||
public new HitResult Result => base.Result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
/// </summary>
|
||||
protected abstract TaikoAction[] HitActions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether a second hit is allowed to be processed. This occurs once this hit object has been hit successfully.
|
||||
/// </summary>
|
||||
protected bool SecondHitAllowed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the last key pressed is a valid hit key.
|
||||
/// </summary>
|
||||
@@ -45,7 +50,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
if (!validKeyPressed)
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
else if (hitOffset < HitObject.HitWindowGood)
|
||||
AddJudgement(new TaikoJudgement { Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good });
|
||||
{
|
||||
AddJudgement(new TaikoJudgement
|
||||
{
|
||||
Result = hitOffset < HitObject.HitWindowGreat ? HitResult.Great : HitResult.Good,
|
||||
Final = !HitObject.IsStrong
|
||||
});
|
||||
|
||||
SecondHitAllowed = true;
|
||||
}
|
||||
else
|
||||
AddJudgement(new TaikoJudgement { Result = HitResult.Miss });
|
||||
}
|
||||
@@ -72,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
var offset = !AllJudged ? 0 : Time.Current - HitObject.StartTime;
|
||||
using (BeginDelayedSequence(HitObject.StartTime - Time.Current + offset, true))
|
||||
{
|
||||
switch (State)
|
||||
switch (State.Value)
|
||||
{
|
||||
case ArmedState.Idle:
|
||||
this.Delay(HitObject.HitWindowMiss).Expire();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
@@ -24,27 +25,25 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
{
|
||||
}
|
||||
|
||||
private bool processedSecondHit;
|
||||
public override bool AllJudged => processedSecondHit && base.AllJudged;
|
||||
|
||||
protected override void CheckForJudgements(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (!base.AllJudged)
|
||||
if (!SecondHitAllowed)
|
||||
{
|
||||
base.CheckForJudgements(userTriggered, timeOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!userTriggered)
|
||||
{
|
||||
if (timeOffset > second_hit_window)
|
||||
AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Miss });
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here, we're assured that the key pressed is the correct secondary key
|
||||
|
||||
if (Math.Abs(firstHitTime - Time.Current) < second_hit_window)
|
||||
{
|
||||
AddJudgement(new TaikoStrongHitJudgement());
|
||||
processedSecondHit = true;
|
||||
}
|
||||
AddJudgement(new TaikoStrongHitJudgement { Result = HitResult.Great });
|
||||
}
|
||||
|
||||
public override bool OnReleased(TaikoAction action)
|
||||
@@ -56,8 +55,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
|
||||
public override bool OnPressed(TaikoAction action)
|
||||
{
|
||||
if (AllJudged)
|
||||
return false;
|
||||
|
||||
// Check if we've handled the first key
|
||||
if (!base.AllJudged)
|
||||
if (!SecondHitAllowed)
|
||||
{
|
||||
// First key hasn't been handled yet, attempt to handle it
|
||||
bool handled = base.OnPressed(action);
|
||||
@@ -72,10 +74,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
||||
return handled;
|
||||
}
|
||||
|
||||
// If we've already hit the second key, don't handle this object any further
|
||||
if (processedSecondHit)
|
||||
return false;
|
||||
|
||||
// Don't handle represses of the first key
|
||||
if (firstHitAction == action)
|
||||
return false;
|
||||
|
||||
@@ -244,7 +244,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
if (judgedObject.X >= -0.05f && judgedObject is DrawableHit)
|
||||
{
|
||||
// If we're far enough away from the left stage, we should bring outselves in front of it
|
||||
topLevelHitContainer.Add(judgedObject.CreateProxy());
|
||||
// Todo: The following try-catch is temporary for replay rewinding support
|
||||
try
|
||||
{
|
||||
topLevelHitContainer.Add(judgedObject.CreateProxy());
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
hitExplosionContainer.Add(new HitExplosion(judgedObject, isRim));
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public class TestCaseIntroSequence : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(OsuLogo),
|
||||
};
|
||||
|
||||
public TestCaseIntroSequence()
|
||||
{
|
||||
OsuLogo logo;
|
||||
|
||||
var rateAdjustClock = new StopwatchClock(true);
|
||||
var framedClock = new FramedClock(rateAdjustClock);
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
Add(new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = framedClock,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
logo = new OsuLogo
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AddStep(@"Restart", logo.PlayIntro);
|
||||
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public class TestCaseOsuGame : OsuTestCase
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(OsuLogo),
|
||||
};
|
||||
|
||||
public TestCaseOsuGame()
|
||||
{
|
||||
var rateAdjustClock = new StopwatchClock(true);
|
||||
var framedClock = new FramedClock(rateAdjustClock);
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
});
|
||||
|
||||
Add(new Loader());
|
||||
|
||||
AddSliderStep("Playback speed", 0.0, 2.0, 1, v => rateAdjustClock.Rate = v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,11 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
@@ -61,7 +64,7 @@ namespace osu.Game.Tests.Visual
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249",
|
||||
Hash = new MemoryStream(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString())).ComputeMD5Hash(),
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.HUD;
|
||||
using osu.Game.Screens.Play.ReplaySettings;
|
||||
|
||||
namespace osu.Game.Tests.Visual
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("Show cookiezi", () => ranks.User = new User { Id = 124493 });
|
||||
AddStep("Show cookiezi", () => ranks.User.Value = new User { Id = 124493 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<Compile Include="Visual\TestCaseGamefield.cs" />
|
||||
<Compile Include="Visual\TestCaseGraph.cs" />
|
||||
<Compile Include="Visual\TestCaseIconButton.cs" />
|
||||
<Compile Include="Visual\TestCaseIntroSequence.cs" />
|
||||
<Compile Include="Visual\TestCaseKeyConfiguration.cs" />
|
||||
<Compile Include="Visual\TestCaseKeyCounter.cs" />
|
||||
<Compile Include="Visual\TestCaseLeaderboard.cs" />
|
||||
@@ -121,6 +122,7 @@
|
||||
<Compile Include="Visual\TestCaseNotificationOverlay.cs" />
|
||||
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
|
||||
<Compile Include="Visual\TestCaseAllPlayers.cs" />
|
||||
<Compile Include="Visual\TestCaseOsuGame.cs" />
|
||||
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
|
||||
<Compile Include="Visual\TestCaseReplay.cs" />
|
||||
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
|
||||
|
||||
@@ -6,12 +6,13 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable
|
||||
public class BeatmapInfo : IEquatable<BeatmapInfo>, IJsonSerializable, IHasPrimaryKey
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int ID { get; set; }
|
||||
@@ -19,12 +20,23 @@ namespace osu.Game.Beatmaps
|
||||
//TODO: should be in database
|
||||
public int BeatmapVersion;
|
||||
|
||||
private int? onlineBeatmapID;
|
||||
private int? onlineBeatmapSetID;
|
||||
|
||||
[JsonProperty("id")]
|
||||
public int? OnlineBeatmapID { get; set; }
|
||||
public int? OnlineBeatmapID
|
||||
{
|
||||
get { return onlineBeatmapID; }
|
||||
set { onlineBeatmapID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
[JsonProperty("beatmapset_id")]
|
||||
[NotMapped]
|
||||
public int? OnlineBeatmapSetID { get; set; }
|
||||
public int? OnlineBeatmapSetID
|
||||
{
|
||||
get { return onlineBeatmapSetID; }
|
||||
set { onlineBeatmapSetID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
public int BeatmapSetInfoID { get; set; }
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Ionic.Zip;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -244,11 +245,17 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
request.Success += data =>
|
||||
{
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
downloadNotification.Text = $"Importing {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}";
|
||||
|
||||
using (var stream = new MemoryStream(data))
|
||||
using (var archive = new OszArchiveReader(stream))
|
||||
Import(archive);
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
// This gets scheduled back to the update thread, but we want the import to run in the background.
|
||||
using (var stream = new MemoryStream(data))
|
||||
using (var archive = new OszArchiveReader(stream))
|
||||
Import(archive);
|
||||
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
|
||||
currentDownloads.Remove(request);
|
||||
};
|
||||
@@ -272,7 +279,7 @@ namespace osu.Game.Beatmaps
|
||||
PostNotification?.Invoke(downloadNotification);
|
||||
|
||||
// don't run in the main api queue as this is a long-running task.
|
||||
Task.Run(() => request.Perform(api));
|
||||
Task.Factory.StartNew(() => request.Perform(api), TaskCreationOptions.LongRunning);
|
||||
|
||||
return request;
|
||||
}
|
||||
@@ -372,7 +379,7 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||
public BeatmapSetInfo QueryBeatmapSet(Func<BeatmapSetInfo, bool> query) => beatmaps.BeatmapSets.FirstOrDefault(query);
|
||||
public BeatmapSetInfo QueryBeatmapSet(Expression<Func<BeatmapSetInfo, bool>> query) => beatmaps.BeatmapSets.AsNoTracking().FirstOrDefault(query);
|
||||
|
||||
/// <summary>
|
||||
/// Refresh an existing instance of a <see cref="BeatmapSetInfo"/> from the store.
|
||||
@@ -386,21 +393,21 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public List<BeatmapSetInfo> QueryBeatmapSets(Func<BeatmapSetInfo, bool> query) => beatmaps.BeatmapSets.Where(query).ToList();
|
||||
public IEnumerable<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query) => beatmaps.BeatmapSets.AsNoTracking().Where(query);
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query) => beatmaps.Beatmaps.FirstOrDefault(query);
|
||||
public BeatmapInfo QueryBeatmap(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().FirstOrDefault(query);
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public List<BeatmapInfo> QueryBeatmaps(Func<BeatmapInfo, bool> query) => beatmaps.Beatmaps.Where(query).ToList();
|
||||
public IEnumerable<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.Beatmaps.AsNoTracking().Where(query);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="ArchiveReader"/> from a valid storage path.
|
||||
|
||||
@@ -14,8 +14,15 @@ namespace osu.Game.Beatmaps
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int ID { get; set; }
|
||||
|
||||
private int? onlineBeatmapSetID;
|
||||
|
||||
[NotMapped]
|
||||
public int? OnlineBeatmapSetID { get; set; }
|
||||
[JsonProperty(@"id")]
|
||||
public int? OnlineBeatmapSetID
|
||||
{
|
||||
get { return onlineBeatmapSetID; }
|
||||
set { onlineBeatmapSetID = value > 0 ? value : null; }
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string TitleUnicode { get; set; }
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
public class BeatmapSetInfo
|
||||
public class BeatmapSetInfo : IHasPrimaryKey
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int ID { get; set; }
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Game.Database;
|
||||
@@ -25,21 +24,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
// https://stackoverflow.com/a/10450893
|
||||
context.Database.ExecuteSqlCommand("DELETE FROM BeatmapMetadata");
|
||||
context.Database.ExecuteSqlCommand("DELETE FROM BeatmapDifficulty");
|
||||
context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetInfo");
|
||||
context.Database.ExecuteSqlCommand("DELETE FROM BeatmapSetFileInfo");
|
||||
context.Database.ExecuteSqlCommand("DELETE FROM BeatmapInfo");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a <see cref="BeatmapSetInfo"/> to the database.
|
||||
/// </summary>
|
||||
@@ -63,10 +47,10 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
if (beatmapSet.DeletePending) return false;
|
||||
Refresh(ref beatmapSet, BeatmapSets);
|
||||
|
||||
if (beatmapSet.DeletePending) return false;
|
||||
beatmapSet.DeletePending = true;
|
||||
context.Update(beatmapSet);
|
||||
context.SaveChanges();
|
||||
|
||||
BeatmapSetRemoved?.Invoke(beatmapSet);
|
||||
@@ -82,10 +66,10 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
if (!beatmapSet.DeletePending) return false;
|
||||
Refresh(ref beatmapSet, BeatmapSets);
|
||||
|
||||
if (!beatmapSet.DeletePending) return false;
|
||||
beatmapSet.DeletePending = false;
|
||||
context.Update(beatmapSet);
|
||||
context.SaveChanges();
|
||||
|
||||
BeatmapSetAdded?.Invoke(beatmapSet);
|
||||
@@ -101,10 +85,10 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
if (beatmap.Hidden) return false;
|
||||
Refresh(ref beatmap, Beatmaps);
|
||||
|
||||
if (beatmap.Hidden) return false;
|
||||
beatmap.Hidden = true;
|
||||
context.Update(beatmap);
|
||||
context.SaveChanges();
|
||||
|
||||
BeatmapHidden?.Invoke(beatmap);
|
||||
@@ -120,10 +104,10 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
if (!beatmap.Hidden) return false;
|
||||
Refresh(ref beatmap, Beatmaps);
|
||||
|
||||
if (!beatmap.Hidden) return false;
|
||||
beatmap.Hidden = false;
|
||||
context.Update(beatmap);
|
||||
context.SaveChanges();
|
||||
|
||||
BeatmapRestored?.Invoke(beatmap);
|
||||
@@ -151,17 +135,17 @@ namespace osu.Game.Beatmaps
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
public IEnumerable<BeatmapSetInfo> BeatmapSets => GetContext().BeatmapSetInfo
|
||||
.Include(s => s.Metadata)
|
||||
.Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
|
||||
.Include(s => s.Files).ThenInclude(f => f.FileInfo);
|
||||
public IQueryable<BeatmapSetInfo> BeatmapSets => GetContext().BeatmapSetInfo
|
||||
.Include(s => s.Metadata)
|
||||
.Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
|
||||
.Include(s => s.Files).ThenInclude(f => f.FileInfo);
|
||||
|
||||
public IEnumerable<BeatmapInfo> Beatmaps => GetContext().BeatmapInfo
|
||||
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
||||
.Include(b => b.Metadata)
|
||||
.Include(b => b.Ruleset)
|
||||
.Include(b => b.BaseDifficulty);
|
||||
public IQueryable<BeatmapInfo> Beatmaps => GetContext().BeatmapInfo
|
||||
.Include(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
||||
.Include(b => b.Metadata)
|
||||
.Include(b => b.Ruleset)
|
||||
.Include(b => b.BaseDifficulty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Lists;
|
||||
@@ -85,6 +86,9 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
private T binarySearch<T>(SortedList<T> list, double time, T prePoint = null)
|
||||
where T : ControlPoint, new()
|
||||
{
|
||||
if (list == null)
|
||||
throw new ArgumentNullException(nameof(list));
|
||||
|
||||
if (list.Count == 0)
|
||||
return new T();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
|
||||
@@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public BeatmapBackgroundSprite(WorkingBeatmap working)
|
||||
{
|
||||
if (working == null)
|
||||
throw new ArgumentNullException(nameof(working));
|
||||
|
||||
this.working = working;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,11 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public BeatmapGroup(BeatmapSetInfo beatmapSet, BeatmapManager manager)
|
||||
{
|
||||
if (beatmapSet == null)
|
||||
throw new ArgumentNullException(nameof(beatmapSet));
|
||||
if (manager == null)
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
|
||||
BeatmapSet = beatmapSet;
|
||||
WorkingBeatmap beatmap = manager.GetWorkingBeatmap(BeatmapSet.Beatmaps.FirstOrDefault());
|
||||
|
||||
|
||||
@@ -73,6 +73,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public BeatmapPanel(BeatmapInfo beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
Beatmap = beatmap;
|
||||
Height *= 0.60f;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
@@ -12,6 +13,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
private readonly BeatmapSetInfo set;
|
||||
public BeatmapSetCover(BeatmapSetInfo set)
|
||||
{
|
||||
if (set == null)
|
||||
throw new ArgumentNullException(nameof(set));
|
||||
|
||||
this.set = set;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public BeatmapSetHeader(WorkingBeatmap beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
this.beatmap = beatmap;
|
||||
|
||||
Children = new Drawable[]
|
||||
@@ -88,6 +91,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(LocalisationEngine localisation)
|
||||
{
|
||||
if (localisation == null)
|
||||
throw new ArgumentNullException(nameof(localisation));
|
||||
|
||||
title.Current = localisation.GetUnicodePreference(beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title);
|
||||
artist.Current = localisation.GetUnicodePreference(beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist);
|
||||
}
|
||||
@@ -154,6 +160,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public void AddDifficultyIcons(IEnumerable<BeatmapPanel> panels)
|
||||
{
|
||||
if (panels == null)
|
||||
throw new ArgumentNullException(nameof(panels));
|
||||
|
||||
foreach (var p in panels)
|
||||
difficultyIcons.Add(new DifficultyIcon(p.Beatmap));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
@@ -23,6 +24,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour palette)
|
||||
{
|
||||
if (palette == null)
|
||||
throw new ArgumentNullException(nameof(palette));
|
||||
|
||||
this.palette = palette;
|
||||
AccentColour = getColour(beatmap);
|
||||
}
|
||||
@@ -39,6 +43,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
var rating = beatmap.StarDifficulty;
|
||||
|
||||
if (rating < 1.5) return DifficultyRating.Easy;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
@@ -15,6 +16,9 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
public DifficultyIcon(BeatmapInfo beatmap) : base(beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
this.beatmap = beatmap;
|
||||
Size = new Vector2(20);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
public static BeatmapDecoder GetDecoder(StreamReader stream)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
string line;
|
||||
do { line = stream.ReadLine()?.Trim(); }
|
||||
while (line != null && line.Length == 0);
|
||||
|
||||
@@ -70,6 +70,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleGeneral(Beatmap beatmap, string line)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var pair = splitKeyVal(line, ':');
|
||||
|
||||
var metadata = beatmap.BeatmapInfo.Metadata;
|
||||
@@ -129,6 +134,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleEditor(Beatmap beatmap, string line)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var pair = splitKeyVal(line, ':');
|
||||
|
||||
switch (pair.Key)
|
||||
@@ -153,6 +163,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleMetadata(Beatmap beatmap, string line)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var pair = splitKeyVal(line, ':');
|
||||
|
||||
var metadata = beatmap.BeatmapInfo.Metadata;
|
||||
@@ -194,6 +209,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleDifficulty(Beatmap beatmap, string line)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var pair = splitKeyVal(line, ':');
|
||||
|
||||
var difficulty = beatmap.BeatmapInfo.BaseDifficulty;
|
||||
@@ -226,6 +246,9 @@ namespace osu.Game.Beatmaps.Formats
|
||||
/// <param name="line">The line which may contains variables.</param>
|
||||
private void decodeVariables(ref string line)
|
||||
{
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
while (line.IndexOf('$') >= 0)
|
||||
{
|
||||
string origLine = line;
|
||||
@@ -244,6 +267,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleEvents(Beatmap beatmap, string line, ref StoryboardSprite storyboardSprite, ref CommandTimelineGroup timelineGroup)
|
||||
{
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
var depth = 0;
|
||||
while (line.StartsWith(" ") || line.StartsWith("_"))
|
||||
{
|
||||
@@ -469,6 +497,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleTimingPoints(Beatmap beatmap, string line)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
string[] split = line.Split(',');
|
||||
|
||||
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
||||
@@ -555,6 +588,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleColours(Beatmap beatmap, string line, ref bool hasCustomColours)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var pair = splitKeyVal(line, ':');
|
||||
|
||||
string[] split = pair.Value.Split(',');
|
||||
@@ -587,6 +625,9 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private void handleVariables(string line)
|
||||
{
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var pair = splitKeyVal(line, '=');
|
||||
variables[pair.Key] = pair.Value;
|
||||
}
|
||||
@@ -603,6 +644,11 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected override void ParseFile(StreamReader stream, Beatmap beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
|
||||
beatmap.BeatmapInfo.BeatmapVersion = beatmapVersion;
|
||||
|
||||
Section section = Section.None;
|
||||
@@ -679,6 +725,9 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private KeyValuePair<string, string> splitKeyVal(string line, char separator)
|
||||
{
|
||||
if (line == null)
|
||||
throw new ArgumentNullException(nameof(line));
|
||||
|
||||
var split = line.Trim().Split(new[] { separator }, 2);
|
||||
|
||||
return new KeyValuePair<string, string>
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
|
||||
Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details);
|
||||
|
||||
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10);
|
||||
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10);
|
||||
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
||||
Set(OsuSetting.DisplayStarsMaximum, 10.0, 0, 10, 0.1);
|
||||
|
||||
Set(OsuSetting.SelectionRandomType, SelectionRandomType.RandomPermutation);
|
||||
|
||||
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1);
|
||||
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2, 1, 0.01);
|
||||
|
||||
// Online settings
|
||||
Set(OsuSetting.Username, string.Empty);
|
||||
@@ -41,11 +41,11 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.MenuVoice, true);
|
||||
Set(OsuSetting.MenuMusic, true);
|
||||
|
||||
Set(OsuSetting.AudioOffset, 0, -500.0, 500.0);
|
||||
Set(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1);
|
||||
|
||||
// Input
|
||||
Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2);
|
||||
Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2);
|
||||
Set(OsuSetting.MenuCursorSize, 1.0, 0.5f, 2, 0.01);
|
||||
Set(OsuSetting.GameplayCursorSize, 1.0, 0.5f, 2, 0.01);
|
||||
Set(OsuSetting.AutoCursorSize, false);
|
||||
|
||||
Set(OsuSetting.MouseDisableButtons, false);
|
||||
@@ -63,13 +63,12 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.SnakingOutSliders, true);
|
||||
|
||||
// Gameplay
|
||||
Set(OsuSetting.DimLevel, 0.3, 0, 1);
|
||||
Set(OsuSetting.DimLevel, 0.3, 0, 1, 0.01);
|
||||
|
||||
Set(OsuSetting.ShowInterface, true);
|
||||
Set(OsuSetting.KeyOverlay, false);
|
||||
|
||||
Set(OsuSetting.FloatingComments, false);
|
||||
Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2);
|
||||
|
||||
// Update
|
||||
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
||||
@@ -93,7 +92,6 @@ namespace osu.Game.Configuration
|
||||
ShowStoryboard,
|
||||
KeyOverlay,
|
||||
FloatingComments,
|
||||
PlaybackSpeed,
|
||||
ShowInterface,
|
||||
MouseDisableButtons,
|
||||
MouseDisableWheel,
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using osu.Framework.Logging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace osu.Game.Database
|
||||
@@ -19,6 +21,22 @@ namespace osu.Game.Database
|
||||
|
||||
private readonly ThreadLocal<OsuDbContext> queryContext;
|
||||
|
||||
/// <summary>
|
||||
/// Refresh an instance potentially from a different thread with a local context-tracked instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to use as a reference when negotiating a local instance.</param>
|
||||
/// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param>
|
||||
/// <typeparam name="T">A valid EF-stored type.</typeparam>
|
||||
protected virtual void Refresh<T>(ref T obj, IEnumerable<T> lookupSource = null) where T : class, IHasPrimaryKey
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
if (context.Entry(obj).State != EntityState.Detached) return;
|
||||
|
||||
var id = obj.ID;
|
||||
obj = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a shared context for performing lookups (or write operations on the update thread, for now).
|
||||
/// </summary>
|
||||
@@ -32,16 +50,6 @@ namespace osu.Game.Database
|
||||
queryContext = new ThreadLocal<OsuDbContext>(CreateContext);
|
||||
|
||||
Storage = storage;
|
||||
|
||||
try
|
||||
{
|
||||
Prepare();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Failed to initialise the {GetType()}! Trying again with a clean database...");
|
||||
Prepare(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,15 +58,5 @@ namespace osu.Game.Database
|
||||
public virtual void Cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare this database for use. Tables should be created here.
|
||||
/// </summary>
|
||||
protected abstract void Prepare(bool reset = false);
|
||||
|
||||
/// <summary>
|
||||
/// Reset this database to a default state. Undo all changes to database and storage backings.
|
||||
/// </summary>
|
||||
public void Reset() => Prepare(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Database
|
||||
{
|
||||
public interface IHasPrimaryKey
|
||||
{
|
||||
int ID { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -78,11 +78,12 @@ namespace osu.Game.Database
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.MD5Hash);
|
||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.Hash);
|
||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.MD5Hash).IsUnique();
|
||||
modelBuilder.Entity<BeatmapInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||
|
||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.OnlineBeatmapSetID).IsUnique();
|
||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.DeletePending);
|
||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.Hash);
|
||||
modelBuilder.Entity<BeatmapSetInfo>().HasIndex(b => b.Hash).IsUnique();
|
||||
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.Variant);
|
||||
modelBuilder.Entity<DatabasedKeyBinding>().HasIndex(b => b.IntAction);
|
||||
@@ -251,7 +252,7 @@ namespace osu.Game.Database
|
||||
Database.ExecuteSqlCommand("DROP TABLE RulesetInfo_Old");
|
||||
|
||||
Database.ExecuteSqlCommand(
|
||||
"INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, IFNULL(Hidden, 0), LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old");
|
||||
"INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, IFNULL(Hidden, 0), LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), NULLIF(OnlineBeatmapID, 0), Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old");
|
||||
Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old");
|
||||
|
||||
Logger.Log("Migration complete!", LoggingTarget.Database, Framework.Logging.LogLevel.Important);
|
||||
|
||||
@@ -11,7 +11,7 @@ using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
internal class ParallaxContainer : Container, IRequireHighFrequencyMousePosition
|
||||
public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition
|
||||
{
|
||||
public float ParallaxAmount = 0.02f;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.MathUtils;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
|
||||
namespace osu.Game.Graphics.Sprites
|
||||
{
|
||||
@@ -40,4 +41,23 @@ namespace osu.Game.Graphics.Sprites
|
||||
return base.CreateFallbackCharacterDrawable();
|
||||
}
|
||||
}
|
||||
|
||||
public static class OsuSpriteTextTransformExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
|
||||
public static TransformSequence<T> TransformTextTo<T>(this T spriteText, string newText, double duration = 0, Easing easing = Easing.None)
|
||||
where T : OsuSpriteText
|
||||
=> spriteText.TransformTo(nameof(OsuSpriteText.Text), newText, duration, easing);
|
||||
|
||||
/// <summary>
|
||||
/// Sets <see cref="OsuSpriteText.Text"/> to a new value after a duration.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="TransformSequence{T}"/> to which further transforms can be added.</returns>
|
||||
public static TransformSequence<T> TransformTextTo<T>(this TransformSequence<T> t, string newText, double duration = 0, Easing easing = Easing.None)
|
||||
where T : OsuSpriteText
|
||||
=> t.Append(o => o.TransformTextTo(newText, duration, easing));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Logging;
|
||||
@@ -27,17 +26,6 @@ namespace osu.Game.IO
|
||||
Store = new StorageBackedResourceStore(Storage);
|
||||
}
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
{
|
||||
if (Storage.ExistsDirectory(string.Empty))
|
||||
Storage.DeleteDirectory(string.Empty);
|
||||
|
||||
GetContext().Database.ExecuteSqlCommand("DELETE FROM FileInfo");
|
||||
}
|
||||
}
|
||||
|
||||
public FileInfo Add(Stream data, bool reference = true)
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Input.Bindings
|
||||
{
|
||||
[Table("KeyBinding")]
|
||||
public class DatabasedKeyBinding : KeyBinding
|
||||
public class DatabasedKeyBinding : KeyBinding, IHasPrimaryKey
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int ID { get; set; }
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
@@ -30,12 +29,6 @@ namespace osu.Game.Input
|
||||
|
||||
public void Register(KeyBindingInputManager manager) => insertDefaults(manager.DefaultKeyBindings);
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
GetContext().Database.ExecuteSqlCommand("DELETE FROM KeyBinding");
|
||||
}
|
||||
|
||||
private void insertDefaults(IEnumerable<KeyBinding> defaults, int? rulesetId = null, int? variant = null)
|
||||
{
|
||||
var context = GetContext();
|
||||
@@ -67,18 +60,24 @@ namespace osu.Game.Input
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve <see cref="KeyBinding"/>s for a specified ruleset/variant content.
|
||||
/// Retrieve <see cref="DatabasedKeyBinding"/>s for a specified ruleset/variant content.
|
||||
/// </summary>
|
||||
/// <param name="rulesetId">The ruleset's internal ID.</param>
|
||||
/// <param name="variant">An optional variant.</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<KeyBinding> Query(int? rulesetId = null, int? variant = null) =>
|
||||
GetContext().DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant);
|
||||
public List<DatabasedKeyBinding> Query(int? rulesetId = null, int? variant = null) =>
|
||||
GetContext().DatabasedKeyBinding.Where(b => b.RulesetID == rulesetId && b.Variant == variant).ToList();
|
||||
|
||||
public void Update(KeyBinding keyBinding)
|
||||
{
|
||||
var dbKeyBinding = (DatabasedKeyBinding)keyBinding;
|
||||
|
||||
var context = GetContext();
|
||||
context.Update(keyBinding);
|
||||
|
||||
Refresh(ref dbKeyBinding);
|
||||
|
||||
dbKeyBinding.KeyCombination = keyBinding.KeyCombination;
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
KeyBindingChanged?.Invoke();
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using osu.Game.Database;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
[DbContext(typeof(OsuDbContext))]
|
||||
[Migration("20171025071459_AddMissingIndexRules")]
|
||||
partial class AddMissingIndexRules
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.0-rtm-26452");
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<float>("ApproachRate");
|
||||
|
||||
b.Property<float>("CircleSize");
|
||||
|
||||
b.Property<float>("DrainRate");
|
||||
|
||||
b.Property<float>("OverallDifficulty");
|
||||
|
||||
b.Property<float>("SliderMultiplier");
|
||||
|
||||
b.Property<float>("SliderTickRate");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("BeatmapDifficulty");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AudioLeadIn");
|
||||
|
||||
b.Property<int>("BaseDifficultyID");
|
||||
|
||||
b.Property<int>("BeatDivisor");
|
||||
|
||||
b.Property<int>("BeatmapSetInfoID");
|
||||
|
||||
b.Property<bool>("Countdown");
|
||||
|
||||
b.Property<double>("DistanceSpacing");
|
||||
|
||||
b.Property<int>("GridSize");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<bool>("Hidden");
|
||||
|
||||
b.Property<bool>("LetterboxInBreaks");
|
||||
|
||||
b.Property<string>("MD5Hash");
|
||||
|
||||
b.Property<int?>("MetadataID");
|
||||
|
||||
b.Property<int?>("OnlineBeatmapID");
|
||||
|
||||
b.Property<string>("Path");
|
||||
|
||||
b.Property<int>("RulesetID");
|
||||
|
||||
b.Property<bool>("SpecialStyle");
|
||||
|
||||
b.Property<float>("StackLeniency");
|
||||
|
||||
b.Property<double>("StarDifficulty");
|
||||
|
||||
b.Property<string>("StoredBookmarks");
|
||||
|
||||
b.Property<double>("TimelineZoom");
|
||||
|
||||
b.Property<string>("Version");
|
||||
|
||||
b.Property<bool>("WidescreenStoryboard");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BaseDifficultyID");
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MD5Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("RulesetID");
|
||||
|
||||
b.ToTable("BeatmapInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Artist");
|
||||
|
||||
b.Property<string>("ArtistUnicode");
|
||||
|
||||
b.Property<string>("AudioFile");
|
||||
|
||||
b.Property<string>("AuthorString")
|
||||
.HasColumnName("Author");
|
||||
|
||||
b.Property<string>("BackgroundFile");
|
||||
|
||||
b.Property<int>("PreviewTime");
|
||||
|
||||
b.Property<string>("Source");
|
||||
|
||||
b.Property<string>("Tags");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("TitleUnicode");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.ToTable("BeatmapMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("BeatmapSetInfoID");
|
||||
|
||||
b.Property<int>("FileInfoID");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("FileInfoID");
|
||||
|
||||
b.ToTable("BeatmapSetFileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("DeletePending");
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int?>("MetadataID");
|
||||
|
||||
b.Property<int?>("OnlineBeatmapSetID");
|
||||
|
||||
b.Property<bool>("Protected");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("DeletePending");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("OnlineBeatmapSetID")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("BeatmapSetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("IntAction")
|
||||
.HasColumnName("Action");
|
||||
|
||||
b.Property<string>("KeysString")
|
||||
.HasColumnName("Keys");
|
||||
|
||||
b.Property<int?>("RulesetID");
|
||||
|
||||
b.Property<int?>("Variant");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("IntAction");
|
||||
|
||||
b.HasIndex("Variant");
|
||||
|
||||
b.ToTable("KeyBinding");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int>("ReferenceCount");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ReferenceCount");
|
||||
|
||||
b.ToTable("FileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||
{
|
||||
b.Property<int?>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Available");
|
||||
|
||||
b.Property<string>("InstantiationInfo");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Available");
|
||||
|
||||
b.ToTable("RulesetInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
|
||||
.WithMany()
|
||||
.HasForeignKey("BaseDifficultyID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
|
||||
.WithMany("Beatmaps")
|
||||
.HasForeignKey("BeatmapSetInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||
.WithMany("Beatmaps")
|
||||
.HasForeignKey("MetadataID");
|
||||
|
||||
b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
|
||||
.WithMany()
|
||||
.HasForeignKey("RulesetID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
|
||||
.WithMany("Files")
|
||||
.HasForeignKey("BeatmapSetInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
|
||||
.WithMany()
|
||||
.HasForeignKey("FileInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
|
||||
.WithMany("BeatmapSets")
|
||||
.HasForeignKey("MetadataID");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace osu.Game.Migrations
|
||||
{
|
||||
public partial class AddMissingIndexRules : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapSetInfo_Hash",
|
||||
table: "BeatmapSetInfo");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapInfo_Hash",
|
||||
table: "BeatmapInfo");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapInfo_MD5Hash",
|
||||
table: "BeatmapInfo");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapSetInfo_Hash",
|
||||
table: "BeatmapSetInfo",
|
||||
column: "Hash",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapSetInfo_OnlineBeatmapSetID",
|
||||
table: "BeatmapSetInfo",
|
||||
column: "OnlineBeatmapSetID",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapInfo_Hash",
|
||||
table: "BeatmapInfo",
|
||||
column: "Hash",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapInfo_MD5Hash",
|
||||
table: "BeatmapInfo",
|
||||
column: "MD5Hash",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapSetInfo_Hash",
|
||||
table: "BeatmapSetInfo");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapSetInfo_OnlineBeatmapSetID",
|
||||
table: "BeatmapSetInfo");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapInfo_Hash",
|
||||
table: "BeatmapInfo");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_BeatmapInfo_MD5Hash",
|
||||
table: "BeatmapInfo");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapSetInfo_Hash",
|
||||
table: "BeatmapSetInfo",
|
||||
column: "Hash");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapInfo_Hash",
|
||||
table: "BeatmapInfo",
|
||||
column: "Hash");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_BeatmapInfo_MD5Hash",
|
||||
table: "BeatmapInfo",
|
||||
column: "MD5Hash");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,9 +95,11 @@ namespace osu.Game.Migrations
|
||||
|
||||
b.HasIndex("BeatmapSetInfoID");
|
||||
|
||||
b.HasIndex("Hash");
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MD5Hash");
|
||||
b.HasIndex("MD5Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
@@ -177,10 +179,14 @@ namespace osu.Game.Migrations
|
||||
|
||||
b.HasIndex("DeletePending");
|
||||
|
||||
b.HasIndex("Hash");
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("MetadataID");
|
||||
|
||||
b.HasIndex("OnlineBeatmapSetID")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("BeatmapSetInfo");
|
||||
});
|
||||
|
||||
|
||||
@@ -118,6 +118,7 @@ namespace osu.Game.Online.API
|
||||
//NotificationOverlay.ShowMessage("Login failed!");
|
||||
log.Add(@"Login failed!");
|
||||
Password = null;
|
||||
authentication.Clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace osu.Game.Online.API
|
||||
return request;
|
||||
}
|
||||
|
||||
private void request_Progress(WebRequest request, long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); });
|
||||
private void request_Progress(long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); });
|
||||
|
||||
protected APIDownloadRequest()
|
||||
{
|
||||
@@ -99,8 +99,8 @@ namespace osu.Game.Online.API
|
||||
throw new TimeoutException(@"API request timeout hit");
|
||||
|
||||
WebRequest = CreateWebRequest();
|
||||
WebRequest.RetryCount = 0;
|
||||
WebRequest.Headers[@"Authorization"] = $@"Bearer {api.AccessToken}";
|
||||
WebRequest.AllowRetryOnTimeout = false;
|
||||
WebRequest.AddHeader("Authorization", $"Bearer {api.AccessToken}");
|
||||
|
||||
if (checkAndProcessFailure())
|
||||
return;
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace osu.Game.Online.API
|
||||
|
||||
internal bool AuthenticateWithLogin(string username, string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(username)) return false;
|
||||
if (string.IsNullOrEmpty(password)) return false;
|
||||
|
||||
using (var req = new AccessTokenRequestPassword(username, password)
|
||||
{
|
||||
Url = $@"{endpoint}/oauth/token",
|
||||
@@ -127,7 +130,8 @@ namespace osu.Game.Online.API
|
||||
|
||||
protected override void PrePerform()
|
||||
{
|
||||
Parameters[@"refresh_token"] = RefreshToken;
|
||||
AddParameter("refresh_token", RefreshToken);
|
||||
|
||||
base.PrePerform();
|
||||
}
|
||||
}
|
||||
@@ -146,8 +150,9 @@ namespace osu.Game.Online.API
|
||||
|
||||
protected override void PrePerform()
|
||||
{
|
||||
Parameters[@"username"] = Username;
|
||||
Parameters[@"password"] = Password;
|
||||
AddParameter("username", Username);
|
||||
AddParameter("password", Password);
|
||||
|
||||
base.PrePerform();
|
||||
}
|
||||
}
|
||||
@@ -161,9 +166,10 @@ namespace osu.Game.Online.API
|
||||
|
||||
protected override void PrePerform()
|
||||
{
|
||||
Parameters[@"grant_type"] = GrantType;
|
||||
Parameters[@"client_id"] = ClientId;
|
||||
Parameters[@"client_secret"] = ClientSecret;
|
||||
AddParameter("grant_type", GrantType);
|
||||
AddParameter("client_id", ClientId);
|
||||
AddParameter("client_secret", ClientSecret);
|
||||
|
||||
base.PrePerform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ using osu.Game.Rulesets;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class GetBeatmapSetsResponse : BeatmapMetadata
|
||||
public class GetBeatmapSetsResponse : BeatmapMetadata // todo: this is a bit wrong...
|
||||
{
|
||||
[JsonProperty(@"covers")]
|
||||
private BeatmapSetOnlineCovers covers { get; set; }
|
||||
@@ -23,9 +23,6 @@ namespace osu.Game.Online.API.Requests
|
||||
[JsonProperty(@"favourite_count")]
|
||||
private int favouriteCount { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
private int onlineId { get; set; }
|
||||
|
||||
[JsonProperty(@"user_id")]
|
||||
private long creatorId {
|
||||
set { Author.Id = value; }
|
||||
@@ -38,7 +35,7 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = onlineId,
|
||||
OnlineBeatmapSetID = OnlineBeatmapSetID,
|
||||
Metadata = this,
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
|
||||
@@ -88,6 +88,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
};
|
||||
}
|
||||
|
||||
public void StopPreview() => preview.Playing.Value = false;
|
||||
|
||||
private class DetailBox : Container
|
||||
{
|
||||
private readonly Container content;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly Container coverContainer;
|
||||
private readonly OsuSpriteText title, artist;
|
||||
private readonly AuthorInfo author;
|
||||
private readonly Details details;
|
||||
public Details Details;
|
||||
|
||||
private DelayedLoadWrapper cover;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
if (value == beatmapSet) return;
|
||||
beatmapSet = value;
|
||||
|
||||
Picker.BeatmapSet = author.BeatmapSet = details.BeatmapSet = BeatmapSet;
|
||||
Picker.BeatmapSet = author.BeatmapSet = Details.BeatmapSet = BeatmapSet;
|
||||
title.Text = BeatmapSet.Metadata.Title;
|
||||
artist.Text = BeatmapSet.Metadata.Artist;
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
},
|
||||
},
|
||||
details = new Details
|
||||
Details = new Details
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
@@ -204,7 +204,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
Picker.Beatmap.ValueChanged += b =>
|
||||
{
|
||||
details.Beatmap = b;
|
||||
Details.Beatmap = b;
|
||||
|
||||
if (b.OnlineInfo.HasVideo)
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
private readonly PlayButton playButton;
|
||||
|
||||
private Track preview => playButton.Preview;
|
||||
private Bindable<bool> playing => playButton.Playing;
|
||||
public Bindable<bool> Playing => playButton.Playing;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet
|
||||
{
|
||||
@@ -66,8 +66,8 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
},
|
||||
};
|
||||
|
||||
Action = () => playing.Value = !playing.Value;
|
||||
playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100);
|
||||
Action = () => Playing.Value = !Playing.Value;
|
||||
Playing.ValueChanged += newValue => progress.FadeTo(newValue ? 1 : 0, 100);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@@ -80,7 +80,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (playing.Value && preview != null)
|
||||
if (Playing.Value && preview != null)
|
||||
{
|
||||
progress.Width = (float)(preview.CurrentTime / preview.Length);
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
playing.Value = false;
|
||||
Playing.Value = false;
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ namespace osu.Game.Overlays
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
header.Details.StopPreview();
|
||||
FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
@@ -65,9 +66,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags));
|
||||
|
||||
if (beatmapSets.Any() && panels == null)
|
||||
// real use case? currently only seems to be for test case
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,13 +273,17 @@ namespace osu.Game.Overlays
|
||||
Filter.DisplayStyleControl.Dropdown.Current.Value,
|
||||
Filter.Tabs.Current.Value); //todo: sort direction (?)
|
||||
|
||||
getSetsRequest.Success += r =>
|
||||
getSetsRequest.Success += response =>
|
||||
{
|
||||
BeatmapSets = r?.
|
||||
Select(response => response.ToBeatmapSet(rulesets)).
|
||||
Where(b => beatmaps.QueryBeatmapSet(q => q.OnlineBeatmapSetID == b.OnlineBeatmapSetID) == null);
|
||||
Task.Run(() =>
|
||||
{
|
||||
var onlineIds = response.Select(r => r.OnlineBeatmapSetID).ToList();
|
||||
var presentOnlineIds = beatmaps.QueryBeatmapSets(s => onlineIds.Contains(s.OnlineBeatmapSetID)).Select(r => r.OnlineBeatmapSetID).ToList();
|
||||
var sets = response.Select(r => r.ToBeatmapSet(rulesets)).Where(b => !presentOnlineIds.Contains(b.OnlineBeatmapSetID)).ToList();
|
||||
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
// may not need scheduling; loads async internally.
|
||||
Schedule(() => BeatmapSets = sets);
|
||||
});
|
||||
};
|
||||
|
||||
api.Queue(getSetsRequest);
|
||||
|
||||
@@ -9,6 +9,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Users;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Overlays.Profile
|
||||
{
|
||||
@@ -22,13 +23,7 @@ namespace osu.Game.Overlays.Profile
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
public virtual User User
|
||||
{
|
||||
get { return user; }
|
||||
set { user = value; }
|
||||
}
|
||||
|
||||
private User user;
|
||||
public readonly Bindable<User> User = new Bindable<User>();
|
||||
|
||||
protected ProfileSection()
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -33,6 +32,9 @@ namespace osu.Game.Overlays.Profile
|
||||
{
|
||||
this.user = user;
|
||||
|
||||
int[] userRanks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank };
|
||||
ranks = userRanks.SkipWhile(x => x == 0).ToArray();
|
||||
|
||||
Padding = new MarginPadding { Vertical = padding };
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@@ -58,19 +60,21 @@ namespace osu.Game.Overlays.Profile
|
||||
Font = @"Exo2.0-RegularItalic",
|
||||
TextSize = secondary_textsize
|
||||
},
|
||||
graph = new RankChartLineGraph
|
||||
};
|
||||
|
||||
if (ranks.Length > 0)
|
||||
{
|
||||
Add(graph = new RankChartLineGraph
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Y = -secondary_textsize,
|
||||
DefaultValueCount = 90,
|
||||
BallRelease = updateRankTexts,
|
||||
BallMove = showHistoryRankTexts
|
||||
}
|
||||
};
|
||||
DefaultValueCount = ranks.Length,
|
||||
});
|
||||
|
||||
ranks = user.RankHistory?.Data ?? new[] { user.Statistics.Rank };
|
||||
graph.OnBallMove += showHistoryRankTexts;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRankTexts()
|
||||
@@ -82,7 +86,8 @@ namespace osu.Game.Overlays.Profile
|
||||
|
||||
private void showHistoryRankTexts(int dayIndex)
|
||||
{
|
||||
rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank";
|
||||
rankText.Text = $"#{ranks[dayIndex]:#,0}";
|
||||
dayIndex++;
|
||||
relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago";
|
||||
//plural should be handled in a general way
|
||||
}
|
||||
@@ -90,14 +95,15 @@ namespace osu.Game.Overlays.Profile
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
graph.Colour = colours.Yellow;
|
||||
|
||||
if (user.Statistics.Rank > 0)
|
||||
if (graph != null)
|
||||
{
|
||||
graph.Colour = colours.Yellow;
|
||||
// use logarithmic coordinates
|
||||
graph.Values = ranks.Select(x => -(float)Math.Log(x));
|
||||
graph.ResetBall();
|
||||
graph.SetStaticBallPosition();
|
||||
}
|
||||
|
||||
updateRankTexts();
|
||||
}
|
||||
|
||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||
@@ -110,67 +116,78 @@ namespace osu.Game.Overlays.Profile
|
||||
return base.Invalidate(invalidation, source, shallPropagate);
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
graph?.UpdateBallPosition(state.Mouse.Position.X);
|
||||
graph?.ShowBall();
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(InputState state)
|
||||
{
|
||||
graph?.UpdateBallPosition(state.Mouse.Position.X);
|
||||
return base.OnMouseMove(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
graph.HideBall();
|
||||
updateRankTexts();
|
||||
}
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
private class RankChartLineGraph : LineGraph
|
||||
{
|
||||
private readonly CircularContainer ball;
|
||||
private bool ballShown;
|
||||
private const double fade_duration = 200;
|
||||
|
||||
private const double transform_duration = 100;
|
||||
private readonly CircularContainer staticBall;
|
||||
private readonly CircularContainer movingBall;
|
||||
|
||||
public Action<int> BallMove;
|
||||
public Action BallRelease;
|
||||
public Action<int> OnBallMove;
|
||||
|
||||
public RankChartLineGraph()
|
||||
{
|
||||
Add(ball = new CircularContainer
|
||||
Add(staticBall = new CircularContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(8),
|
||||
Masking = true,
|
||||
Origin = Anchor.Centre,
|
||||
Alpha = 0,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
||||
});
|
||||
Add(movingBall = new CircularContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(8),
|
||||
Alpha = 0,
|
||||
Masking = true,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
||||
});
|
||||
}
|
||||
|
||||
public void ResetBall()
|
||||
public void SetStaticBallPosition() => staticBall.Position = new Vector2(1, GetYPosition(Values.Last()));
|
||||
|
||||
public void UpdateBallPosition(float mouseXPosition)
|
||||
{
|
||||
ball.MoveTo(new Vector2(1, GetYPosition(Values.Last())), ballShown ? transform_duration : 0, Easing.OutQuint);
|
||||
ball.Show();
|
||||
BallRelease();
|
||||
ballShown = true;
|
||||
int index = calculateIndex(mouseXPosition);
|
||||
movingBall.Position = calculateBallPosition(index);
|
||||
OnBallMove.Invoke(index);
|
||||
}
|
||||
|
||||
protected override bool OnMouseMove(InputState state)
|
||||
{
|
||||
if (ballShown)
|
||||
{
|
||||
var values = (IList<float>)Values;
|
||||
var position = ToLocalSpace(state.Mouse.NativeState.Position);
|
||||
int count = Math.Max(values.Count, DefaultValueCount);
|
||||
int index = (int)Math.Round(position.X / DrawWidth * (count - 1));
|
||||
if (index >= count - values.Count)
|
||||
{
|
||||
int i = index + values.Count - count;
|
||||
float y = GetYPosition(values[i]);
|
||||
if (Math.Abs(y * DrawHeight - position.Y) <= 8f)
|
||||
{
|
||||
ball.MoveTo(new Vector2(index / (float)(count - 1), y), transform_duration, Easing.OutQuint);
|
||||
BallMove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.OnMouseMove(state);
|
||||
}
|
||||
public void ShowBall() => movingBall.FadeIn(fade_duration);
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
public void HideBall() => movingBall.FadeOut(fade_duration);
|
||||
|
||||
private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
|
||||
|
||||
private Vector2 calculateBallPosition(int index)
|
||||
{
|
||||
if (ballShown)
|
||||
ResetBall();
|
||||
base.OnHoverLost(state);
|
||||
float y = GetYPosition(Values.ElementAt(index));
|
||||
return new Vector2(index / (float)(DefaultValueCount - 1), y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
public class HistoricalSection : ProfileSection
|
||||
@@ -8,5 +11,10 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
public override string Title => "Historical";
|
||||
|
||||
public override string Identifier => "historical";
|
||||
|
||||
public HistoricalSection()
|
||||
{
|
||||
Child = new PaginatedScoreContainer(ScoreType.Recent, User, "Recent Plays (24h)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
public class DrawablePerformanceScore : DrawableScore
|
||||
{
|
||||
private readonly double? weight;
|
||||
|
||||
public DrawablePerformanceScore(Score score, double? weight = null)
|
||||
: base(score)
|
||||
{
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private new void load(OsuColour colour)
|
||||
{
|
||||
double pp = Score.PP ?? 0;
|
||||
Stats.Add(new OsuSpriteText
|
||||
{
|
||||
Text = $"{pp:0}pp",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 18,
|
||||
Font = "Exo2.0-BoldItalic",
|
||||
});
|
||||
|
||||
if (weight.HasValue)
|
||||
{
|
||||
Stats.Add(new OsuSpriteText
|
||||
{
|
||||
Text = $"weighted: {pp * weight:0}pp ({weight:P0})",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Colour = colour.GrayA,
|
||||
TextSize = 11,
|
||||
Font = "Exo2.0-RegularItalic",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,18 +18,16 @@ using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
public class DrawableScore : Container
|
||||
public abstract class DrawableScore : Container
|
||||
{
|
||||
private readonly FillFlowContainer<OsuSpriteText> stats;
|
||||
protected readonly FillFlowContainer<OsuSpriteText> Stats;
|
||||
private readonly FillFlowContainer metadata;
|
||||
private readonly ModContainer modContainer;
|
||||
private readonly Score score;
|
||||
private readonly double? weight;
|
||||
protected readonly Score Score;
|
||||
|
||||
public DrawableScore(Score score, double? weight = null)
|
||||
protected DrawableScore(Score score)
|
||||
{
|
||||
this.score = score;
|
||||
this.weight = weight;
|
||||
Score = score;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@@ -39,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
Width = 60,
|
||||
FillMode = FillMode.Fit,
|
||||
},
|
||||
stats = new FillFlowContainer<OsuSpriteText>
|
||||
Stats = new FillFlowContainer<OsuSpriteText>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
@@ -74,40 +72,18 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuColour colour, LocalisationEngine locale, BeatmapSetOverlay beatmapSetOverlay)
|
||||
{
|
||||
double pp = score.PP ?? 0;
|
||||
stats.Add(new OsuSpriteText
|
||||
Stats.Add(new OsuSpriteText
|
||||
{
|
||||
Text = $"{pp:0}pp",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 18,
|
||||
Font = "Exo2.0-BoldItalic",
|
||||
});
|
||||
|
||||
if (weight.HasValue)
|
||||
{
|
||||
stats.Add(new OsuSpriteText
|
||||
{
|
||||
Text = $"weighted: {pp * weight:0}pp ({weight:P0})",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Colour = colour.GrayA,
|
||||
TextSize = 11,
|
||||
Font = "Exo2.0-RegularItalic",
|
||||
});
|
||||
}
|
||||
|
||||
stats.Add(new OsuSpriteText
|
||||
{
|
||||
Text = $"accuracy: {score.Accuracy:P2}",
|
||||
Text = $"accuracy: {Score.Accuracy:P2}",
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Colour = colour.GrayA,
|
||||
TextSize = 11,
|
||||
Font = "Exo2.0-RegularItalic",
|
||||
Depth = -1,
|
||||
});
|
||||
|
||||
metadata.Add(new OsuHoverContainer
|
||||
@@ -115,7 +91,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Action = () =>
|
||||
{
|
||||
if (score.Beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay.ShowBeatmapSet(score.Beatmap.OnlineBeatmapSetID.Value);
|
||||
if (Score.Beatmap.OnlineBeatmapSetID.HasValue) beatmapSetOverlay?.ShowBeatmapSet(Score.Beatmap.OnlineBeatmapSetID.Value);
|
||||
},
|
||||
Child = new FillFlowContainer
|
||||
{
|
||||
@@ -125,15 +101,15 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
new OsuSpriteText
|
||||
{
|
||||
Current = locale.GetUnicodePreference(
|
||||
$"{score.Beatmap.Metadata.TitleUnicode ?? score.Beatmap.Metadata.Title} [{score.Beatmap.Version}] ",
|
||||
$"{score.Beatmap.Metadata.Title ?? score.Beatmap.Metadata.TitleUnicode} [{score.Beatmap.Version}] "
|
||||
$"{Score.Beatmap.Metadata.TitleUnicode ?? Score.Beatmap.Metadata.Title} [{Score.Beatmap.Version}] ",
|
||||
$"{Score.Beatmap.Metadata.Title ?? Score.Beatmap.Metadata.TitleUnicode} [{Score.Beatmap.Version}] "
|
||||
),
|
||||
TextSize = 15,
|
||||
Font = "Exo2.0-SemiBoldItalic",
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Current = locale.GetUnicodePreference(score.Beatmap.Metadata.ArtistUnicode, score.Beatmap.Metadata.Artist),
|
||||
Current = locale.GetUnicodePreference(Score.Beatmap.Metadata.ArtistUnicode, Score.Beatmap.Metadata.Artist),
|
||||
TextSize = 12,
|
||||
Padding = new MarginPadding { Top = 3 },
|
||||
Font = "Exo2.0-RegularItalic",
|
||||
@@ -142,7 +118,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
},
|
||||
});
|
||||
|
||||
foreach (Mod mod in score.Mods)
|
||||
foreach (Mod mod in Score.Mods)
|
||||
modContainer.Add(new ModIcon(mod)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
public class DrawableTotalScore : DrawableScore
|
||||
{
|
||||
public DrawableTotalScore(Score score)
|
||||
: base(score)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private new void load()
|
||||
{
|
||||
Stats.Add(new OsuSpriteText
|
||||
{
|
||||
Text = Score.TotalScore.ToString("#,###"),
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
TextSize = 18,
|
||||
Font = "Exo2.0-BoldItalic",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections.Ranks
|
||||
{
|
||||
public class PaginatedScoreContainer : FillFlowContainer
|
||||
{
|
||||
private readonly FillFlowContainer<DrawableScore> scoreContainer;
|
||||
private readonly OsuSpriteText missing;
|
||||
private readonly OsuHoverContainer showMoreButton;
|
||||
private readonly LoadingAnimation showMoreLoading;
|
||||
|
||||
private readonly bool includeWeight;
|
||||
private readonly ScoreType type;
|
||||
private int visiblePages;
|
||||
|
||||
private readonly Bindable<User> user = new Bindable<User>();
|
||||
|
||||
private RulesetStore rulesets;
|
||||
private APIAccess api;
|
||||
|
||||
public PaginatedScoreContainer(ScoreType type, Bindable<User> user, string header, bool includeWeight = false)
|
||||
{
|
||||
this.type = type;
|
||||
this.includeWeight = includeWeight;
|
||||
this.user.BindTo(user);
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Vertical;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
TextSize = 15,
|
||||
Text = header,
|
||||
Font = "Exo2.0-RegularItalic",
|
||||
Margin = new MarginPadding { Top = 10, Bottom = 10 },
|
||||
},
|
||||
scoreContainer = new FillFlowContainer<DrawableScore>
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
showMoreButton = new OsuHoverContainer
|
||||
{
|
||||
Alpha = 0,
|
||||
Action = showMore,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Child = new OsuSpriteText
|
||||
{
|
||||
TextSize = 14,
|
||||
Text = "show more",
|
||||
}
|
||||
},
|
||||
showMoreLoading = new LoadingAnimation
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
missing = new OsuSpriteText
|
||||
{
|
||||
TextSize = 14,
|
||||
Text = type == ScoreType.Recent ? "No performance records. :(" : "No awesome performance records yet. :(",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api, RulesetStore rulesets)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
|
||||
user.ValueChanged += user_ValueChanged;
|
||||
user.TriggerChange();
|
||||
}
|
||||
|
||||
private void user_ValueChanged(User newUser)
|
||||
{
|
||||
visiblePages = 0;
|
||||
scoreContainer.Clear();
|
||||
showMoreButton.Hide();
|
||||
missing.Show();
|
||||
|
||||
if (newUser != null)
|
||||
showMore();
|
||||
}
|
||||
|
||||
private void showMore()
|
||||
{
|
||||
var req = new GetUserScoresRequest(user.Value.Id, type, visiblePages++ * 5);
|
||||
|
||||
showMoreLoading.Show();
|
||||
showMoreButton.Hide();
|
||||
|
||||
req.Success += scores =>
|
||||
{
|
||||
foreach (var s in scores)
|
||||
s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID));
|
||||
|
||||
showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0);
|
||||
showMoreLoading.Hide();
|
||||
|
||||
if (!scores.Any()) return;
|
||||
|
||||
missing.Hide();
|
||||
|
||||
foreach (OnlineScore score in scores)
|
||||
{
|
||||
DrawableScore drawableScore;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
drawableScore = new DrawablePerformanceScore(score, includeWeight ? Math.Pow(0.95, scoreContainer.Count) : (double?)null);
|
||||
break;
|
||||
case ScoreType.Recent:
|
||||
drawableScore = new DrawableTotalScore(score);
|
||||
break;
|
||||
}
|
||||
|
||||
drawableScore.RelativeSizeAxes = Axes.X;
|
||||
drawableScore.Height = 60;
|
||||
|
||||
scoreContainer.Add(drawableScore);
|
||||
}
|
||||
};
|
||||
|
||||
api.Queue(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays.Profile.Sections.Ranks;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Sections
|
||||
{
|
||||
@@ -24,147 +12,13 @@ namespace osu.Game.Overlays.Profile.Sections
|
||||
|
||||
public override string Identifier => "top_ranks";
|
||||
|
||||
private readonly ScoreContainer best, first;
|
||||
|
||||
public RanksSection()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
best = new ScoreContainer(ScoreType.Best, "Best Performance", true),
|
||||
first = new ScoreContainer(ScoreType.Firsts, "First Place Ranks"),
|
||||
new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", true),
|
||||
new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks"),
|
||||
};
|
||||
}
|
||||
|
||||
public override User User
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.User;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
base.User = value;
|
||||
best.User = value;
|
||||
first.User = value;
|
||||
}
|
||||
}
|
||||
|
||||
private class ScoreContainer : FillFlowContainer
|
||||
{
|
||||
private readonly FillFlowContainer<DrawableScore> scoreContainer;
|
||||
private readonly OsuSpriteText missing;
|
||||
private readonly OsuHoverContainer showMoreButton;
|
||||
private readonly LoadingAnimation showMoreLoading;
|
||||
|
||||
private readonly ScoreType type;
|
||||
private int visiblePages;
|
||||
private User user;
|
||||
private readonly bool includeWeigth;
|
||||
|
||||
private RulesetStore rulesets;
|
||||
private APIAccess api;
|
||||
|
||||
public User User
|
||||
{
|
||||
set
|
||||
{
|
||||
user = value;
|
||||
visiblePages = 0;
|
||||
scoreContainer.Clear();
|
||||
showMoreButton.Hide();
|
||||
missing.Show();
|
||||
showMore();
|
||||
}
|
||||
}
|
||||
|
||||
public ScoreContainer(ScoreType type, string header, bool includeWeigth = false)
|
||||
{
|
||||
this.type = type;
|
||||
this.includeWeigth = includeWeigth;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Vertical;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
TextSize = 15,
|
||||
Text = header,
|
||||
Font = "Exo2.0-RegularItalic",
|
||||
Margin = new MarginPadding { Top = 10, Bottom = 10 },
|
||||
},
|
||||
scoreContainer = new FillFlowContainer<DrawableScore>
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
showMoreButton = new OsuHoverContainer
|
||||
{
|
||||
Alpha = 0,
|
||||
Action = showMore,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Child = new OsuSpriteText
|
||||
{
|
||||
TextSize = 14,
|
||||
Text = "show more",
|
||||
}
|
||||
},
|
||||
showMoreLoading = new LoadingAnimation
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
missing = new OsuSpriteText
|
||||
{
|
||||
TextSize = 14,
|
||||
Text = "No awesome performance records yet. :(",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api, RulesetStore rulesets)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
}
|
||||
|
||||
private void showMore()
|
||||
{
|
||||
var req = new GetUserScoresRequest(user.Id, type, visiblePages++ * 5);
|
||||
|
||||
showMoreLoading.Show();
|
||||
showMoreButton.Hide();
|
||||
|
||||
req.Success += scores =>
|
||||
{
|
||||
foreach (var s in scores)
|
||||
s.ApplyRuleset(rulesets.GetRuleset(s.OnlineRulesetID));
|
||||
|
||||
showMoreButton.FadeTo(scores.Count == 5 ? 1 : 0);
|
||||
showMoreLoading.Hide();
|
||||
|
||||
if (scores.Any())
|
||||
{
|
||||
missing.Hide();
|
||||
foreach (OnlineScore score in scores)
|
||||
scoreContainer.Add(new DrawableScore(score, includeWeigth ? Math.Pow(0.95, scoreContainer.Count) : (double?)null)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 60,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Schedule(() => { api.Queue(req); });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
Action = () =>
|
||||
{
|
||||
importButton.Enabled.Value = false;
|
||||
Task.Run(() => beatmaps.ImportFromStable()).ContinueWith(t => Schedule(() => importButton.Enabled.Value = true));
|
||||
Task.Factory.StartNew(beatmaps.ImportFromStable)
|
||||
.ContinueWith(t => Schedule(() => importButton.Enabled.Value = true), TaskContinuationOptions.LongRunning);
|
||||
}
|
||||
},
|
||||
deleteButton = new SettingsButton
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Settings
|
||||
controlWithCurrent?.Current.BindTo(bindable);
|
||||
if (ShowsDefaultIndicator)
|
||||
{
|
||||
restoreDefaultValueButton.Bindable.BindTo(bindable);
|
||||
restoreDefaultValueButton.Bindable = bindable.GetBoundCopy();
|
||||
restoreDefaultValueButton.Bindable.TriggerChange();
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,17 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
private class RestoreDefaultValueButton<T> : Box, IHasTooltip
|
||||
{
|
||||
internal readonly Bindable<T> Bindable = new Bindable<T>();
|
||||
private Bindable<T> bindable;
|
||||
internal Bindable<T> Bindable
|
||||
{
|
||||
get { return bindable; }
|
||||
set
|
||||
{
|
||||
bindable = value;
|
||||
bindable.ValueChanged += newValue => UpdateState();
|
||||
bindable.DisabledChanged += disabled => UpdateState();
|
||||
}
|
||||
}
|
||||
|
||||
private Color4 buttonColour;
|
||||
|
||||
@@ -142,9 +152,6 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public RestoreDefaultValueButton()
|
||||
{
|
||||
Bindable.ValueChanged += value => UpdateState();
|
||||
Bindable.DisabledChanged += disabled => UpdateState();
|
||||
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = SettingsOverlay.CONTENT_MARGINS;
|
||||
Alpha = 0f;
|
||||
@@ -160,8 +167,8 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
if (!Bindable.Disabled)
|
||||
Bindable.SetDefault();
|
||||
if (bindable != null && !bindable.Disabled)
|
||||
bindable.SetDefault();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -186,8 +193,10 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
internal void UpdateState()
|
||||
{
|
||||
var colour = Bindable.Disabled ? Color4.Gray : buttonColour;
|
||||
this.FadeTo(Bindable.IsDefault ? 0f : hovering && !Bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint);
|
||||
if (bindable == null)
|
||||
return;
|
||||
var colour = bindable.Disabled ? Color4.Gray : buttonColour;
|
||||
this.FadeTo(bindable.IsDefault ? 0f : hovering && !bindable.Disabled ? 1f : 0.5f, 200, Easing.OutQuint);
|
||||
this.FadeColour(ColourInfo.GradientHorizontal(colour.Opacity(0.8f), colour.Opacity(0)), 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace osu.Game.Overlays
|
||||
//new RecentSection(),
|
||||
new RanksSection(),
|
||||
//new MedalsSection(),
|
||||
//new HistoricalSection(),
|
||||
new HistoricalSection(),
|
||||
//new BeatmapsSection(),
|
||||
//new KudosuSection()
|
||||
};
|
||||
@@ -175,7 +175,7 @@ namespace osu.Game.Overlays
|
||||
var sec = sections.FirstOrDefault(s => s.Identifier == id);
|
||||
if (sec != null)
|
||||
{
|
||||
sec.User = user;
|
||||
sec.User.Value = user;
|
||||
|
||||
sectionsContainer.Add(sec);
|
||||
tabs.AddItem(sec);
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Judgements
|
||||
break;
|
||||
}
|
||||
|
||||
Expire();
|
||||
Expire(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,26 @@ namespace osu.Game.Rulesets.Judgements
|
||||
/// </summary>
|
||||
public virtual HitResult MaxResult => HitResult.Perfect;
|
||||
|
||||
/// <summary>
|
||||
/// The combo prior to this judgement occurring.
|
||||
/// </summary>
|
||||
internal int ComboAtJudgement;
|
||||
|
||||
/// <summary>
|
||||
/// The highest combo achieved prior to this judgement occurring.
|
||||
/// </summary>
|
||||
internal int HighestComboAtJudgement;
|
||||
|
||||
/// <summary>
|
||||
/// Whether a successful hit occurred.
|
||||
/// </summary>
|
||||
public bool IsHit => Result > HitResult.Miss;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this judgement is the final judgement for the hit object.
|
||||
/// </summary>
|
||||
public bool Final = true;
|
||||
|
||||
/// <summary>
|
||||
/// The offset from a perfect hit at which this judgement occurred.
|
||||
/// Populated when added via <see cref="DrawableHitObject{TObject}.AddJudgement"/>.
|
||||
|
||||
@@ -13,6 +13,7 @@ using OpenTK.Graphics;
|
||||
using osu.Game.Audio;
|
||||
using System.Linq;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects.Drawables
|
||||
{
|
||||
@@ -30,6 +31,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// </summary>
|
||||
public virtual bool DisplayJudgement => true;
|
||||
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
protected DrawableHitObject(HitObject hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
@@ -40,6 +44,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
where TObject : HitObject
|
||||
{
|
||||
public event Action<DrawableHitObject, Judgement> OnJudgement;
|
||||
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved;
|
||||
|
||||
public new readonly TObject HitObject;
|
||||
|
||||
@@ -56,31 +61,42 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
|
||||
protected List<SampleChannel> Samples = new List<SampleChannel>();
|
||||
|
||||
public readonly Bindable<ArmedState> State = new Bindable<ArmedState>();
|
||||
|
||||
protected DrawableHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
HitObject = hitObject;
|
||||
}
|
||||
|
||||
private ArmedState state;
|
||||
public ArmedState State
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
get { return state; }
|
||||
|
||||
set
|
||||
foreach (SampleInfo sample in HitObject.Samples)
|
||||
{
|
||||
if (state == value)
|
||||
return;
|
||||
state = value;
|
||||
SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}");
|
||||
|
||||
if (!IsLoaded)
|
||||
return;
|
||||
if (channel == null)
|
||||
continue;
|
||||
|
||||
channel.Volume.Value = sample.Volume;
|
||||
Samples.Add(channel);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
State.ValueChanged += state =>
|
||||
{
|
||||
UpdateState(state);
|
||||
|
||||
if (State == ArmedState.Hit)
|
||||
PlaySamples();
|
||||
}
|
||||
};
|
||||
|
||||
State.TriggerChange();
|
||||
}
|
||||
|
||||
protected void PlaySamples()
|
||||
@@ -88,21 +104,13 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
Samples.ForEach(s => s?.Play());
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
//force application of the state that was set before we loaded.
|
||||
UpdateState(State);
|
||||
}
|
||||
|
||||
private bool hasJudgementResult;
|
||||
private bool judgementOccurred;
|
||||
private bool judgementFinalized => judgements.LastOrDefault()?.Final == true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
|
||||
/// </summary>
|
||||
public virtual bool AllJudged => (!ProvidesJudgement || hasJudgementResult) && (NestedHitObjects?.All(h => h.AllJudged) ?? true);
|
||||
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (NestedHitObjects?.All(h => h.AllJudged) ?? true);
|
||||
|
||||
/// <summary>
|
||||
/// Notifies that a new judgement has occurred for this <see cref="DrawableHitObject"/>.
|
||||
@@ -110,7 +118,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// <param name="judgement">The <see cref="Judgement"/>.</param>
|
||||
protected void AddJudgement(Judgement judgement)
|
||||
{
|
||||
hasJudgementResult = judgement.Result >= HitResult.Miss;
|
||||
judgementOccurred = true;
|
||||
|
||||
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
|
||||
@@ -124,10 +131,10 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
case HitResult.None:
|
||||
break;
|
||||
case HitResult.Miss:
|
||||
State = ArmedState.Miss;
|
||||
State.Value = ArmedState.Miss;
|
||||
break;
|
||||
default:
|
||||
State = ArmedState.Hit;
|
||||
State.Value = ArmedState.Hit;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -152,7 +159,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
judgementOccurred |= d.UpdateJudgement(userTriggered);
|
||||
}
|
||||
|
||||
if (!ProvidesJudgement || hasJudgementResult || judgementOccurred)
|
||||
if (!ProvidesJudgement || judgementFinalized || judgementOccurred)
|
||||
return judgementOccurred;
|
||||
|
||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||
@@ -170,6 +177,25 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
/// implies that this check occurred after the end time of <see cref="HitObject"/>. </param>
|
||||
protected virtual void CheckForJudgements(bool userTriggered, double timeOffset) { }
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
|
||||
|
||||
while (judgements.Count > 0)
|
||||
{
|
||||
var lastJudgement = judgements[judgements.Count - 1];
|
||||
if (lastJudgement.TimeOffset + endTime <= Time.Current)
|
||||
break;
|
||||
|
||||
judgements.RemoveAt(judgements.Count - 1);
|
||||
State.Value = ArmedState.Idle;
|
||||
|
||||
OnJudgementRemoved?.Invoke(this, lastJudgement);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
@@ -177,21 +203,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
||||
UpdateJudgement(false);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
foreach (SampleInfo sample in HitObject.Samples)
|
||||
{
|
||||
SampleChannel channel = audio.Sample.Get($@"Gameplay/{sample.Bank}-{sample.Name}");
|
||||
|
||||
if (channel == null)
|
||||
continue;
|
||||
|
||||
channel.Volume.Value = sample.Volume;
|
||||
Samples.Add(channel);
|
||||
}
|
||||
}
|
||||
|
||||
private List<DrawableHitObject<TObject>> nestedHitObjects;
|
||||
protected IEnumerable<DrawableHitObject<TObject>> NestedHitObjects => nestedHitObjects;
|
||||
|
||||
|
||||
@@ -104,7 +104,13 @@ namespace osu.Game.Rulesets.Replays
|
||||
{
|
||||
//if we changed frames, we want to execute once *exactly* on the frame's time.
|
||||
if (currentDirection == time.CompareTo(NextFrame.Time) && advanceFrame())
|
||||
{
|
||||
// If going backwards, we need to execute once _before_ the frame time to reverse any judgements
|
||||
// that would occur as a result of this frame in forward playback
|
||||
if (currentDirection == -1)
|
||||
return currentTime = CurrentFrame.Time - 1;
|
||||
return currentTime = CurrentFrame.Time;
|
||||
}
|
||||
|
||||
//if we didn't change frames, we need to ensure we are allowed to run frames in between, else return null.
|
||||
if (inImportantSection)
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
@@ -29,6 +28,7 @@ namespace osu.Game.Rulesets
|
||||
public RulesetStore(Func<OsuDbContext> factory)
|
||||
: base(factory)
|
||||
{
|
||||
AddMissingRulesets();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,21 +41,16 @@ namespace osu.Game.Rulesets
|
||||
/// <summary>
|
||||
/// All available rulesets.
|
||||
/// </summary>
|
||||
public IEnumerable<RulesetInfo> AvailableRulesets => GetContext().RulesetInfo.Where(r => r.Available);
|
||||
public IEnumerable<RulesetInfo> AvailableRulesets;
|
||||
|
||||
private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name);
|
||||
|
||||
private const string ruleset_library_prefix = "osu.Game.Rulesets";
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
protected void AddMissingRulesets()
|
||||
{
|
||||
var context = GetContext();
|
||||
|
||||
if (reset)
|
||||
{
|
||||
context.Database.ExecuteSqlCommand("DELETE FROM RulesetInfo");
|
||||
}
|
||||
|
||||
var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, new RulesetInfo())).ToList();
|
||||
|
||||
//add all legacy modes in correct order
|
||||
@@ -98,6 +93,8 @@ namespace osu.Game.Rulesets
|
||||
}
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
AvailableRulesets = context.RulesetInfo.Where(r => r.Available).ToList();
|
||||
}
|
||||
|
||||
private static void loadRulesetFromFile(string file)
|
||||
|
||||
@@ -174,6 +174,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
private double maxBaseScore;
|
||||
private double rollingMaxBaseScore;
|
||||
private double baseScore;
|
||||
private double bonusScore;
|
||||
|
||||
protected ScoreProcessor()
|
||||
{
|
||||
@@ -184,6 +185,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
Debug.Assert(base_portion + combo_portion == 1.0);
|
||||
|
||||
rulesetContainer.OnJudgement += AddJudgement;
|
||||
rulesetContainer.OnJudgementRemoved += RemoveJudgement;
|
||||
|
||||
SimulateAutoplay(rulesetContainer.Beatmap);
|
||||
Reset(true);
|
||||
@@ -212,14 +214,26 @@ namespace osu.Game.Rulesets.Scoring
|
||||
protected void AddJudgement(Judgement judgement)
|
||||
{
|
||||
OnNewJudgement(judgement);
|
||||
NotifyNewJudgement(judgement);
|
||||
updateScore();
|
||||
|
||||
NotifyNewJudgement(judgement);
|
||||
UpdateFailed();
|
||||
}
|
||||
|
||||
protected void RemoveJudgement(Judgement judgement)
|
||||
{
|
||||
OnJudgementRemoved(judgement);
|
||||
updateScore();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a judgement.
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement to apply/</param>
|
||||
protected virtual void OnNewJudgement(Judgement judgement)
|
||||
{
|
||||
double bonusScore = 0;
|
||||
judgement.ComboAtJudgement = Combo;
|
||||
judgement.HighestComboAtJudgement = HighestCombo;
|
||||
|
||||
if (judgement.AffectsCombo)
|
||||
{
|
||||
@@ -242,7 +256,30 @@ namespace osu.Game.Rulesets.Scoring
|
||||
}
|
||||
else if (judgement.IsHit)
|
||||
bonusScore += judgement.NumericResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a judgement. This should reverse everything in <see cref="OnNewJudgement(Judgement)"/>.
|
||||
/// </summary>
|
||||
/// <param name="judgement">The judgement to remove.</param>
|
||||
protected virtual void OnJudgementRemoved(Judgement judgement)
|
||||
{
|
||||
Combo.Value = judgement.ComboAtJudgement;
|
||||
HighestCombo.Value = judgement.HighestComboAtJudgement;
|
||||
|
||||
if (judgement.AffectsCombo)
|
||||
{
|
||||
baseScore -= judgement.NumericResult;
|
||||
rollingMaxBaseScore -= judgement.MaxNumericResult;
|
||||
|
||||
Hits--;
|
||||
}
|
||||
else if (judgement.IsHit)
|
||||
bonusScore -= judgement.NumericResult;
|
||||
}
|
||||
|
||||
private void updateScore()
|
||||
{
|
||||
if (rollingMaxBaseScore != 0)
|
||||
Accuracy.Value = baseScore / rollingMaxBaseScore;
|
||||
|
||||
@@ -271,6 +308,7 @@ namespace osu.Game.Rulesets.Scoring
|
||||
Hits = 0;
|
||||
baseScore = 0;
|
||||
rollingMaxBaseScore = 0;
|
||||
bonusScore = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,9 +143,5 @@ namespace osu.Game.Rulesets.Scoring
|
||||
|
||||
return new Replay { Frames = frames };
|
||||
}
|
||||
|
||||
protected override void Prepare(bool reset = false)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ namespace osu.Game.Rulesets.UI
|
||||
where TObject : HitObject
|
||||
{
|
||||
public event Action<Judgement> OnJudgement;
|
||||
public event Action<Judgement> OnJudgementRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// The Beatmap
|
||||
@@ -241,6 +242,8 @@ namespace osu.Game.Rulesets.UI
|
||||
OnJudgement?.Invoke(j);
|
||||
};
|
||||
|
||||
drawableObject.OnJudgementRemoved += (d, j) => { OnJudgementRemoved?.Invoke(j); };
|
||||
|
||||
Playfield.Add(drawableObject);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenCustom(@"Backgrounds/bg4");
|
||||
|
||||
internal override bool ShowOverlays => false;
|
||||
public override bool ShowOverlays => false;
|
||||
|
||||
private readonly Box bottomBackground;
|
||||
private readonly Container screenContainer;
|
||||
|
||||
@@ -2,26 +2,62 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK;
|
||||
using osu.Framework.Screens;
|
||||
|
||||
namespace osu.Game.Screens
|
||||
{
|
||||
internal class Loader : OsuScreen
|
||||
public class Loader : OsuScreen
|
||||
{
|
||||
internal override bool ShowOverlays => false;
|
||||
private bool showDisclaimer;
|
||||
|
||||
public override bool ShowOverlays => false;
|
||||
|
||||
public Loader()
|
||||
{
|
||||
ValidForResume = false;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGame game)
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
if (game.IsDeployedBuild)
|
||||
base.LogoArriving(logo, resuming);
|
||||
|
||||
logo.RelativePositionAxes = Axes.None;
|
||||
logo.Triangles = false;
|
||||
logo.Origin = Anchor.BottomRight;
|
||||
logo.Anchor = Anchor.BottomRight;
|
||||
logo.Position = new Vector2(-40);
|
||||
logo.Scale = new Vector2(0.2f);
|
||||
|
||||
logo.FadeInFromZero(5000, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
if (showDisclaimer)
|
||||
LoadComponentAsync(new Disclaimer(), d => Push(d));
|
||||
else
|
||||
LoadComponentAsync(new Intro(), d => Push(d));
|
||||
}
|
||||
|
||||
protected override void LogoSuspending(OsuLogo logo)
|
||||
{
|
||||
base.LogoSuspending(logo);
|
||||
logo.FadeOut(100).OnComplete(l =>
|
||||
{
|
||||
l.Anchor = Anchor.TopLeft;
|
||||
l.Origin = Anchor.Centre;
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game)
|
||||
{
|
||||
showDisclaimer = game.IsDeployedBuild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,25 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
//todo: make these non-internal somehow.
|
||||
internal const float BUTTON_AREA_HEIGHT = 100;
|
||||
|
||||
internal const float BUTTON_WIDTH = 140f;
|
||||
internal const float WEDGE_WIDTH = 20;
|
||||
|
||||
public const int EXIT_DELAY = 3000;
|
||||
private OsuLogo logo;
|
||||
|
||||
public void SetOsuLogo(OsuLogo logo)
|
||||
{
|
||||
this.logo = logo;
|
||||
|
||||
if (this.logo != null)
|
||||
{
|
||||
this.logo.Action = onOsuLogo;
|
||||
|
||||
// osuLogo.SizeForFlow relies on loading to be complete.
|
||||
buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + this.logo.SizeForFlow / 4), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly OsuLogo osuLogo;
|
||||
private readonly Drawable iconFacade;
|
||||
private readonly Container buttonArea;
|
||||
private readonly Box buttonAreaBackground;
|
||||
@@ -99,12 +112,6 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
},
|
||||
osuLogo = new OsuLogo
|
||||
{
|
||||
Action = onOsuLogo,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
|
||||
buttonsPlay.Add(new Button(@"solo", @"select-6", FontAwesome.fa_user, new Color4(102, 68, 204, 255), () => OnSolo?.Invoke(), WEDGE_WIDTH, Key.P));
|
||||
@@ -127,14 +134,6 @@ namespace osu.Game.Screens.Menu
|
||||
sampleBack = audio.Sample.Get(@"Menu/select-4");
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
// osuLogo.SizeForFlow relies on loading to be complete.
|
||||
buttonFlow.Position = new Vector2(WEDGE_WIDTH * 2 - (BUTTON_WIDTH + osuLogo.SizeForFlow / 4), 0);
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Repeat) return false;
|
||||
@@ -142,7 +141,7 @@ namespace osu.Game.Screens.Menu
|
||||
switch (args.Key)
|
||||
{
|
||||
case Key.Space:
|
||||
osuLogo.TriggerOnClick(state);
|
||||
logo?.TriggerOnClick(state);
|
||||
return true;
|
||||
case Key.Escape:
|
||||
switch (State)
|
||||
@@ -215,24 +214,31 @@ namespace osu.Game.Screens.Menu
|
||||
backButton.ContractStyle = 0;
|
||||
settingsButton.ContractStyle = 0;
|
||||
|
||||
bool fromInitial = lastState == MenuState.Initial;
|
||||
|
||||
if (state == MenuState.TopLevel)
|
||||
buttonArea.FinishTransforms(true);
|
||||
|
||||
using (buttonArea.BeginDelayedSequence(fromInitial ? 150 : 0, true))
|
||||
using (buttonArea.BeginDelayedSequence(lastState == MenuState.Initial ? 150 : 0, true))
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case MenuState.Exit:
|
||||
case MenuState.Initial:
|
||||
trackingPosition = false;
|
||||
|
||||
buttonAreaBackground.ScaleTo(Vector2.One, 500, Easing.Out);
|
||||
buttonArea.FadeOut(300);
|
||||
|
||||
osuLogo.Delay(150)
|
||||
.Schedule(() => toolbar?.Hide())
|
||||
.ScaleTo(1, 800, Easing.OutExpo)
|
||||
.MoveTo(Vector2.Zero, 800, Easing.OutExpo);
|
||||
logo?.Delay(150)
|
||||
.Schedule(() =>
|
||||
{
|
||||
toolbar?.Hide();
|
||||
|
||||
logo.ClearTransforms(targetMember: nameof(Position));
|
||||
logo.RelativePositionAxes = Axes.Both;
|
||||
|
||||
logo.MoveTo(new Vector2(0.5f), 800, Easing.OutExpo);
|
||||
logo.ScaleTo(1, 800, Easing.OutExpo);
|
||||
});
|
||||
|
||||
foreach (Button b in buttonsTopLevel)
|
||||
b.State = ButtonState.Contracted;
|
||||
@@ -240,27 +246,38 @@ namespace osu.Game.Screens.Menu
|
||||
foreach (Button b in buttonsPlay)
|
||||
b.State = ButtonState.Contracted;
|
||||
|
||||
if (state == MenuState.Exit)
|
||||
{
|
||||
osuLogo.RotateTo(20, EXIT_DELAY * 1.5f);
|
||||
osuLogo.FadeOut(EXIT_DELAY);
|
||||
}
|
||||
else if (lastState == MenuState.TopLevel)
|
||||
if (state != MenuState.Exit && lastState == MenuState.TopLevel)
|
||||
sampleBack?.Play();
|
||||
break;
|
||||
case MenuState.TopLevel:
|
||||
buttonAreaBackground.ScaleTo(Vector2.One, 200, Easing.Out);
|
||||
|
||||
var sequence = osuLogo
|
||||
.ScaleTo(0.5f, 200, Easing.In)
|
||||
.MoveTo(buttonFlow.DrawPosition, 200, Easing.In);
|
||||
logo.ClearTransforms(targetMember: nameof(Position));
|
||||
logo.RelativePositionAxes = Axes.None;
|
||||
|
||||
if (fromInitial && osuLogo.Scale.X > 0.5f)
|
||||
sequence.OnComplete(o =>
|
||||
{
|
||||
o.Impact();
|
||||
toolbar?.Show();
|
||||
});
|
||||
trackingPosition = true;
|
||||
|
||||
switch (lastState)
|
||||
{
|
||||
case MenuState.Initial:
|
||||
logo.ScaleTo(0.5f, 200, Easing.In);
|
||||
|
||||
trackingPosition = false;
|
||||
|
||||
logo
|
||||
.MoveTo(iconTrackingPosition, lastState == MenuState.EnteringMode ? 0 : 200, Easing.In)
|
||||
.OnComplete(o =>
|
||||
{
|
||||
trackingPosition = true;
|
||||
|
||||
o.Impact();
|
||||
toolbar?.Show();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
logo.ScaleTo(0.5f, 200, Easing.OutQuint);
|
||||
break;
|
||||
}
|
||||
|
||||
buttonArea.FadeIn(300);
|
||||
|
||||
@@ -280,6 +297,8 @@ namespace osu.Game.Screens.Menu
|
||||
case MenuState.EnteringMode:
|
||||
buttonAreaBackground.ScaleTo(new Vector2(2, 0), 300, Easing.InSine);
|
||||
|
||||
trackingPosition = true;
|
||||
|
||||
buttonsTopLevel.ForEach(b => b.ContractStyle = 1);
|
||||
buttonsPlay.ForEach(b => b.ContractStyle = 1);
|
||||
backButton.ContractStyle = 1;
|
||||
@@ -301,15 +320,24 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 iconTrackingPosition => logo.Parent.ToLocalSpace(iconFacade.ScreenSpaceDrawQuad.Centre);
|
||||
|
||||
private bool trackingPosition;
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
//if (OsuGame.IdleTime > 6000 && State != MenuState.Exit)
|
||||
// State = MenuState.Initial;
|
||||
|
||||
osuLogo.Interactive = Alpha > 0.2f;
|
||||
|
||||
iconFacade.Width = osuLogo.SizeForFlow * 0.5f;
|
||||
base.Update();
|
||||
|
||||
if (logo != null)
|
||||
{
|
||||
if (trackingPosition)
|
||||
logo.Position = iconTrackingPosition;
|
||||
|
||||
iconFacade.Width = logo.SizeForFlow * 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,15 +12,15 @@ using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
internal class Disclaimer : OsuScreen
|
||||
public class Disclaimer : OsuScreen
|
||||
{
|
||||
private Intro intro;
|
||||
private readonly SpriteIcon icon;
|
||||
private Color4 iconColour;
|
||||
|
||||
internal override bool ShowOverlays => false;
|
||||
public override bool ShowOverlays => false;
|
||||
|
||||
internal override bool HasLocalCursorDisplayed => true;
|
||||
public override bool HasLocalCursorDisplayed => true;
|
||||
|
||||
public Disclaimer()
|
||||
{
|
||||
|
||||
@@ -14,13 +14,14 @@ using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
public class Intro : OsuScreen
|
||||
{
|
||||
private readonly OsuLogo logo;
|
||||
private readonly IntroSequence introSequence;
|
||||
|
||||
private const string menu_music_beatmap_hash = "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83";
|
||||
|
||||
@@ -33,38 +34,16 @@ namespace osu.Game.Screens.Menu
|
||||
private SampleChannel welcome;
|
||||
private SampleChannel seeya;
|
||||
|
||||
internal override bool HasLocalCursorDisplayed => true;
|
||||
public override bool HasLocalCursorDisplayed => true;
|
||||
|
||||
internal override bool ShowOverlays => false;
|
||||
public override bool ShowOverlays => false;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty();
|
||||
|
||||
public Intro()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ParallaxContainer
|
||||
{
|
||||
ParallaxAmount = 0.01f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
logo = new OsuLogo
|
||||
{
|
||||
Alpha = 0,
|
||||
Triangles = false,
|
||||
Blending = BlendingMode.Additive,
|
||||
Interactive = false,
|
||||
Colour = Color4.DarkGray,
|
||||
Ripple = false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Bindable<bool> menuVoice;
|
||||
private Bindable<bool> menuMusic;
|
||||
private Track track;
|
||||
private readonly ParallaxContainer parallax;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuConfigManager config, BeatmapManager beatmaps, Framework.Game game)
|
||||
@@ -99,7 +78,9 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
welcome = audio.Sample.Get(@"welcome");
|
||||
seeya = audio.Sample.Get(@"seeya");
|
||||
beatmaps.Delete(setInfo);
|
||||
|
||||
if (setInfo.Protected)
|
||||
beatmaps.Delete(setInfo);
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
@@ -121,14 +102,48 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
DidLoadMenu = true;
|
||||
Push(mainMenu);
|
||||
}, 2300);
|
||||
}, 600);
|
||||
}, delay_step_one);
|
||||
}, delay_step_two);
|
||||
}
|
||||
|
||||
logo.ScaleTo(0.4f);
|
||||
logo.FadeOut();
|
||||
private const double delay_step_one = 2300;
|
||||
private const double delay_step_two = 600;
|
||||
|
||||
logo.ScaleTo(1, 4400, Easing.OutQuint);
|
||||
logo.FadeIn(20000, Easing.OutQuint);
|
||||
public const int EXIT_DELAY = 3000;
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
base.LogoArriving(logo, resuming);
|
||||
|
||||
logo.RelativePositionAxes = Axes.Both;
|
||||
logo.Colour = Color4.White;
|
||||
logo.Ripple = false;
|
||||
|
||||
const int quick_appear = 350;
|
||||
|
||||
int initialMovementTime = logo.Alpha > 0.2f ? quick_appear : 0;
|
||||
|
||||
logo.MoveTo(new Vector2(0.5f), initialMovementTime, Easing.OutQuint);
|
||||
|
||||
if (!resuming)
|
||||
{
|
||||
logo.Triangles = true;
|
||||
|
||||
logo.ScaleTo(1);
|
||||
logo.FadeIn();
|
||||
logo.PlayIntro();
|
||||
}
|
||||
else
|
||||
{
|
||||
logo.Triangles = false;
|
||||
|
||||
logo
|
||||
.ScaleTo(1, initialMovementTime, Easing.OutQuint)
|
||||
.FadeIn(quick_appear, Easing.OutQuint)
|
||||
.Then()
|
||||
.RotateTo(20, EXIT_DELAY * 1.5f)
|
||||
.FadeOut(EXIT_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSuspending(Screen next)
|
||||
@@ -148,7 +163,7 @@ namespace osu.Game.Screens.Menu
|
||||
if (!(last is MainMenu))
|
||||
Content.FadeIn(300);
|
||||
|
||||
double fadeOutTime = 2000;
|
||||
double fadeOutTime = EXIT_DELAY;
|
||||
//we also handle the exit transition.
|
||||
if (menuVoice)
|
||||
seeya.Play();
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
public class IntroSequence : Container
|
||||
{
|
||||
private const float logo_size = 460; //todo: this should probably be 480
|
||||
|
||||
private OsuSpriteText welcomeText;
|
||||
|
||||
private Container<Box> lines;
|
||||
|
||||
private Box lineTopLeft;
|
||||
private Box lineBottomLeft;
|
||||
private Box lineTopRight;
|
||||
private Box lineBottomRight;
|
||||
|
||||
private Ring smallRing;
|
||||
private Ring mediumRing;
|
||||
private Ring bigRing;
|
||||
|
||||
private Box backgroundFill;
|
||||
private Box foregroundFill;
|
||||
|
||||
private CircularContainer pinkCircle;
|
||||
private CircularContainer blueCircle;
|
||||
private CircularContainer yellowCircle;
|
||||
private CircularContainer purpleCircle;
|
||||
|
||||
public IntroSequence()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
const int line_offset = 80;
|
||||
const int circle_offset = 250;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
lines = new Container<Box>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = new []
|
||||
{
|
||||
lineTopLeft = new Box
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(-line_offset, -line_offset),
|
||||
Rotation = 45,
|
||||
Colour = Color4.White.Opacity(180),
|
||||
},
|
||||
lineTopRight = new Box
|
||||
{
|
||||
Origin = Anchor.CentreRight,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(line_offset, -line_offset),
|
||||
Rotation = -45,
|
||||
Colour = Color4.White.Opacity(80),
|
||||
},
|
||||
lineBottomLeft = new Box
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(-line_offset, line_offset),
|
||||
Rotation = -45,
|
||||
Colour = Color4.White.Opacity(230),
|
||||
},
|
||||
lineBottomRight = new Box
|
||||
{
|
||||
Origin = Anchor.CentreRight,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(line_offset, line_offset),
|
||||
Rotation = 45,
|
||||
Colour = Color4.White.Opacity(130),
|
||||
},
|
||||
}
|
||||
},
|
||||
bigRing = new Ring(OsuColour.FromHex(@"B6C5E9"), 0.85f),
|
||||
mediumRing = new Ring(Color4.White.Opacity(130), 0.7f),
|
||||
smallRing = new Ring(Color4.White, 0.6f),
|
||||
welcomeText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = "welcome",
|
||||
Padding = new MarginPadding { Bottom = 10 },
|
||||
Font = @"Exo2.0-Light",
|
||||
Alpha = 0,
|
||||
TextSize = 42,
|
||||
Spacing = new Vector2(5),
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(logo_size),
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
backgroundFill = new Box
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0,
|
||||
Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160),
|
||||
},
|
||||
foregroundFill = new Box
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = Vector2.Zero,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0,
|
||||
Colour = Color4.White,
|
||||
},
|
||||
}
|
||||
},
|
||||
purpleCircle = new Circle
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Position = new Vector2(0, circle_offset),
|
||||
Colour = OsuColour.FromHex(@"AA92FF"),
|
||||
},
|
||||
blueCircle = new Circle
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.CentreRight,
|
||||
Position = new Vector2(-circle_offset, 0),
|
||||
Colour = OsuColour.FromHex(@"8FE5FE"),
|
||||
},
|
||||
yellowCircle = new Circle
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Position = new Vector2(0, -circle_offset),
|
||||
Colour = OsuColour.FromHex(@"FFD64C"),
|
||||
},
|
||||
pinkCircle = new Circle
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Position = new Vector2(circle_offset, 0),
|
||||
Colour = OsuColour.FromHex(@"e967a1"),
|
||||
},
|
||||
};
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
line.Size = new Vector2(105, 1.5f);
|
||||
line.Alpha = 0;
|
||||
}
|
||||
|
||||
Scale = new Vector2(0.5f);
|
||||
}
|
||||
|
||||
public void Start(double length)
|
||||
{
|
||||
if (Children.Any())
|
||||
{
|
||||
// restart if we were already run previously.
|
||||
FinishTransforms(true);
|
||||
load();
|
||||
}
|
||||
|
||||
smallRing.ResizeTo(logo_size * 0.086f, 400, Easing.InOutQuint);
|
||||
|
||||
mediumRing.ResizeTo(130, 340, Easing.OutQuad);
|
||||
mediumRing.Foreground.ResizeTo(1, 880, Easing.Out);
|
||||
|
||||
Func<double> remainingTime = () => length - TransformDelay;
|
||||
|
||||
using (BeginDelayedSequence(250, true))
|
||||
{
|
||||
welcomeText.FadeIn(700);
|
||||
welcomeText.TransformSpacingTo(new Vector2(20, 0), remainingTime(), Easing.Out);
|
||||
|
||||
const int line_duration = 700;
|
||||
const int line_resize = 150;
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
line.FadeIn(40).ResizeWidthTo(0, line_duration - line_resize, Easing.OutQuint);
|
||||
}
|
||||
|
||||
const int line_end_offset = 120;
|
||||
|
||||
smallRing.Foreground.ResizeTo(1, line_duration, Easing.OutQuint);
|
||||
|
||||
lineTopLeft.MoveTo(new Vector2(-line_end_offset, -line_end_offset), line_duration, Easing.OutQuint);
|
||||
lineTopRight.MoveTo(new Vector2(line_end_offset, -line_end_offset), line_duration, Easing.OutQuint);
|
||||
lineBottomLeft.MoveTo(new Vector2(-line_end_offset, line_end_offset), line_duration, Easing.OutQuint);
|
||||
lineBottomRight.MoveTo(new Vector2(line_end_offset, line_end_offset), line_duration, Easing.OutQuint);
|
||||
|
||||
using (BeginDelayedSequence(length * 0.56, true))
|
||||
{
|
||||
bigRing.ResizeTo(logo_size, 500, Easing.InOutQuint);
|
||||
bigRing.Foreground.Delay(250).ResizeTo(1, 850, Easing.OutQuint);
|
||||
|
||||
using (BeginDelayedSequence(250, true))
|
||||
{
|
||||
backgroundFill.ResizeHeightTo(1, remainingTime(), Easing.InOutQuart);
|
||||
backgroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart);
|
||||
|
||||
using (BeginDelayedSequence(50, true))
|
||||
{
|
||||
foregroundFill.ResizeWidthTo(1, remainingTime(), Easing.InOutQuart);
|
||||
foregroundFill.RotateTo(-90, remainingTime(), Easing.InOutQuart);
|
||||
}
|
||||
|
||||
this.ScaleTo(1, remainingTime(), Easing.InOutCubic);
|
||||
|
||||
const float circle_size = logo_size * 0.9f;
|
||||
|
||||
const int rotation_delay = 110;
|
||||
const int appear_delay = 80;
|
||||
|
||||
purpleCircle.MoveToY(circle_size / 2, remainingTime(), Easing.InOutQuart);
|
||||
purpleCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart);
|
||||
purpleCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart);
|
||||
|
||||
using (BeginDelayedSequence(appear_delay, true))
|
||||
{
|
||||
yellowCircle.MoveToY(-circle_size / 2, remainingTime(), Easing.InOutQuart);
|
||||
yellowCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart);
|
||||
yellowCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart);
|
||||
|
||||
using (BeginDelayedSequence(appear_delay, true))
|
||||
{
|
||||
blueCircle.MoveToX(-circle_size / 2, remainingTime(), Easing.InOutQuart);
|
||||
blueCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart);
|
||||
blueCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart);
|
||||
|
||||
using (BeginDelayedSequence(appear_delay, true))
|
||||
{
|
||||
pinkCircle.MoveToX(circle_size / 2, remainingTime(), Easing.InOutQuart);
|
||||
pinkCircle.Delay(rotation_delay).RotateTo(-180, remainingTime() - rotation_delay, Easing.InOutQuart);
|
||||
pinkCircle.ResizeTo(circle_size, remainingTime(), Easing.InOutQuart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Ring : Container<Circle>
|
||||
{
|
||||
public readonly Circle Foreground;
|
||||
|
||||
public Ring(Color4 ringColour, float foregroundSize)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
Children = new[]
|
||||
{
|
||||
new Circle
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.98f),
|
||||
Colour = ringColour,
|
||||
},
|
||||
Foreground = new Circle
|
||||
{
|
||||
Size = new Vector2(foregroundSize),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ using osu.Framework.Allocation;
|
||||
|
||||
namespace osu.Game.Screens.Menu
|
||||
{
|
||||
internal class LogoVisualisation : Drawable, IHasAccentColour
|
||||
public class LogoVisualisation : Drawable, IHasAccentColour
|
||||
{
|
||||
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
@@ -23,7 +24,7 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
private readonly ButtonSystem buttons;
|
||||
|
||||
internal override bool ShowOverlays => buttons.State != MenuState.Initial;
|
||||
public override bool ShowOverlays => buttons.State != MenuState.Initial;
|
||||
|
||||
private readonly BackgroundScreenDefault background;
|
||||
private Screen songSelect;
|
||||
@@ -58,13 +59,16 @@ namespace osu.Game.Screens.Menu
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGame game)
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuGame game = null)
|
||||
{
|
||||
LoadComponentAsync(background);
|
||||
|
||||
buttons.OnSettings = game.ToggleSettings;
|
||||
buttons.OnDirect = game.ToggleDirect;
|
||||
if (game != null)
|
||||
{
|
||||
buttons.OnSettings = game.ToggleSettings;
|
||||
buttons.OnDirect = game.ToggleDirect;
|
||||
}
|
||||
|
||||
preloadSongSelect();
|
||||
}
|
||||
@@ -102,6 +106,38 @@ namespace osu.Game.Screens.Menu
|
||||
Beatmap.ValueChanged += beatmap_ValueChanged;
|
||||
}
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
base.LogoArriving(logo, resuming);
|
||||
|
||||
buttons.SetOsuLogo(logo);
|
||||
|
||||
logo.Triangles = true;
|
||||
logo.Ripple = false;
|
||||
|
||||
logo.FadeColour(Color4.White, 100, Easing.OutQuint);
|
||||
logo.FadeIn(100, Easing.OutQuint);
|
||||
|
||||
if (resuming)
|
||||
{
|
||||
buttons.State = MenuState.TopLevel;
|
||||
|
||||
const float length = 300;
|
||||
|
||||
Content.FadeIn(length, Easing.OutQuint);
|
||||
Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint);
|
||||
|
||||
sideFlashes.Delay(length).FadeIn(64, Easing.InQuint);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LogoSuspending(OsuLogo logo)
|
||||
{
|
||||
logo.FadeOut(300, Easing.InSine)
|
||||
.ScaleTo(0.2f, 300, Easing.InSine)
|
||||
.OnComplete(l => buttons.SetOsuLogo(null));
|
||||
}
|
||||
|
||||
private void beatmap_ValueChanged(WorkingBeatmap newValue)
|
||||
{
|
||||
if (!IsCurrentScreen)
|
||||
@@ -121,7 +157,7 @@ namespace osu.Game.Screens.Menu
|
||||
Content.FadeOut(length, Easing.InSine);
|
||||
Content.MoveTo(new Vector2(-800, 0), length, Easing.InSine);
|
||||
|
||||
sideFlashes.FadeOut(length / 4, Easing.OutQuint);
|
||||
sideFlashes.FadeOut(64, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void OnResuming(Screen last)
|
||||
@@ -132,15 +168,6 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
//we may have consumed our preloaded instance, so let's make another.
|
||||
preloadSongSelect();
|
||||
|
||||
const float length = 300;
|
||||
|
||||
buttons.State = MenuState.TopLevel;
|
||||
|
||||
Content.FadeIn(length, Easing.OutQuint);
|
||||
Content.MoveTo(new Vector2(0, 0), length, Easing.OutQuint);
|
||||
|
||||
sideFlashes.FadeIn(length / 4, Easing.InQuint);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace osu.Game.Screens.Menu
|
||||
{
|
||||
public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1");
|
||||
|
||||
private const double transition_length = 300;
|
||||
|
||||
private readonly Sprite logo;
|
||||
private readonly CircularContainer logoContainer;
|
||||
private readonly Container logoBounceContainer;
|
||||
@@ -37,6 +39,8 @@ namespace osu.Game.Screens.Menu
|
||||
private readonly Container logoHoverContainer;
|
||||
private readonly LogoVisualisation visualizer;
|
||||
|
||||
private readonly IntroSequence intro;
|
||||
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleBeat;
|
||||
|
||||
@@ -54,7 +58,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
public bool Triangles
|
||||
{
|
||||
set { colourAndTriangles.Alpha = value ? 1 : 0; }
|
||||
set { colourAndTriangles.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); }
|
||||
}
|
||||
|
||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => logoContainer.ReceiveMouseInputAt(screenSpacePos);
|
||||
@@ -62,10 +66,9 @@ namespace osu.Game.Screens.Menu
|
||||
public bool Ripple
|
||||
{
|
||||
get { return rippleContainer.Alpha > 0; }
|
||||
set { rippleContainer.Alpha = value ? 1 : 0; }
|
||||
set { rippleContainer.FadeTo(value ? 1 : 0, transition_length, Easing.OutQuint); }
|
||||
}
|
||||
|
||||
public bool Interactive = true;
|
||||
private readonly Box flashLayer;
|
||||
|
||||
private readonly Container impactContainer;
|
||||
@@ -76,17 +79,23 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
public OsuLogo()
|
||||
{
|
||||
// Required to make Schedule calls run in OsuScreen even when we are not visible.
|
||||
AlwaysPresent = true;
|
||||
|
||||
EarlyActivationMilliseconds = early_activation;
|
||||
|
||||
Size = new Vector2(default_size);
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
intro = new IntroSequence
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
logoHoverContainer = new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
@@ -266,6 +275,17 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayIntro()
|
||||
{
|
||||
const double length = 3150;
|
||||
const double fade = 200;
|
||||
|
||||
logoHoverContainer.FadeOut().Delay(length).FadeIn(fade);
|
||||
intro.Show();
|
||||
intro.Start(length);
|
||||
intro.Delay(length + fade).FadeOut();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
@@ -290,9 +310,11 @@ namespace osu.Game.Screens.Menu
|
||||
}
|
||||
}
|
||||
|
||||
private bool interactive => Action != null && Alpha > 0.2f;
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
if (!Interactive) return false;
|
||||
if (!interactive) return false;
|
||||
|
||||
logoBounceContainer.ScaleTo(0.9f, 1000, Easing.Out);
|
||||
return true;
|
||||
@@ -306,7 +328,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
if (!Interactive) return false;
|
||||
if (!interactive) return false;
|
||||
|
||||
sampleClick.Play();
|
||||
|
||||
@@ -320,7 +342,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
if (!Interactive) return false;
|
||||
if (!interactive) return false;
|
||||
|
||||
logoHoverContainer.ScaleTo(1.1f, 500, Easing.OutElastic);
|
||||
return true;
|
||||
|
||||
@@ -10,13 +10,15 @@ using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Screens
|
||||
{
|
||||
public abstract class OsuScreen : Screen
|
||||
{
|
||||
internal BackgroundScreen Background { get; private set; }
|
||||
public BackgroundScreen Background { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override to create a BackgroundMode for the current screen.
|
||||
@@ -24,17 +26,19 @@ namespace osu.Game.Screens
|
||||
/// </summary>
|
||||
protected virtual BackgroundScreen CreateBackground() => null;
|
||||
|
||||
internal virtual bool ShowOverlays => true;
|
||||
public virtual bool ShowOverlays => true;
|
||||
|
||||
protected new OsuGameBase Game => base.Game as OsuGameBase;
|
||||
|
||||
internal virtual bool HasLocalCursorDisplayed => false;
|
||||
public virtual bool HasLocalCursorDisplayed => false;
|
||||
|
||||
private OsuLogo logo;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the beatmap or ruleset should be allowed to be changed by the user or game.
|
||||
/// Used to mark exclusive areas where this is strongly prohibited, like gameplay.
|
||||
/// </summary>
|
||||
internal virtual bool AllowBeatmapRulesetChange => true;
|
||||
public virtual bool AllowBeatmapRulesetChange => true;
|
||||
|
||||
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
@@ -72,9 +76,16 @@ namespace osu.Game.Screens
|
||||
protected override void OnResuming(Screen last)
|
||||
{
|
||||
base.OnResuming(last);
|
||||
logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, true));
|
||||
sampleExit?.Play();
|
||||
}
|
||||
|
||||
protected override void OnSuspending(Screen next)
|
||||
{
|
||||
base.OnSuspending(next);
|
||||
onSuspendingLogo();
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
OsuScreen lastOsu = last as OsuScreen;
|
||||
@@ -106,11 +117,19 @@ namespace osu.Game.Screens
|
||||
});
|
||||
}
|
||||
|
||||
if ((logo = lastOsu?.logo) == null)
|
||||
AddInternal(logo = new OsuLogo());
|
||||
|
||||
base.OnEntering(last);
|
||||
|
||||
logo.DelayUntilTransformsFinished().Schedule(() => LogoArriving(logo, false));
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
if (ValidForResume && logo != null)
|
||||
onExitingLogo();
|
||||
|
||||
OsuScreen nextOsu = next as OsuScreen;
|
||||
|
||||
if (Background != null && !Background.Equals(nextOsu?.Background))
|
||||
@@ -128,5 +147,40 @@ namespace osu.Game.Screens
|
||||
Beatmap.UnbindAll();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fired when this screen was entered or resumed and the logo state is required to be adjusted.
|
||||
/// </summary>
|
||||
protected virtual void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
logo.Action = null;
|
||||
logo.FadeOut(300, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void onExitingLogo()
|
||||
{
|
||||
logo.ClearTransforms();
|
||||
LogoExiting(logo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fired when this screen was exited to add any outwards transition to the logo.
|
||||
/// </summary>
|
||||
protected virtual void LogoExiting(OsuLogo logo)
|
||||
{
|
||||
}
|
||||
|
||||
private void onSuspendingLogo()
|
||||
{
|
||||
logo.ClearTransforms();
|
||||
LogoSuspending(logo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fired when this screen was suspended to add any outwards transition to the logo.
|
||||
/// </summary>
|
||||
protected virtual void LogoSuspending(OsuLogo logo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Screens.Play.BreaksOverlay
|
||||
{
|
||||
@@ -30,6 +31,8 @@ namespace osu.Game.Screens.Play.BreaksOverlay
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
private readonly bool letterboxing;
|
||||
private readonly LetterboxOverlay letterboxOverlay;
|
||||
private readonly Container remainingTimeAdjustmentBox;
|
||||
@@ -101,38 +104,41 @@ namespace osu.Game.Screens.Play.BreaksOverlay
|
||||
if (!b.HasEffect)
|
||||
continue;
|
||||
|
||||
using (BeginAbsoluteSequence(b.StartTime, true))
|
||||
{
|
||||
remainingTimeAdjustmentBox
|
||||
.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint)
|
||||
.Delay(b.Duration - fade_duration)
|
||||
.ResizeWidthTo(0);
|
||||
|
||||
remainingTimeBox
|
||||
.ResizeWidthTo(0, b.Duration - fade_duration)
|
||||
.Then()
|
||||
.ResizeWidthTo(1);
|
||||
|
||||
remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration);
|
||||
}
|
||||
|
||||
using (BeginAbsoluteSequence(b.StartTime))
|
||||
{
|
||||
Schedule(() => onBreakIn(b));
|
||||
Schedule(showBreak);
|
||||
using (BeginDelayedSequence(b.Duration - fade_duration))
|
||||
Schedule(onBreakOut);
|
||||
Schedule(hideBreak);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onBreakIn(BreakPeriod b)
|
||||
private void showBreak()
|
||||
{
|
||||
if (letterboxing)
|
||||
letterboxOverlay.Show();
|
||||
|
||||
remainingTimeAdjustmentBox
|
||||
.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint)
|
||||
.Delay(b.Duration - fade_duration)
|
||||
.ResizeWidthTo(0);
|
||||
|
||||
remainingTimeBox
|
||||
.ResizeWidthTo(0, b.Duration - fade_duration)
|
||||
.Then()
|
||||
.ResizeWidthTo(1);
|
||||
|
||||
remainingTimeCounter.StartCounting(b.EndTime);
|
||||
|
||||
remainingTimeCounter.Show();
|
||||
info.Show();
|
||||
arrowsOverlay.Show();
|
||||
}
|
||||
|
||||
private void onBreakOut()
|
||||
private void hideBreak()
|
||||
{
|
||||
if (letterboxing)
|
||||
letterboxOverlay.Hide();
|
||||
|
||||
@@ -1,65 +1,37 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics;
|
||||
using System;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Screens.Play.BreaksOverlay
|
||||
{
|
||||
public class RemainingTimeCounter : VisibilityContainer
|
||||
public class RemainingTimeCounter : Counter
|
||||
{
|
||||
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2;
|
||||
|
||||
private readonly OsuSpriteText counter;
|
||||
|
||||
private int? previousSecond;
|
||||
|
||||
private double endTime;
|
||||
|
||||
private bool isCounting;
|
||||
|
||||
public RemainingTimeCounter()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Child = counter = new OsuSpriteText
|
||||
InternalChild = counter = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
TextSize = 33,
|
||||
Font = "Venera",
|
||||
};
|
||||
|
||||
Alpha = 0;
|
||||
}
|
||||
|
||||
public void StartCounting(double endTime)
|
||||
{
|
||||
this.endTime = endTime;
|
||||
isCounting = true;
|
||||
}
|
||||
protected override void OnCountChanged(double count) => counter.Text = ((int)Math.Ceiling(count / 1000)).ToString();
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (isCounting)
|
||||
{
|
||||
var currentTime = Clock.CurrentTime;
|
||||
if (currentTime < endTime)
|
||||
{
|
||||
int currentSecond = (int)Math.Ceiling((endTime - Clock.CurrentTime) / 1000.0);
|
||||
if (currentSecond != previousSecond)
|
||||
{
|
||||
counter.Text = currentSecond.ToString();
|
||||
previousSecond = currentSecond;
|
||||
}
|
||||
}
|
||||
else isCounting = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn() => this.FadeIn(fade_duration);
|
||||
protected override void PopOut() => this.FadeOut(fade_duration);
|
||||
public override void Show() => this.FadeIn(fade_duration);
|
||||
public override void Hide() => this.FadeOut(fade_duration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Play.ReplaySettings;
|
||||
using OpenTK;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Game.Screens.Play.HUD
|
||||
{
|
||||
public class ReplaySettingsOverlay : VisibilityContainer
|
||||
{
|
||||
private const int fade_duration = 200;
|
||||
|
||||
public bool ReplayLoaded;
|
||||
|
||||
public override bool HandleInput => true;
|
||||
|
||||
public readonly PlaybackSettings PlaybackSettings;
|
||||
//public readonly CollectionSettings CollectionSettings;
|
||||
//public readonly DiscussionSettings DiscussionSettings;
|
||||
|
||||
public ReplaySettingsOverlay()
|
||||
{
|
||||
AlwaysPresent = true;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Child = new FillFlowContainer<ReplayGroup>
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 20),
|
||||
Margin = new MarginPadding { Top = 100, Right = 10 },
|
||||
Children = new []
|
||||
{
|
||||
//CollectionSettings = new CollectionSettings(),
|
||||
//DiscussionSettings = new DiscussionSettings(),
|
||||
PlaybackSettings = new PlaybackSettings(),
|
||||
}
|
||||
};
|
||||
|
||||
State = Visibility.Visible;
|
||||
}
|
||||
|
||||
protected override void PopIn() => this.FadeIn(fade_duration);
|
||||
protected override void PopOut() => this.FadeOut(fade_duration);
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Repeat) return false;
|
||||
|
||||
if (state.Keyboard.ControlPressed)
|
||||
{
|
||||
if (args.Key == Key.H && ReplayLoaded)
|
||||
{
|
||||
ToggleVisibility();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnKeyDown(state, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ namespace osu.Game.Screens.Play
|
||||
public readonly HealthDisplay HealthDisplay;
|
||||
public readonly SongProgress Progress;
|
||||
public readonly ModDisplay ModDisplay;
|
||||
public readonly ReplaySettingsOverlay ReplaySettingsOverlay;
|
||||
|
||||
private Bindable<bool> showHud;
|
||||
private bool replayLoaded;
|
||||
@@ -55,7 +56,7 @@ namespace osu.Game.Screens.Play
|
||||
HealthDisplay = CreateHealthDisplay(),
|
||||
Progress = CreateProgress(),
|
||||
ModDisplay = CreateModsContainer(),
|
||||
//ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
||||
ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -96,9 +97,14 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
replayLoaded = rulesetContainer.HasReplayLoaded;
|
||||
|
||||
ReplaySettingsOverlay.ReplayLoaded = replayLoaded;
|
||||
|
||||
// in the case a replay isn't loaded, we want some elements to only appear briefly.
|
||||
if (!replayLoaded)
|
||||
{
|
||||
ReplaySettingsOverlay.Hide();
|
||||
ModDisplay.Delay(2000).FadeOut(200);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
@@ -176,12 +182,7 @@ namespace osu.Game.Screens.Play
|
||||
Margin = new MarginPadding { Top = 20, Right = 10 },
|
||||
};
|
||||
|
||||
//protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay
|
||||
//{
|
||||
// Anchor = Anchor.TopRight,
|
||||
// Origin = Anchor.TopRight,
|
||||
// Margin = new MarginPadding { Top = 100, Right = 10 },
|
||||
//};
|
||||
protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay();
|
||||
|
||||
public virtual void BindProcessor(ScoreProcessor processor)
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@ using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@@ -34,13 +36,13 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap);
|
||||
|
||||
internal override bool ShowOverlays => false;
|
||||
public override bool ShowOverlays => false;
|
||||
|
||||
internal override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor;
|
||||
public override bool HasLocalCursorDisplayed => !pauseContainer.IsPaused && !HasFailed && RulesetContainer.ProvidingUserCursor;
|
||||
|
||||
public Action RestartRequested;
|
||||
|
||||
internal override bool AllowBeatmapRulesetChange => false;
|
||||
public override bool AllowBeatmapRulesetChange => false;
|
||||
|
||||
public bool HasFailed { get; private set; }
|
||||
|
||||
@@ -142,14 +144,20 @@ namespace osu.Game.Screens.Play
|
||||
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
||||
userAudioOffset.TriggerChange();
|
||||
|
||||
Schedule(() =>
|
||||
Task.Run(() =>
|
||||
{
|
||||
adjustableSourceClock.Reset();
|
||||
|
||||
foreach (var mod in working.Mods.Value.OfType<IApplicableToClock>())
|
||||
mod.ApplyToClock(adjustableSourceClock);
|
||||
// this is temporary until we have blocking (async.Wait()) audio component methods.
|
||||
// then we can call ResetAsync().Wait() or the blocking version above.
|
||||
while (adjustableSourceClock.IsRunning)
|
||||
Thread.Sleep(1);
|
||||
|
||||
decoupledClock.ChangeSource(adjustableSourceClock);
|
||||
Schedule(() =>
|
||||
{
|
||||
decoupledClock.ChangeSource(adjustableSourceClock);
|
||||
applyRateFromMods();
|
||||
});
|
||||
});
|
||||
|
||||
Children = new Drawable[]
|
||||
@@ -230,11 +238,20 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
breakOverlay.BindProcessor(scoreProcessor);
|
||||
|
||||
hudOverlay.ReplaySettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
||||
|
||||
// Bind ScoreProcessor to ourselves
|
||||
scoreProcessor.AllJudged += onCompletion;
|
||||
scoreProcessor.Failed += onFail;
|
||||
}
|
||||
|
||||
private void applyRateFromMods()
|
||||
{
|
||||
adjustableSourceClock.Rate = 1;
|
||||
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
|
||||
mod.ApplyToClock(adjustableSourceClock);
|
||||
}
|
||||
|
||||
private void initializeStoryboard(bool asyncLoad)
|
||||
{
|
||||
var beatmap = Beatmap.Value.Beatmap;
|
||||
@@ -332,6 +349,9 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
if (HasFailed || !ValidForResume || pauseContainer?.AllowExit != false || RulesetContainer?.HasReplayLoaded != false)
|
||||
{
|
||||
// In the case of replays, we may have changed the playback rate.
|
||||
applyRateFromMods();
|
||||
|
||||
fadeOut();
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Screens.Menu;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@@ -20,13 +20,12 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
private Player player;
|
||||
|
||||
private readonly OsuLogo logo;
|
||||
private BeatmapMetadataDisplay info;
|
||||
|
||||
private bool showOverlays = true;
|
||||
internal override bool ShowOverlays => showOverlays;
|
||||
public override bool ShowOverlays => showOverlays;
|
||||
|
||||
internal override bool AllowBeatmapRulesetChange => false;
|
||||
public override bool AllowBeatmapRulesetChange => false;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap);
|
||||
|
||||
@@ -39,15 +38,6 @@ namespace osu.Game.Screens.Play
|
||||
showOverlays = false;
|
||||
ValidForResume = true;
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
logo = new OsuLogo
|
||||
{
|
||||
Scale = new Vector2(0.15f),
|
||||
Interactive = false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@@ -101,11 +91,24 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
contentIn();
|
||||
|
||||
logo.Delay(500).MoveToOffset(new Vector2(0, -180), 500, Easing.InOutExpo);
|
||||
info.Delay(750).FadeIn(500);
|
||||
this.Delay(2150).Schedule(pushWhenLoaded);
|
||||
}
|
||||
|
||||
protected override void LogoArriving(OsuLogo logo, bool resuming)
|
||||
{
|
||||
base.LogoArriving(logo, resuming);
|
||||
|
||||
logo.ClearTransforms(targetMember: nameof(Position));
|
||||
logo.RelativePositionAxes = Axes.Both;
|
||||
|
||||
logo.ScaleTo(new Vector2(0.15f), 300, Easing.In);
|
||||
logo.MoveTo(new Vector2(0.5f), 300, Easing.In);
|
||||
logo.FadeIn(350);
|
||||
|
||||
logo.Delay(resuming ? 0 : 500).MoveToOffset(new Vector2(0, -0.24f), 500, Easing.InOutExpo);
|
||||
}
|
||||
|
||||
private void pushWhenLoaded()
|
||||
{
|
||||
if (player.LoadState != LoadState.Ready)
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Screens.Play.ReplaySettings
|
||||
{
|
||||
@@ -11,18 +10,34 @@ namespace osu.Game.Screens.Play.ReplaySettings
|
||||
{
|
||||
protected override string Title => @"playback";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
public IAdjustableClock AdjustableClock { set; get; }
|
||||
|
||||
private readonly ReplaySliderBar<double> sliderbar;
|
||||
|
||||
public PlaybackSettings()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
Child = sliderbar = new ReplaySliderBar<double>
|
||||
{
|
||||
new ReplaySliderBar<double>
|
||||
LabelText = "Playback speed",
|
||||
Bindable = new BindableDouble(1)
|
||||
{
|
||||
LabelText = "Playback speed",
|
||||
Bindable = config.GetBindable<double>(OsuSetting.PlaybackSpeed),
|
||||
KeyboardStep = 0.5f
|
||||
}
|
||||
Default = 1,
|
||||
MinValue = 0.5,
|
||||
MaxValue = 2,
|
||||
Precision = 0.01,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (AdjustableClock == null)
|
||||
return;
|
||||
|
||||
var clockRate = AdjustableClock.Rate;
|
||||
sliderbar.Bindable.ValueChanged += rateMultiplier => AdjustableClock.Rate = clockRate * rateMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Screens.Play.ReplaySettings;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
public class ReplaySettingsOverlay : FillFlowContainer
|
||||
{
|
||||
public ReplaySettingsOverlay()
|
||||
{
|
||||
Direction = FillDirection.Vertical;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Spacing = new Vector2(0, 20);
|
||||
|
||||
Add(new CollectionSettings());
|
||||
Add(new DiscussionSettings());
|
||||
Add(new PlaybackSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking
|
||||
|
||||
private ResultModeTabControl modeChangeButtons;
|
||||
|
||||
internal override bool AllowBeatmapRulesetChange => false;
|
||||
public override bool AllowBeatmapRulesetChange => false;
|
||||
|
||||
private Container currentPage;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user