1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 09:02:55 +08:00

Merge branch 'master' of https://github.com/ppy/osu into musiccontroller-canbeatmapchange

This commit is contained in:
MrTheMake 2017-07-19 16:50:29 +02:00
commit 6ff2b73c30
65 changed files with 2103 additions and 507 deletions

@ -1 +1 @@
Subproject commit 991177da4fbed2dd8260c215f2d341ebc858b03e
Subproject commit 6b44a9f807fadcb3b3f044780d7e27d62ffe80ac

View File

@ -151,6 +151,8 @@ namespace osu.Desktop.VisualTests.Tests
private int calculateBeatCount(TimingControlPoint current)
{
if (timingPoints.Count == 0) return 0;
if (timingPoints[timingPoints.Count - 1] == current)
return (int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength);

View File

@ -81,7 +81,7 @@ namespace osu.Desktop.VisualTests.Tests
{
return new Player
{
Beatmap = beatmap
InitialBeatmap = beatmap
};
}
}

View File

@ -59,7 +59,7 @@ namespace osu.Desktop.VisualTests.Tests
}
})
{
Beatmap = beatmap
InitialBeatmap = beatmap
});
}
}

View File

@ -0,0 +1,64 @@
// 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 osu.Framework.Testing;
using osu.Game.Overlays;
using osu.Game.Users;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseUserProfile : TestCase
{
public override string Description => "Tests user's profile page.";
public TestCaseUserProfile()
{
var profile = new UserProfileOverlay();
Add(profile);
AddStep("Show offline dummy", () => profile.ShowUser(new User
{
Username = @"Somebody",
Id = 1,
Country = new Country { FullName = @"Alien" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
JoinDate = DateTimeOffset.Now.AddDays(-1),
LastVisit = DateTimeOffset.Now,
Age = 1,
ProfileOrder = new[] { "me" },
CountryRank = 1,
Statistics = new UserStatistics
{
Rank = 2148,
PP = 4567.89m
},
AllRankHistories = new User.RankHistories
{
Osu = new User.RankHistory
{
Mode = @"osu",
Data = Enumerable.Range(2345,45).Concat(Enumerable.Range(2109,40)).ToArray()
}
}
}, false));
AddStep("Show ppy", () => profile.ShowUser(new User
{
Username = @"peppy",
Id = 2,
Country = new Country { FullName = @"Australia", FlagName = @"AU" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg"
}));
AddStep("Show flyte", () => profile.ShowUser(new User
{
Username = @"flyte",
Id = 3103765,
Country = new Country { FullName = @"Japan", FlagName = @"JP" },
CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
}));
AddStep("Hide", profile.Hide);
AddStep("Show without reload", profile.Show);
}
}
}

View File

@ -216,6 +216,7 @@
<Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
<Compile Include="Tests\TestCaseUserProfile.cs" />
<Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseSettings.cs" />

View File

@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Mania.UI
{
base.ApplyBeatmap();
PreferredColumns = (int)Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize);
PreferredColumns = (int)Math.Max(1, Math.Round(Beatmap.BeatmapInfo.Difficulty.CircleSize));
}
protected override void ApplySpeedAdjustments()

View File

@ -5,7 +5,7 @@ using System;
namespace osu.Game.Beatmaps.ControlPoints
{
public class ControlPoint : IComparable<ControlPoint>
public class ControlPoint : IComparable<ControlPoint>, IEquatable<ControlPoint>
{
/// <summary>
/// The time at which the control point takes effect.
@ -13,5 +13,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public double Time;
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
public bool Equals(ControlPoint other) => Time.Equals(other?.Time);
}
}

View File

@ -0,0 +1,82 @@
// 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.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play;
namespace osu.Game.Beatmaps
{
internal class DummyWorkingBeatmap : WorkingBeatmap
{
private readonly OsuGameBase game;
public DummyWorkingBeatmap(OsuGameBase game)
: base(new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = "please load a beatmap!",
Title = "no beatmaps available!",
Author = "no one",
},
BeatmapSet = new BeatmapSetInfo(),
Difficulty = new BeatmapDifficulty
{
DrainRate = 0,
CircleSize = 0,
OverallDifficulty = 0,
ApproachRate = 0,
SliderMultiplier = 0,
SliderTickRate = 0,
},
Ruleset = new DummyRulesetInfo()
})
{
this.game = game;
}
protected override Beatmap GetBeatmap() => new Beatmap
{
HitObjects = new List<HitObject>(),
};
protected override Texture GetBackground() => game.Textures.Get(@"Backgrounds/bg4");
protected override Track GetTrack() => new TrackVirtual();
private class DummyRulesetInfo : RulesetInfo
{
public override Ruleset CreateInstance() => new DummyRuleset();
private class DummyRuleset : Ruleset
{
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[] { };
public override HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap, bool isForCurrentRuleset)
{
throw new NotImplementedException();
}
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => null;
public override ScoreProcessor CreateScoreProcessor()
{
throw new NotImplementedException();
}
public override string Description => "dummy";
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new List<KeyCounter>();
}
}
}
}

View File

@ -15,7 +15,7 @@ namespace osu.Game.Beatmaps.IO
AddReader<OszArchiveReader>((storage, path) =>
{
using (var stream = storage.GetStream(path))
return ZipFile.IsZipFile(stream, false);
return stream != null && ZipFile.IsZipFile(stream, false);
});
OsuLegacyDecoder.Register();
}

View File

@ -28,6 +28,11 @@ namespace osu.Game.Database
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc;
/// <summary>
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
/// </summary>
public WorkingBeatmap DefaultBeatmap { private get; set; }
public BeatmapDatabase(Storage storage, SQLiteConnection connection, RulesetDatabase rulesets, IIpcHost importHost = null) : base(storage, connection)
{
this.rulesets = rulesets;
@ -144,7 +149,11 @@ namespace osu.Game.Database
public void Import(params string[] paths)
{
foreach (string p in paths)
Import(p);
{
//In case the file was imported twice and deleted after the first time
if (File.Exists(p))
Import(p);
}
}
/// <summary>
@ -178,6 +187,8 @@ namespace osu.Game.Database
if (existing != null)
{
GetChildren(existing);
if (existing.DeletePending)
{
existing.DeletePending = false;
@ -268,6 +279,9 @@ namespace osu.Game.Database
public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo, WorkingBeatmap previous = null, bool withStoryboard = false)
{
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
if (beatmapInfo.BeatmapSet == null || beatmapInfo.Ruleset == null)
beatmapInfo = GetChildren(beatmapInfo, true);

View File

@ -21,6 +21,6 @@ namespace osu.Game.Database
[Indexed]
public bool Available { get; set; }
public Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo));
public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo));
}
}

View File

@ -35,10 +35,12 @@ namespace osu.Game.Graphics.Containers
protected override void Update()
{
if (Beatmap.Value?.Track == null)
var track = Beatmap.Value.Track;
if (track == null)
return;
double currentTrackTime = Beatmap.Value.Track.CurrentTime + EarlyActivationMilliseconds;
double currentTrackTime = track.Length > 0 ? track.CurrentTime + EarlyActivationMilliseconds : Clock.CurrentTime;
TimingControlPoint timingPoint = Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(currentTrackTime);
EffectControlPoint effectPoint = Beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(currentTrackTime);
@ -58,7 +60,7 @@ namespace osu.Game.Graphics.Containers
TimeSinceLastBeat = timingPoint.BeatLength - TimeUntilNextBeat;
if (timingPoint == lastTimingPoint && beatIndex == lastBeat)
if (timingPoint.Equals(lastTimingPoint) && beatIndex == lastBeat)
return;
using (BeginDelayedSequence(-TimeSinceLastBeat, true))

View File

@ -0,0 +1,21 @@
// 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.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.Containers
{
public class OsuTextFlowContainer : TextFlowContainer
{
public OsuTextFlowContainer(Action<SpriteText> defaultCreationParameters = null) : base(defaultCreationParameters)
{
}
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
public void AddIcon(FontAwesome icon, Action<SpriteText> creationParameters = null) => AddText(((char)icon).ToString(), creationParameters);
}
}

View File

@ -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 osu.Framework.Configuration;
using osu.Framework.Graphics;
@ -13,11 +12,15 @@ namespace osu.Game.Graphics.Containers
/// <summary>
/// A container that can scroll to each section inside it.
/// </summary>
public class SectionsContainer : Container
public class SectionsContainer<T> : Container<T>
where T : Drawable
{
private Drawable expandableHeader, fixedHeader, footer;
public readonly ScrollContainer ScrollContainer;
private readonly Container<Drawable> sectionsContainer;
private Drawable expandableHeader, fixedHeader, footer, headerBackground;
private readonly ScrollContainer scrollContainer;
private readonly Container headerBackgroundContainer;
private readonly FlowContainer<T> scrollContentContainer;
protected override Container<T> Content => scrollContentContainer;
public Drawable ExpandableHeader
{
@ -26,12 +29,11 @@ namespace osu.Game.Graphics.Containers
{
if (value == expandableHeader) return;
if (expandableHeader != null)
Remove(expandableHeader);
expandableHeader?.Expire();
expandableHeader = value;
if (value == null) return;
Add(expandableHeader);
AddInternal(expandableHeader);
lastKnownScroll = float.NaN;
}
}
@ -43,12 +45,11 @@ namespace osu.Game.Graphics.Containers
{
if (value == fixedHeader) return;
if (fixedHeader != null)
Remove(fixedHeader);
fixedHeader?.Expire();
fixedHeader = value;
if (value == null) return;
Add(fixedHeader);
AddInternal(fixedHeader);
lastKnownScroll = float.NaN;
}
}
@ -61,69 +62,84 @@ namespace osu.Game.Graphics.Containers
if (value == footer) return;
if (footer != null)
ScrollContainer.Remove(footer);
scrollContainer.Remove(footer);
footer = value;
if (value == null) return;
footer.Anchor |= Anchor.y2;
footer.Origin |= Anchor.y2;
ScrollContainer.Add(footer);
scrollContainer.Add(footer);
lastKnownScroll = float.NaN;
}
}
public Bindable<Drawable> SelectedSection { get; } = new Bindable<Drawable>();
protected virtual Container<Drawable> CreateScrollContentContainer()
=> new FillFlowContainer
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both
};
private List<Drawable> sections = new List<Drawable>();
public IEnumerable<Drawable> Sections
public Drawable HeaderBackground
{
get { return sections; }
get { return headerBackground; }
set
{
foreach (var section in sections)
sectionsContainer.Remove(section);
if (value == headerBackground) return;
sections = value.ToList();
if (sections.Count == 0) return;
headerBackgroundContainer.Clear();
headerBackground = value;
if (value == null) return;
headerBackgroundContainer.Add(headerBackground);
sectionsContainer.AddRange(sections);
SelectedSection.Value = sections[0];
lastKnownScroll = float.NaN;
}
}
public Bindable<T> SelectedSection { get; } = new Bindable<T>();
protected virtual FlowContainer<T> CreateScrollContentContainer()
=> new FillFlowContainer<T>
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
};
public override void Add(T drawable)
{
base.Add(drawable);
lastKnownScroll = float.NaN;
headerHeight = float.NaN;
footerHeight = float.NaN;
}
private float headerHeight, footerHeight;
private readonly MarginPadding originalSectionsMargin;
private void updateSectionsMargin()
{
if (sections.Count == 0) return;
if (!Children.Any()) return;
var newMargin = originalSectionsMargin;
newMargin.Top += headerHeight;
newMargin.Bottom += footerHeight;
sectionsContainer.Margin = newMargin;
scrollContentContainer.Margin = newMargin;
}
public SectionsContainer()
{
Add(ScrollContainer = new OsuScrollContainer
AddInternal(scrollContainer = new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
Masking = false,
Children = new Drawable[] { sectionsContainer = CreateScrollContentContainer() }
Masking = true,
ScrollbarVisible = false,
Children = new Drawable[] { scrollContentContainer = CreateScrollContentContainer() },
Depth = float.MaxValue
});
originalSectionsMargin = sectionsContainer.Margin;
AddInternal(headerBackgroundContainer = new Container
{
RelativeSizeAxes = Axes.X,
Depth = float.MaxValue / 2
});
originalSectionsMargin = scrollContentContainer.Margin;
}
public void ScrollTo(Drawable section) => ScrollContainer.ScrollTo(ScrollContainer.GetChildPosInContent(section) - FixedHeader.BoundingBox.Height);
public void ScrollTo(Drawable section) => scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0));
private float lastKnownScroll;
protected override void UpdateAfterChildren()
@ -139,25 +155,30 @@ namespace osu.Game.Graphics.Containers
updateSectionsMargin();
}
float currentScroll = Math.Max(0, ScrollContainer.Current);
float currentScroll = scrollContainer.Current;
if (currentScroll != lastKnownScroll)
{
lastKnownScroll = currentScroll;
if (expandableHeader != null && fixedHeader != null)
if (ExpandableHeader != null && FixedHeader != null)
{
float offset = Math.Min(expandableHeader.LayoutSize.Y, currentScroll);
float offset = Math.Min(ExpandableHeader.LayoutSize.Y, currentScroll);
expandableHeader.Y = -offset;
fixedHeader.Y = -offset + expandableHeader.LayoutSize.Y;
ExpandableHeader.Y = -offset;
FixedHeader.Y = -offset + ExpandableHeader.LayoutSize.Y;
}
Drawable bestMatch = null;
float minDiff = float.MaxValue;
headerBackgroundContainer.Height = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
headerBackgroundContainer.Y = ExpandableHeader?.Y ?? 0;
foreach (var section in sections)
T bestMatch = null;
float minDiff = float.MaxValue;
float scrollOffset = FixedHeader?.LayoutSize.Y ?? 0;
foreach (var section in Children)
{
float diff = Math.Abs(ScrollContainer.GetChildPosInContent(section) - currentScroll);
float diff = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll - scrollOffset);
if (diff < minDiff)
{
minDiff = diff;

View File

@ -83,6 +83,8 @@ namespace osu.Game.Graphics.Cursor
protected override void PopIn()
{
instantMovement |= !IsPresent;
ClearTransforms();
FadeIn(500, EasingTypes.OutQuint);
}

View File

@ -0,0 +1,102 @@
// 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 OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
namespace osu.Game.Graphics.UserInterface
{
public class LineGraph : Container
{
/// <summary>
/// Manually set the max value, otherwise <see cref="Enumerable.Max(IEnumerable{float})"/> will be used.
/// </summary>
public float? MaxValue { get; set; }
/// <summary>
/// Manually set the min value, otherwise <see cref="Enumerable.Min(IEnumerable{float})"/> will be used.
/// </summary>
public float? MinValue { get; set; }
public float ActualMaxValue { get; private set; } = float.NaN;
public float ActualMinValue { get; private set; } = float.NaN;
private const double transform_duration = 1500;
/// <summary>
/// Hold an empty area if values are less.
/// </summary>
public int DefaultValueCount;
private readonly Container<Path> maskingContainer;
private readonly Path path;
private float[] values;
/// <summary>
/// A list of floats decides position of each line node.
/// </summary>
public IEnumerable<float> Values
{
get { return values; }
set
{
values = value.ToArray();
applyPath();
maskingContainer.Width = 0;
maskingContainer.ResizeWidthTo(1, transform_duration, EasingTypes.OutQuint);
}
}
public LineGraph()
{
Add(maskingContainer = new Container<Path>
{
Masking = true,
RelativeSizeAxes = Axes.Both,
Child = path = new Path { RelativeSizeAxes = Axes.Both, PathWidth = 1 }
});
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) != 0)
applyPath();
return base.Invalidate(invalidation, source, shallPropagate);
}
private void applyPath()
{
path.ClearVertices();
if (values == null) return;
int count = Math.Max(values.Length, DefaultValueCount);
float max = values.Max(), min = values.Min();
if (MaxValue > max) max = MaxValue.Value;
if (MinValue < min) min = MinValue.Value;
ActualMaxValue = max;
ActualMinValue = min;
for (int i = 0; i < values.Length; i++)
{
float x = (i + count - values.Length) / (float)(count - 1) * DrawWidth - 1;
float y = GetYPosition(values[i]) * DrawHeight - 1;
// the -1 is for inner offset in path (actually -PathWidth)
path.AddVertex(new Vector2(x, y));
}
}
protected float GetYPosition(float value)
{
if (ActualMaxValue == ActualMinValue) return 0;
return (ActualMaxValue - value) / (ActualMaxValue - ActualMinValue);
}
}
}

View File

@ -23,7 +23,7 @@ namespace osu.Game.Graphics.UserInterface
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem(value);
private bool isEnumType => typeof(T).IsEnum;
private static bool isEnumType => typeof(T).IsEnum;
public OsuTabControl()
{

View File

@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
@ -23,12 +24,14 @@ namespace osu.Game.Graphics.UserInterface
Height = 30;
}
private class PageTabItem : TabItem<T>
public class PageTabItem : TabItem<T>
{
private const float transition_duration = 100;
private readonly Box box;
protected readonly SpriteText Text;
public PageTabItem(T value) : base(value)
{
AutoSizeAxes = Axes.X;
@ -36,12 +39,12 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[]
{
new OsuSpriteText
Text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 8, Bottom = 8 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Text = (value as Enum).GetDescription() ?? value.ToString(),
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
Font = @"Exo2.0-Bold",
},

View File

@ -7,9 +7,9 @@ namespace osu.Game.Online.API.Requests
{
public class GetUserRequest : APIRequest<User>
{
private int? userId;
private long? userId;
public GetUserRequest(int? userId = null)
public GetUserRequest(long? userId = null)
{
this.userId = userId;
}

View File

@ -45,6 +45,8 @@ namespace osu.Game
private SocialOverlay social;
private UserProfileOverlay userProfile;
private Intro intro
{
get
@ -173,6 +175,7 @@ namespace osu.Game
LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(social = new SocialOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(settings = new SettingsOverlay { Depth = -1 }, overlayContent.Add);
LoadComponentAsync(musicController = new MusicController
{
@ -207,6 +210,7 @@ namespace osu.Game
Dependencies.Cache(settings);
Dependencies.Cache(social);
Dependencies.Cache(chat);
Dependencies.Cache(userProfile);
Dependencies.Cache(musicController);
Dependencies.Cache(notificationManager);
Dependencies.Cache(dialogOverlay);
@ -322,6 +326,7 @@ namespace osu.Game
chat.State = Visibility.Hidden;
direct.State = Visibility.Hidden;
social.State = Visibility.Hidden;
userProfile.State = Visibility.Hidden;
}
else
{

View File

@ -43,7 +43,7 @@ namespace osu.Game
protected MenuCursor Cursor;
public readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
public Bindable<WorkingBeatmap> Beatmap { get; private set; }
private Bindable<bool> fpsDisplayVisible;
@ -121,6 +121,10 @@ namespace osu.Game
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera"));
Fonts.AddStore(new GlyphStore(Resources, @"Fonts/Venera-Light"));
var defaultBeatmap = new DummyWorkingBeatmap(this);
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
BeatmapDatabase.DefaultBeatmap = defaultBeatmap;
OszArchiveReader.Register();
Dependencies.Cache(API = new APIAccess

View File

@ -8,6 +8,9 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Allocation;
namespace osu.Game.Overlays.Chat
{
@ -53,21 +56,14 @@ namespace osu.Game.Overlays.Chat
OsuColour.FromHex("992861"),
};
private Color4 getUsernameColour(Message message)
{
if (!string.IsNullOrEmpty(message.Sender?.Colour))
return OsuColour.FromHex(message.Sender.Colour);
//todo: use User instead of Message when user_id is correctly populated.
return username_colours[message.UserId % username_colours.Length];
}
public const float LEFT_PADDING = message_padding + padding * 2;
private const float padding = 15;
private const float message_padding = 200;
private const float text_size = 20;
private Color4 customUsernameColour;
public ChatLine(Message message)
{
Message = message;
@ -76,13 +72,67 @@ namespace osu.Game.Overlays.Chat
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding { Left = padding, Right = padding };
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
customUsernameColour = colours.ChatBlue;
}
protected override void LoadComplete()
{
base.LoadComplete();
bool hasBackground = !string.IsNullOrEmpty(Message.Sender.Colour);
Drawable username = new OsuSpriteText
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Font = @"Exo2.0-BoldItalic",
Text = $@"{Message.Sender.Username}" + (hasBackground ? "" : ":"),
Colour = hasBackground ? customUsernameColour : username_colours[Message.UserId % username_colours.Length],
TextSize = text_size,
};
if (hasBackground)
{
// Background effect
username = username.WithEffect(new EdgeEffect
{
CornerRadius = 4,
Parameters = new EdgeEffectParameters
{
Radius = 1,
Colour = OsuColour.FromHex(Message.Sender.Colour),
Type = EdgeEffectType.Shadow,
}
}, d =>
{
d.Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 };
d.Y = 3;
})
// Drop shadow effect
.WithEffect(new EdgeEffect
{
CornerRadius = 4,
Parameters = new EdgeEffectParameters
{
Roundness = 1,
Offset = new Vector2(0, 3),
Radius = 3,
Colour = Color4.Black.Opacity(0.3f),
Type = EdgeEffectType.Shadow,
}
});
}
Children = new Drawable[]
{
new Container
{
Size = new Vector2(message_padding, text_size),
Children = new Drawable[]
Children = new[]
{
new OsuSpriteText
{
@ -94,15 +144,7 @@ namespace osu.Game.Overlays.Chat
TextSize = text_size * 0.75f,
Alpha = 0.4f,
},
new OsuSpriteText
{
Font = @"Exo2.0-BoldItalic",
Text = $@"{Message.Sender.Username}:",
Colour = getUsernameColour(Message),
TextSize = text_size,
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
}
username
}
},
new Container

View File

@ -29,6 +29,9 @@ namespace osu.Game.Overlays.Chat
scroll = new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
// Some chat lines have effects that slightly protrude to the bottom,
// which we do not want to mask away, hence the padding.
Padding = new MarginPadding { Bottom = 5 },
Children = new Drawable[]
{
flow = new FillFlowContainer<ChatLine>

View File

@ -111,7 +111,7 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding
{
Bottom = textbox_height + padding
Bottom = textbox_height
},
},
new Container

View File

@ -1,107 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input;
using OpenTK;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays
{
public class DragBar : Container
{
protected readonly Container Fill;
public Action<float> SeekRequested;
public bool IsSeeking { get; private set; }
private bool enabled = true;
public bool IsEnabled
{
get { return enabled; }
set
{
enabled = value;
if (!enabled)
Fill.Width = 0;
}
}
public DragBar()
{
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
Fill = new Container
{
Name = "FillContainer",
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
RelativeSizeAxes = Axes.Both,
Width = 0,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both
}
}
}
};
}
public void UpdatePosition(float position)
{
if (IsSeeking || !IsEnabled) return;
updatePosition(position, false);
}
private void seek(InputState state)
{
float seekLocation = state.Mouse.Position.X / DrawWidth;
if (!IsEnabled) return;
SeekRequested?.Invoke(seekLocation);
updatePosition(seekLocation);
}
private void updatePosition(float position, bool easing = true)
{
position = MathHelper.Clamp(position, 0, 1);
Fill.TransformTo(position, easing ? 200 : 0, EasingTypes.OutQuint, new TransformSeek());
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
seek(state);
return true;
}
protected override bool OnDrag(InputState state)
{
seek(state);
return true;
}
protected override bool OnDragStart(InputState state) => IsSeeking = true;
protected override bool OnDragEnd(InputState state)
{
IsSeeking = false;
return true;
}
private class TransformSeek : TransformFloat<Drawable>
{
public override void Apply(Drawable d) => d.Width = CurrentValue;
public override void ReadIntoStartValue(Drawable d) => StartValue = d.Width;
}
}
}

View File

@ -46,6 +46,7 @@ namespace osu.Game.Overlays
settingsSection = new LoginSettings
{
Padding = new MarginPadding(10),
RequestHide = Hide,
},
new Box
{

View File

@ -2,15 +2,16 @@
// 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.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Database;
using osu.Game.Graphics;
using OpenTK.Graphics;
using osu.Framework.Localisation;
using osu.Framework.Graphics.Sprites;
using System.Collections.Generic;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Music
{
@ -77,7 +78,7 @@ namespace osu.Game.Overlays.Music
Margin = new MarginPadding { Left = 5 },
Padding = new MarginPadding { Top = 2 },
},
text = new TextFlowContainer
text = new OsuTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,

View File

@ -83,11 +83,12 @@ namespace osu.Game.Overlays.Music
},
};
list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>().ToList();
list.BeatmapSets = BeatmapSets = beatmaps.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending).ToList();
beatmapBacking.BindTo(game.Beatmap);
filter.Search.OnCommit = (sender, newText) => {
filter.Search.OnCommit = (sender, newText) =>
{
var beatmap = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
if (beatmap != null) playSpecified(beatmap);
};

View File

@ -14,6 +14,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Framework.Localisation;
using osu.Framework.Threading;
@ -39,7 +40,7 @@ namespace osu.Game.Overlays
private const float bottom_black_area_height = 55;
private Drawable currentBackground;
private DragBar progressBar;
private ProgressBar progressBar;
private IconButton prevButton;
private IconButton playButton;
@ -189,13 +190,13 @@ namespace osu.Game.Overlays
},
}
},
progressBar = new DragBar
progressBar = new ProgressBar
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Height = progress_height,
Colour = colours.Yellow,
SeekRequested = seek
FillColour = colours.Yellow,
OnSeek = progress => current?.Track.Seek(progress)
}
},
},
@ -241,7 +242,9 @@ namespace osu.Game.Overlays
{
var track = current.Track;
progressBar.UpdatePosition(track.Length == 0 ? 0 : (float)(track.CurrentTime / track.Length));
progressBar.EndTime = track.Length;
progressBar.CurrentTime = track.CurrentTime;
playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o;
if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled)
@ -285,13 +288,11 @@ namespace osu.Game.Overlays
private void beatmapChanged(WorkingBeatmap beatmap)
{
progressBar.IsEnabled = beatmap != null;
TransformDirection direction = TransformDirection.None;
if (current != null)
{
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current.BeatmapInfo) ?? false;
bool audioEquals = beatmap?.BeatmapInfo?.AudioEquals(current.BeatmapInfo) ?? false;
if (audioEquals)
direction = TransformDirection.None;
@ -304,15 +305,18 @@ namespace osu.Game.Overlays
{
//figure out the best direction based on order in playlist.
var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
var next = beatmap == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmap.BeatmapSetInfo.ID).Count();
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
}
}
current = beatmapBacking.Value;
current = beatmap;
progressBar.CurrentTime = 0;
updateDisplay(current, direction);
updateDisplay(beatmapBacking, direction);
queuedDirection = null;
}
@ -371,12 +375,6 @@ namespace osu.Game.Overlays
});
}
private void seek(float position)
{
var track = current?.Track;
track?.Seek(track.Length * position);
}
protected override void PopIn()
{
base.PopIn();
@ -437,5 +435,49 @@ namespace osu.Game.Overlays
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
}
}
private class ProgressBar : SliderBar<double>
{
public Action<double> OnSeek;
private readonly Box fill;
public Color4 FillColour
{
set { fill.Colour = value; }
}
public double EndTime
{
set { CurrentNumber.MaxValue = value; }
}
public double CurrentTime
{
set { CurrentNumber.Value = value; }
}
public ProgressBar()
{
CurrentNumber.MinValue = 0;
CurrentNumber.MaxValue = 1;
RelativeSizeAxes = Axes.X;
Children = new Drawable[]
{
fill = new Box
{
RelativeSizeAxes = Axes.Y
}
};
}
protected override void UpdateValue(float value)
{
fill.Width = value * UsableWidth;
}
protected override void OnUserChange() => OnSeek?.Invoke(Current);
}
}
}

View File

@ -0,0 +1,483 @@
// 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 OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile
{
public class ProfileHeader : Container
{
private readonly OsuTextFlowContainer infoTextLeft, infoTextRight;
private readonly FillFlowContainer<SpriteText> scoreText, scoreNumberText;
private readonly Container coverContainer, chartContainer, supporterTag;
private readonly Sprite levelBadge;
private readonly SpriteText levelText;
private readonly GradeBadge gradeSSPlus, gradeSS, gradeSPlus, gradeS, gradeA;
private readonly Box colourBar;
private const float cover_height = 350;
private const float info_height = 150;
private const float info_width = 220;
private const float avatar_size = 110;
private const float level_position = 30;
private const float level_height = 60;
public ProfileHeader(User user)
{
RelativeSizeAxes = Axes.X;
Height = cover_height + info_height;
Children = new Drawable[]
{
coverContainer = new Container
{
RelativeSizeAxes = Axes.X,
Height = cover_height,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientVertical(Color4.Black.Opacity(0.1f), Color4.Black.Opacity(0.75f))
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
X = UserProfileOverlay.CONTENT_X_MARGIN,
Y = -20,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new UpdateableAvatar
{
User = user,
Size = new Vector2(avatar_size),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Masking = true,
CornerRadius = 5,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.25f),
Radius = 4,
},
},
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
X = avatar_size + 10,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
supporterTag = new CircularContainer
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = -75,
Size = new Vector2(25, 25),
Masking = true,
BorderThickness = 3,
BorderColour = Color4.White,
Alpha = 0,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
AlwaysPresent = true
},
new TextAwesome
{
Icon = FontAwesome.fa_heart,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
TextSize = 12
}
}
},
new OsuSpriteText
{
Text = user.Username,
TextSize = 30,
Font = @"Exo2.0-RegularItalic",
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = -48
},
new DrawableFlag(user.Country?.FlagName ?? "__")
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Width = 30,
Height = 20
}
}
}
}
},
colourBar = new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
X = UserProfileOverlay.CONTENT_X_MARGIN,
Height = 5,
Width = info_width,
Alpha = 0
}
}
},
infoTextLeft = new OsuTextFlowContainer(t =>
{
t.TextSize = 14;
t.Alpha = 0.8f;
})
{
X = UserProfileOverlay.CONTENT_X_MARGIN,
Y = cover_height + 20,
Width = info_width,
AutoSizeAxes = Axes.Y,
ParagraphSpacing = 0.8f,
LineSpacing = 0.2f
},
infoTextRight = new OsuTextFlowContainer(t =>
{
t.TextSize = 14;
t.Font = @"Exo2.0-RegularItalic";
})
{
X = UserProfileOverlay.CONTENT_X_MARGIN + info_width + 20,
Y = cover_height + 20,
Width = info_width,
AutoSizeAxes = Axes.Y,
ParagraphSpacing = 0.8f,
LineSpacing = 0.2f
},
new Container
{
X = -UserProfileOverlay.CONTENT_X_MARGIN,
RelativeSizeAxes = Axes.Y,
Width = 280,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
Y = level_position,
Height = level_height,
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black.Opacity(0.5f),
RelativeSizeAxes = Axes.Both
},
levelBadge = new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Height = 50,
Width = 50,
Alpha = 0
},
levelText = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = 11,
TextSize = 20
}
}
},
new Container
{
RelativeSizeAxes = Axes.X,
Y = cover_height,
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
Height = cover_height - level_height - level_position - 5,
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black.Opacity(0.5f),
RelativeSizeAxes = Axes.Both
},
scoreText = new FillFlowContainer<SpriteText>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Horizontal = 20, Vertical = 18 },
Spacing = new Vector2(0, 2)
},
scoreNumberText = new FillFlowContainer<SpriteText>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Padding = new MarginPadding { Horizontal = 20, Vertical = 18 },
Spacing = new Vector2(0, 2)
},
new FillFlowContainer<GradeBadge>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Y = -64,
Spacing = new Vector2(20, 0),
Children = new[]
{
gradeSSPlus = new GradeBadge("SSPlus") { Alpha = 0 },
gradeSS = new GradeBadge("SS") { Alpha = 0 },
}
},
new FillFlowContainer<GradeBadge>
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Y = -18,
Spacing = new Vector2(20, 0),
Children = new[]
{
gradeSPlus = new GradeBadge("SPlus") { Alpha = 0 },
gradeS = new GradeBadge("S") { Alpha = 0 },
gradeA = new GradeBadge("A") { Alpha = 0 },
}
}
}
},
chartContainer = new Container
{
RelativeSizeAxes = Axes.X,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Height = info_height - 15,
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black.Opacity(0.25f),
RelativeSizeAxes = Axes.Both
}
}
}
}
}
};
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
levelBadge.Texture = textures.Get(@"Profile/levelbadge");
}
private User user;
public User User
{
get
{
return user;
}
set
{
user = value;
loadUser();
}
}
private void loadUser()
{
coverContainer.Add(new AsyncLoadWrapper(new UserCoverBackground(user)
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fill,
OnLoadComplete = d => d.FadeInFromZero(200)
})
{
Masking = true,
RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue
});
if (user.IsSupporter) supporterTag.Show();
if (!string.IsNullOrEmpty(user.Colour))
{
colourBar.Colour = OsuColour.FromHex(user.Colour);
colourBar.Show();
}
Action<SpriteText> boldItalic = t =>
{
t.Font = @"Exo2.0-BoldItalic";
t.Alpha = 1;
};
if (user.Age != null)
{
infoTextLeft.AddText($"{user.Age} years old ", boldItalic);
}
if (user.Country != null)
{
infoTextLeft.AddText("from ");
infoTextLeft.AddText(user.Country.FullName, boldItalic);
}
infoTextLeft.NewParagraph();
if (user.JoinDate.ToUniversalTime().Year < 2008)
{
infoTextLeft.AddText("Here since the beginning", boldItalic);
}
else
{
infoTextLeft.AddText("Joined ");
infoTextLeft.AddText(user.JoinDate.LocalDateTime.ToShortDateString(), boldItalic);
}
infoTextLeft.NewLine();
infoTextLeft.AddText("Last seen ");
infoTextLeft.AddText(user.LastVisit.LocalDateTime.ToShortDateString(), boldItalic);
infoTextLeft.NewParagraph();
if (user.PlayStyle?.Length > 0)
{
infoTextLeft.AddText("Plays with ");
infoTextLeft.AddText(string.Join(", ", user.PlayStyle), boldItalic);
}
tryAddInfoRightLine(FontAwesome.fa_map_marker, user.Location);
tryAddInfoRightLine(FontAwesome.fa_heart_o, user.Intrerests);
tryAddInfoRightLine(FontAwesome.fa_suitcase, user.Occupation);
infoTextRight.NewParagraph();
if (!string.IsNullOrEmpty(user.Twitter))
tryAddInfoRightLine(FontAwesome.fa_twitter, "@" + user.Twitter);
tryAddInfoRightLine(FontAwesome.fa_globe, user.Website);
tryAddInfoRightLine(FontAwesome.fa_skype, user.Skype);
if (user.Statistics != null)
{
levelBadge.Show();
levelText.Text = user.Statistics.Level.Current.ToString();
scoreText.Add(createScoreText("Ranked Score"));
scoreNumberText.Add(createScoreNumberText(user.Statistics.RankedScore.ToString(@"#,0")));
scoreText.Add(createScoreText("Accuracy"));
scoreNumberText.Add(createScoreNumberText($"{user.Statistics.Accuracy}%"));
scoreText.Add(createScoreText("Play Count"));
scoreNumberText.Add(createScoreNumberText(user.Statistics.PlayCount.ToString(@"#,0")));
scoreText.Add(createScoreText("Total Score"));
scoreNumberText.Add(createScoreNumberText(user.Statistics.TotalScore.ToString(@"#,0")));
scoreText.Add(createScoreText("Total Hits"));
scoreNumberText.Add(createScoreNumberText(user.Statistics.TotalHits.ToString(@"#,0")));
scoreText.Add(createScoreText("Max Combo"));
scoreNumberText.Add(createScoreNumberText(user.Statistics.MaxCombo.ToString(@"#,0")));
scoreText.Add(createScoreText("Replay Watched by Others"));
scoreNumberText.Add(createScoreNumberText(user.Statistics.ReplayWatched.ToString(@"#,0")));
gradeSS.DisplayCount = user.Statistics.GradesCount.SS;
gradeSS.Show();
gradeS.DisplayCount = user.Statistics.GradesCount.S;
gradeS.Show();
gradeA.DisplayCount = user.Statistics.GradesCount.A;
gradeA.Show();
gradeSPlus.DisplayCount = 0;
gradeSSPlus.DisplayCount = 0;
chartContainer.Add(new RankChart(user) { RelativeSizeAxes = Axes.Both });
}
}
// These could be local functions when C# 7 enabled
private OsuSpriteText createScoreText(string text) => new OsuSpriteText
{
TextSize = 14,
Text = text
};
private OsuSpriteText createScoreNumberText(string text) => new OsuSpriteText
{
TextSize = 14,
Font = @"Exo2.0-Bold",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Text = text
};
private void tryAddInfoRightLine(FontAwesome icon, string str)
{
if (string.IsNullOrEmpty(str)) return;
infoTextRight.AddIcon(icon);
infoTextRight.AddText(" " + str);
infoTextRight.NewLine();
}
private class GradeBadge : Container
{
private const float width = 50;
private readonly string grade;
private readonly Sprite badge;
private readonly SpriteText numberText;
public int DisplayCount
{
set { numberText.Text = value.ToString(@"#,0"); }
}
public GradeBadge(string grade)
{
this.grade = grade;
Width = width;
Height = 41;
Add(badge = new Sprite
{
Width = width,
Height = 26
});
Add(numberText = new SpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
TextSize = 14,
Font = @"Exo2.0-Bold"
});
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
badge.Texture = textures.Get($"Grades/{grade}");
}
}
}
}

View File

@ -0,0 +1,74 @@
// 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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using OpenTK.Graphics;
namespace osu.Game.Overlays.Profile
{
public abstract class ProfileSection : FillFlowContainer
{
public abstract string Title { get; }
public abstract string Identifier { get; }
private readonly FillFlowContainer content;
protected override Container<Drawable> Content => content;
protected ProfileSection()
{
Direction = FillDirection.Vertical;
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
InternalChildren = new Drawable[]
{
new OsuSpriteText
{
Text = Title,
TextSize = 20,
Font = @"Exo2.0-RegularItalic",
Margin = new MarginPadding
{
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN,
Vertical = 10
}
},
content = new FillFlowContainer
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding
{
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN,
Bottom = 20
}
},
new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Colour = OsuColour.Gray(34),
EdgeSmoothness = new Vector2(1)
}
};
// placeholder
Add(new OsuSpriteText
{
Text = @"coming soon!",
TextSize = 16,
Font = @"Exo2.0-Medium",
Colour = Color4.Gray,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Top = 100, Bottom = 100 }
});
}
}
}

View File

@ -0,0 +1,177 @@
// 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 OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile
{
public class RankChart : Container
{
private readonly SpriteText rankText, performanceText, relativeText;
private readonly RankChartLineGraph graph;
private readonly int[] ranks;
private const float primary_textsize = 25, secondary_textsize = 13, padding = 10;
private readonly User user;
public RankChart(User user)
{
this.user = user;
Padding = new MarginPadding { Vertical = padding };
Children = new Drawable[]
{
rankText = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = @"Exo2.0-RegularItalic",
TextSize = primary_textsize
},
relativeText = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = @"Exo2.0-RegularItalic",
Y = 25,
TextSize = secondary_textsize
},
performanceText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Font = @"Exo2.0-RegularItalic",
TextSize = secondary_textsize
},
graph = new RankChartLineGraph
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
Y = -secondary_textsize,
DefaultValueCount = 90,
BallRelease = updateRankTexts,
BallMove = showHistoryRankTexts
}
};
ranks = user.AllRankHistories?.Osu?.Data ?? new[] { user.Statistics.Rank };
}
private void updateRankTexts()
{
rankText.Text = user.Statistics.Rank > 0 ? $"#{user.Statistics.Rank:#,0}" : "no rank";
performanceText.Text = user.Statistics.PP != null ? $"{user.Statistics.PP:#,0}pp" : string.Empty;
relativeText.Text = $"{user.Country?.FullName} #{user.CountryRank:#,0}";
}
private void showHistoryRankTexts(int dayIndex)
{
rankText.Text = ranks[dayIndex] > 0 ? $"#{ranks[dayIndex]:#,0}" : "no rank";
relativeText.Text = dayIndex == ranks.Length ? "Now" : $"{ranks.Length - dayIndex} days ago";
//plural should be handled in a general way
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
graph.Colour = colours.Yellow;
if (user.Statistics.Rank > 0)
{
// use logarithmic coordinates
graph.Values = ranks.Select(x => -(float)Math.Log(x));
graph.ResetBall();
}
}
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
{
if ((invalidation & Invalidation.DrawSize) != 0)
{
graph.Height = DrawHeight - padding * 2 - primary_textsize - secondary_textsize * 2;
}
return base.Invalidate(invalidation, source, shallPropagate);
}
private class RankChartLineGraph : LineGraph
{
private readonly CircularContainer ball;
private bool ballShown;
private const double transform_duration = 100;
public Action<int> BallMove;
public Action BallRelease;
public RankChartLineGraph()
{
Add(ball = new CircularContainer
{
Size = new Vector2(8),
Masking = true,
Origin = Anchor.Centre,
Alpha = 0,
RelativePositionAxes = Axes.Both,
Children = new Drawable[]
{
new Box { RelativeSizeAxes = Axes.Both }
}
});
}
public void ResetBall()
{
ball.MoveTo(new Vector2(1, GetYPosition(Values.Last())), ballShown ? transform_duration : 0, EasingTypes.OutQuint);
ball.Show();
BallRelease();
ballShown = true;
}
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, EasingTypes.OutQuint);
BallMove(i);
}
}
}
return base.OnMouseMove(state);
}
protected override void OnHoverLost(InputState state)
{
if (ballShown)
ResetBall();
base.OnHoverLost(state);
}
}
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class AboutSection : ProfileSection
{
public override string Title => "me!";
public override string Identifier => "me";
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class BeatmapsSection : ProfileSection
{
public override string Title => "Beatmaps";
public override string Identifier => "beatmaps";
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class HistoricalSection : ProfileSection
{
public override string Title => "Historical";
public override string Identifier => "historical";
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class KudosuSection : ProfileSection
{
public override string Title => "Kudosu!";
public override string Identifier => "kudosu";
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class MedalsSection : ProfileSection
{
public override string Title => "Medals";
public override string Identifier => "medals";
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class RanksSection : ProfileSection
{
public override string Title => "Ranks";
public override string Identifier => "top_ranks";
}
}

View File

@ -0,0 +1,12 @@
// 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.Overlays.Profile.Sections
{
public class RecentSection : ProfileSection
{
public override string Title => "Recent";
public override string Identifier => "recent_activities";
}
}

View File

@ -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.Framework.Graphics.Containers;
@ -31,6 +32,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
private UserPanel panel;
private UserDropdown dropdown;
/// <summary>
/// Called to request a hide of a parent displaying this container.
/// </summary>
public Action RequestHide;
public override RectangleF BoundingBox => bounding ? base.BoundingBox : RectangleF.Empty;
public bool Bounding
@ -58,6 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
{
this.inputManager = inputManager;
this.colours = colours;
api?.Register(this);
}
@ -129,7 +136,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
},
},
},
panel = new UserPanel(api.LocalUser.Value) { RelativeSizeAxes = Axes.X },
panel = new UserPanel(api.LocalUser.Value)
{
RelativeSizeAxes = Axes.X,
Action = RequestHide
},
dropdown = new UserDropdown { RelativeSizeAxes = Axes.X },
},
},

View File

@ -86,7 +86,7 @@ namespace osu.Game.Overlays
},
Exit = Hide,
},
Sections = sections,
Children = sections,
Footer = new SettingsFooter()
},
sidebar = new Sidebar
@ -163,13 +163,12 @@ namespace osu.Game.Overlays
sectionsContainer.Padding = new MarginPadding { Top = getToolbarHeight() };
}
private class SettingsSectionsContainer : SectionsContainer
private class SettingsSectionsContainer : SectionsContainer<SettingsSection>
{
public SearchContainer SearchContainer;
private readonly Box headerBackground;
public SearchContainer<SettingsSection> SearchContainer;
protected override Container<Drawable> CreateScrollContentContainer()
=> SearchContainer = new SearchContainer
protected override FlowContainer<SettingsSection> CreateScrollContentContainer()
=> SearchContainer = new SearchContainer<SettingsSection>
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
@ -178,12 +177,11 @@ namespace osu.Game.Overlays
public SettingsSectionsContainer()
{
ScrollContainer.ScrollbarVisible = false;
Add(headerBackground = new Box
HeaderBackground = new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.X
});
RelativeSizeAxes = Axes.Both
};
}
protected override void UpdateAfterChildren()
@ -191,9 +189,7 @@ namespace osu.Game.Overlays
base.UpdateAfterChildren();
// no null check because the usage of this class is strict
headerBackground.Height = ExpandableHeader.LayoutSize.Y + FixedHeader.LayoutSize.Y;
headerBackground.Y = ExpandableHeader.Y;
headerBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f;
HeaderBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y * 0.5f;
}
}
}

View File

@ -0,0 +1,224 @@
// 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.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.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Users;
namespace osu.Game.Overlays
{
public class UserProfileOverlay : WaveOverlayContainer
{
private ProfileSection lastSection;
private ProfileSection[] sections;
private GetUserRequest userReq;
private APIAccess api;
private ProfileHeader header;
private SectionsContainer<ProfileSection> sectionsContainer;
private ProfileTabControl tabs;
public const float CONTENT_X_MARGIN = 50;
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
protected override bool OnClick(InputState state)
{
State = Visibility.Hidden;
return true;
}
public UserProfileOverlay()
{
FirstWaveColour = OsuColour.Gray(0.4f);
SecondWaveColour = OsuColour.Gray(0.3f);
ThirdWaveColour = OsuColour.Gray(0.2f);
FourthWaveColour = OsuColour.Gray(0.1f);
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
Width = 0.85f;
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0),
Type = EdgeEffectType.Shadow,
Radius = 10
};
}
[BackgroundDependencyLoader]
private void load(APIAccess api)
{
this.api = api;
}
protected override void PopIn()
{
base.PopIn();
FadeEdgeEffectTo(0.5f, APPEAR_DURATION, EasingTypes.In);
}
protected override void PopOut()
{
base.PopOut();
FadeEdgeEffectTo(0, DISAPPEAR_DURATION, EasingTypes.Out);
}
public void ShowUser(User user, bool fetchOnline = true)
{
userReq?.Cancel();
Clear();
lastSection = null;
sections = new ProfileSection[]
{
new AboutSection(),
new RecentSection(),
new RanksSection(),
new MedalsSection(),
new HistoricalSection(),
new BeatmapsSection(),
new KudosuSection()
};
tabs = new ProfileTabControl
{
RelativeSizeAxes = Axes.X,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Height = 30
};
Add(new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.2f)
});
header = new ProfileHeader(user);
Add(sectionsContainer = new SectionsContainer<ProfileSection>
{
RelativeSizeAxes = Axes.Both,
ExpandableHeader = header,
FixedHeader = tabs,
HeaderBackground = new Box
{
Colour = OsuColour.Gray(34),
RelativeSizeAxes = Axes.Both
}
});
sectionsContainer.SelectedSection.ValueChanged += s =>
{
if (lastSection != s)
{
lastSection = s;
tabs.Current.Value = lastSection;
}
};
tabs.Current.ValueChanged += s =>
{
if (lastSection == null)
{
lastSection = sectionsContainer.Children.FirstOrDefault();
if (lastSection != null)
tabs.Current.Value = lastSection;
return;
}
if (lastSection != s)
{
lastSection = s;
sectionsContainer.ScrollTo(lastSection);
}
};
if (fetchOnline)
{
userReq = new GetUserRequest(user.Id);
userReq.Success += userLoadComplete;
api.Queue(userReq);
}
else
{
userReq = null;
userLoadComplete(user);
}
Show();
}
private void userLoadComplete(User user)
{
header.User = user;
for (int i = 0; i < user.ProfileOrder.Length; i++)
{
string id = user.ProfileOrder[i];
var sec = sections.FirstOrDefault(s => s.Identifier == id);
if (sec != null)
{
sec.Depth = -i;
sectionsContainer.Add(sec);
tabs.AddItem(sec);
}
}
}
private class ProfileTabControl : PageTabControl<ProfileSection>
{
private readonly Box bottom;
public ProfileTabControl()
{
TabContainer.RelativeSizeAxes &= ~Axes.X;
TabContainer.AutoSizeAxes |= Axes.X;
TabContainer.Anchor |= Anchor.x1;
TabContainer.Origin |= Anchor.x1;
Add(bottom = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
EdgeSmoothness = new Vector2(1)
});
}
protected override TabItem<ProfileSection> CreateTabItem(ProfileSection value) => new ProfileTabItem(value);
protected override Dropdown<ProfileSection> CreateDropdown() => null;
private class ProfileTabItem : PageTabItem
{
public ProfileTabItem(ProfileSection value) : base(value)
{
Text.Text = value.Title;
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
bottom.Colour = colours.Yellow;
}
}
}
}

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Textures;
using OpenTK;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Backgrounds;
@ -26,11 +27,12 @@ namespace osu.Game.Screens.Backgrounds
{
if (beatmap == value && beatmap != null)
return;
beatmap = value;
Schedule(() =>
{
var newBackground = beatmap == null ? new Background(@"Backgrounds/bg1") : new BeatmapBackground(beatmap);
var newBackground = new BeatmapBackground(beatmap);
LoadComponentAsync(newBackground, delegate
{
@ -51,7 +53,7 @@ namespace osu.Game.Screens.Backgrounds
}
}
public BackgroundScreenBeatmap(WorkingBeatmap beatmap)
public BackgroundScreenBeatmap(WorkingBeatmap beatmap = null)
{
Beatmap = beatmap;
}
@ -80,9 +82,9 @@ namespace osu.Game.Screens.Backgrounds
}
[BackgroundDependencyLoader]
private void load()
private void load(TextureStore textures)
{
Sprite.Texture = beatmap?.Background;
Sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg1");
}
}
}

View File

@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit
protected override void OnResuming(Screen last)
{
Beatmap?.Track?.Stop();
Beatmap.Value.Track?.Stop();
base.OnResuming(last);
}
@ -26,13 +26,13 @@ namespace osu.Game.Screens.Edit
{
base.OnEntering(last);
Background.FadeColour(Color4.DarkGray, 500);
Beatmap?.Track?.Stop();
Beatmap.Value.Track?.Stop();
}
protected override bool OnExiting(Screen next)
{
Background.FadeColour(Color4.White, 500);
Beatmap?.Track?.Start();
Beatmap.Value.Track?.Start();
return base.OnExiting(next);
}
}

View File

@ -103,9 +103,9 @@ namespace osu.Game.Screens.Menu
}
beatmaps.GetChildren(setInfo);
Beatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
Beatmap.Value = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]);
track = Beatmap.Track;
track = Beatmap.Value.Track;
trackManager.SetExclusive(track);
welcome = audio.Sample.Get(@"welcome");

View File

@ -4,7 +4,6 @@
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.ES30;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Batches;
@ -16,6 +15,7 @@ using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using System;
using osu.Framework.Allocation;
namespace osu.Game.Screens.Menu
{
@ -76,23 +76,24 @@ namespace osu.Game.Screens.Menu
BlendingMode = BlendingMode.Additive;
}
[BackgroundDependencyLoader(true)]
private void load(ShaderManager shaders, OsuGame game)
[BackgroundDependencyLoader]
private void load(ShaderManager shaders, OsuGameBase game)
{
if (game?.Beatmap != null)
beatmap.BindTo(game.Beatmap);
shader = shaders?.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
beatmap.BindTo(game.Beatmap);
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED);
}
private void updateAmplitudes()
{
float[] temporalAmplitudes = beatmap.Value?.Track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256];
var track = beatmap.Value.Track;
var effect = beatmap.Value?.Beatmap.ControlPointInfo.EffectPointAt(beatmap.Value.Track?.CurrentTime ?? Time.Current);
float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes ?? new float[256];
var effect = beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current);
for (int i = 0; i < bars_per_visualiser; i++)
{
if (beatmap?.Value?.Track?.IsRunning ?? false)
if (track?.IsRunning ?? false)
{
float targetAmplitude = temporalAmplitudes[(i + indexOffset) % bars_per_visualiser] * (effect?.KiaiMode == true ? 1 : 0.5f);
if (targetAmplitude > frequencyAmplitudes[i])

View File

@ -28,6 +28,8 @@ namespace osu.Game.Screens.Menu
private readonly BackgroundScreenDefault background;
private Screen songSelect;
private readonly MenuSideFlashes sideFlashes;
protected override BackgroundScreen CreateBackground() => background;
public MainMenu()
@ -49,10 +51,10 @@ namespace osu.Game.Screens.Menu
OnSolo = delegate { Push(consumeSongSelect()); },
OnMulti = delegate { Push(new Lobby()); },
OnExit = delegate { Exit(); },
},
new MenuSideFlashes(),
}
}
}
},
sideFlashes = new MenuSideFlashes(),
};
}
@ -67,12 +69,6 @@ namespace osu.Game.Screens.Menu
preloadSongSelect();
}
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
{
base.OnBeatmapChanged(beatmap);
background.Next();
}
private void preloadSongSelect()
{
if (songSelect == null)
@ -90,16 +86,30 @@ namespace osu.Game.Screens.Menu
{
base.OnEntering(last);
buttons.FadeInFromZero(500);
if (last is Intro && Beatmap != null)
var track = Beatmap.Value.Track;
var metadata = Beatmap.Value.Metadata;
if (last is Intro && track != null)
{
if (!Beatmap.Track.IsRunning)
if (!track.IsRunning)
{
Beatmap.Track.Seek(Beatmap.Metadata.PreviewTime);
if (Beatmap.Metadata.PreviewTime == -1)
Beatmap.Track.Seek(Beatmap.Track.Length * 0.4f);
Beatmap.Track.Start();
track.Seek(metadata.PreviewTime);
if (metadata.PreviewTime == -1)
track.Seek(track.Length * 0.4f);
track.Start();
}
}
Beatmap.ValueChanged += beatmap_ValueChanged;
}
private void beatmap_ValueChanged(WorkingBeatmap newValue)
{
if (!IsCurrentScreen)
return;
background.Next();
}
protected override void OnSuspending(Screen next)
@ -112,6 +122,8 @@ namespace osu.Game.Screens.Menu
Content.FadeOut(length, EasingTypes.InSine);
Content.MoveTo(new Vector2(-800, 0), length, EasingTypes.InSine);
sideFlashes.FadeOut(length / 4, EasingTypes.OutQuint);
}
protected override void OnResuming(Screen last)
@ -129,6 +141,8 @@ namespace osu.Game.Screens.Menu
Content.FadeIn(length, EasingTypes.OutQuint);
Content.MoveTo(new Vector2(0, 0), length, EasingTypes.OutQuint);
sideFlashes.FadeIn(length / 4, EasingTypes.InQuint);
}
protected override bool OnExiting(Screen next)

View File

@ -275,7 +275,7 @@ namespace osu.Game.Screens.Menu
const float scale_adjust_cutoff = 0.4f;
const float velocity_adjust_cutoff = 0.98f;
var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value?.Track?.CurrentAmplitudes.Maximum ?? 0 : 0;
var maxAmplitude = lastBeatIndex >= 0 ? Beatmap.Value.Track?.CurrentAmplitudes.Maximum ?? 0 : 0;
logoAmplitudeContainer.ScaleTo(1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 75, EasingTypes.OutQuint);
if (maxAmplitude > velocity_adjust_cutoff)

View File

@ -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.Configuration;
using osu.Framework.Screens;
@ -35,34 +36,31 @@ namespace osu.Game.Screens
/// </summary>
internal virtual bool AllowBeatmapRulesetChange => true;
private readonly Bindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
protected readonly Bindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
public WorkingBeatmap InitialBeatmap
{
set
{
if (IsLoaded) throw new InvalidOperationException($"Cannot set {nameof(InitialBeatmap)} post-load.");
Beatmap.Value = value;
}
}
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private SampleChannel sampleExit;
public WorkingBeatmap Beatmap
{
get
{
return beatmap.Value;
}
set
{
beatmap.Value = value;
}
}
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuGameBase game, OsuGame osuGame, AudioManager audio)
{
if (game != null)
{
//if we were given a beatmap at ctor time, we want to pass this on to the game-wide beatmap.
var localMap = beatmap.Value;
beatmap.BindTo(game.Beatmap);
var localMap = Beatmap.Value;
Beatmap.BindTo(game.Beatmap);
if (localMap != null)
beatmap.Value = localMap;
Beatmap.Value = localMap;
}
if (osuGame != null)
@ -71,20 +69,6 @@ namespace osu.Game.Screens
sampleExit = audio.Sample.Get(@"UI/melodic-1");
}
protected override void LoadComplete()
{
base.LoadComplete();
beatmap.ValueChanged += OnBeatmapChanged;
}
/// <summary>
/// The global Beatmap was changed.
/// </summary>
protected virtual void OnBeatmapChanged(WorkingBeatmap beatmap)
{
}
protected override void Update()
{
if (!IsCurrentScreen) return;
@ -94,7 +78,7 @@ namespace osu.Game.Screens
// we only want to apply these restrictions when we are inside a screen stack.
// the use case for not applying is in visual/unit tests.
ruleset.Disabled = !AllowBeatmapRulesetChange;
beatmap.Disabled = !AllowBeatmapRulesetChange;
Beatmap.Disabled = !AllowBeatmapRulesetChange;
}
}
@ -110,8 +94,6 @@ namespace osu.Game.Screens
BackgroundScreen bg = CreateBackground();
OnBeatmapChanged(Beatmap);
if (lastOsu?.Background != null)
{
if (bg == null || lastOsu.Background.Equals(bg))
@ -156,11 +138,7 @@ namespace osu.Game.Screens
if (base.OnExiting(next))
return true;
// while this is not necessary as we are constructing our own bindable, there are cases where
// the GC doesn't run as fast as expected and this is triggered post-exit.
// added to resolve https://github.com/ppy/osu/issues/829
beatmap.ValueChanged -= OnBeatmapChanged;
Beatmap.UnbindAll();
return false;
}
}

View File

@ -69,6 +69,8 @@ namespace osu.Game.Screens.Play
private HUDOverlay hudOverlay;
private FailOverlay failOverlay;
private bool loadedSuccessfully => HitRenderer?.Objects.Any() == true;
[BackgroundDependencyLoader(permitNulls: true)]
private void load(AudioManager audio, BeatmapDatabase beatmaps, OsuConfigManager config, OsuGame osu)
{
@ -81,24 +83,25 @@ namespace osu.Game.Screens.Play
try
{
if (Beatmap == null)
Beatmap = beatmaps.GetWorkingBeatmap(BeatmapInfo, withStoryboard: true);
if (!Beatmap.Value.WithStoryboard)
// we need to ensure the storyboard is loaded.
Beatmap.Value = beatmaps.GetWorkingBeatmap(BeatmapInfo, withStoryboard: true);
if (Beatmap?.Beatmap == null)
if (Beatmap.Value.Beatmap == null)
throw new InvalidOperationException("Beatmap was not loaded");
ruleset = osu?.Ruleset.Value ?? Beatmap.BeatmapInfo.Ruleset;
ruleset = osu?.Ruleset.Value ?? Beatmap.Value.BeatmapInfo.Ruleset;
rulesetInstance = ruleset.CreateInstance();
try
{
HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.BeatmapInfo.Ruleset.ID);
HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, ruleset.ID == Beatmap.Value.BeatmapInfo.Ruleset.ID);
}
catch (BeatmapInvalidForRulesetException)
{
// we may fail to create a HitRenderer if the beatmap cannot be loaded with the user's preferred ruleset
// let's try again forcing the beatmap's ruleset.
ruleset = Beatmap.BeatmapInfo.Ruleset;
ruleset = Beatmap.Value.BeatmapInfo.Ruleset;
rulesetInstance = ruleset.CreateInstance();
HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap, true);
}
@ -115,7 +118,7 @@ namespace osu.Game.Screens.Play
return;
}
Track track = Beatmap.Track;
Track track = Beatmap.Value.Track;
if (track != null)
{
@ -128,7 +131,7 @@ namespace osu.Game.Screens.Play
decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
var firstObjectTime = HitRenderer.Objects.First().StartTime;
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.BeatmapInfo.AudioLeadIn)));
decoupledClock.Seek(Math.Min(0, firstObjectTime - Math.Max(Beatmap.Value.Beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, Beatmap.Value.BeatmapInfo.AudioLeadIn)));
decoupledClock.ProcessFrame();
offsetClock = new FramedOffsetClock(decoupledClock);
@ -141,7 +144,7 @@ namespace osu.Game.Screens.Play
{
adjustableSourceClock.Reset();
foreach (var mod in Beatmap.Mods.Value.OfType<IApplicableToClock>())
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
mod.ApplyToClock(adjustableSourceClock);
decoupledClock.ChangeSource(adjustableSourceClock);
@ -209,7 +212,7 @@ namespace osu.Game.Screens.Play
hudOverlay.Progress.AllowSeeking = HitRenderer.HasReplayLoaded;
hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos);
hudOverlay.ModDisplay.Current.BindTo(Beatmap.Mods);
hudOverlay.ModDisplay.Current.BindTo(Beatmap.Value.Mods);
//bind HitRenderer to ScoreProcessor and ourselves (for a pass situation)
HitRenderer.OnAllJudged += onCompletion;
@ -242,7 +245,7 @@ namespace osu.Game.Screens.Play
{
var score = new Score
{
Beatmap = Beatmap.BeatmapInfo,
Beatmap = Beatmap.Value.BeatmapInfo,
Ruleset = ruleset
};
scoreProcessor.PopulateScore(score);
@ -265,6 +268,9 @@ namespace osu.Game.Screens.Play
{
base.OnEntering(last);
if (!loadedSuccessfully)
return;
(Background as BackgroundScreenBeatmap)?.BlurTo(Vector2.Zero, 1500, EasingTypes.OutQuint);
Background?.FadeTo(1 - (float)dimLevel, 1500, EasingTypes.OutQuint);
@ -304,7 +310,11 @@ namespace osu.Game.Screens.Play
return base.OnExiting(next);
}
pauseContainer.Pause();
if (loadedSuccessfully)
{
pauseContainer.Pause();
}
return true;
}

View File

@ -35,7 +35,8 @@ namespace osu.Game.Screens.Play
{
this.player = player;
player.RestartRequested = () => {
player.RestartRequested = () =>
{
showOverlays = false;
ValidForResume = true;
};
@ -74,7 +75,6 @@ namespace osu.Game.Screens.Play
{
RestartCount = player.RestartCount + 1,
RestartRequested = player.RestartRequested,
Beatmap = player.Beatmap,
});
Delay(400);

View File

@ -12,7 +12,6 @@ using System.Linq;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Screens.Play
{
public class SongProgress : OverlayContainer
@ -50,6 +49,9 @@ namespace osu.Game.Screens.Play
info.StartTime = firstHitTime;
info.EndTime = lastHitTime;
bar.StartTime = firstHitTime;
bar.EndTime = lastHitTime;
}
}
@ -89,10 +91,7 @@ namespace osu.Game.Screens.Play
Alpha = 0,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
SeekRequested = delegate (float position)
{
OnSeek?.Invoke(firstHitTime + position * (lastHitTime - firstHitTime));
},
OnSeek = position => OnSeek?.Invoke(position),
},
};
}
@ -144,11 +143,12 @@ namespace osu.Game.Screens.Play
if (objects == null)
return;
double progress = ((audioClock?.CurrentTime ?? Time.Current) - firstHitTime) / (lastHitTime - firstHitTime);
double position = audioClock?.CurrentTime ?? Time.Current;
double progress = (position - firstHitTime) / (lastHitTime - firstHitTime);
if (progress < 1)
{
bar.UpdatePosition((float)progress);
bar.CurrentTime = position;
graph.Progress = (int)(graph.ColumnCount * progress);
}
}

View File

@ -1,74 +1,117 @@
// 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 OpenTK;
using OpenTK.Graphics;
using osu.Game.Overlays;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Screens.Play
{
public class SongProgressBar : DragBar
public class SongProgressBar : SliderBar<double>
{
public Action<double> OnSeek;
private readonly Box fill;
private readonly Container handleBase;
public Color4 FillColour
{
get { return Fill.Colour; }
set { Fill.Colour = value; }
set { fill.Colour = value; }
}
public double StartTime
{
set { CurrentNumber.MinValue = value; }
}
public double EndTime
{
set { CurrentNumber.MaxValue = value; }
}
public double CurrentTime
{
set { CurrentNumber.Value = value; }
}
public SongProgressBar(float barHeight, float handleBarHeight, Vector2 handleSize)
{
CurrentNumber.MinValue = 0;
CurrentNumber.MaxValue = 1;
RelativeSizeAxes = Axes.X;
Height = barHeight + handleBarHeight + handleSize.Y;
Fill.RelativeSizeAxes = Axes.X;
Fill.Height = barHeight;
Add(new Box
Children = new Drawable[]
{
Name = "Background",
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = barHeight,
Colour = Color4.Black,
Alpha = 0.5f,
Depth = 1
});
Fill.Add(new Container
{
Origin = Anchor.BottomRight,
Anchor = Anchor.BottomRight,
Width = 2,
Height = barHeight + handleBarHeight,
Colour = Color4.White,
Position = new Vector2(2, 0),
Children = new Drawable[]
new Box
{
new Box
Name = "Background",
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = barHeight,
Colour = Color4.Black,
Alpha = 0.5f,
Depth = 1,
},
fill = new Box
{
Name = "Fill",
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Height = barHeight,
},
handleBase = new Container
{
Name = "HandleBar container",
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Width = 2,
Height = barHeight + handleBarHeight,
Colour = Color4.White,
Position = new Vector2(2, 0),
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
},
new Container
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.TopCentre,
Size = handleSize,
CornerRadius = 5,
Masking = true,
Children = new Drawable[]
new Box
{
new Box
Name = "HandleBar box",
RelativeSizeAxes = Axes.Both,
},
new Container
{
Name = "Handle container",
Origin = Anchor.BottomCentre,
Anchor = Anchor.TopCentre,
Size = handleSize,
CornerRadius = 5,
Masking = true,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.White
new Box
{
Name = "Handle box",
RelativeSizeAxes = Axes.Both,
Colour = Color4.White
}
}
}
}
}
});
};
}
protected override void UpdateValue(float value)
{
var xFill = value * UsableWidth;
fill.Width = xFill;
handleBase.MoveToX(xFill);
}
protected override void OnUserChange() => OnSeek?.Invoke(Current);
}
}

View File

@ -165,7 +165,7 @@ namespace osu.Game.Screens.Ranking
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f,
Texture = Beatmap?.Background,
Texture = Beatmap.Value.Background,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fill

View File

@ -137,6 +137,7 @@ namespace osu.Game.Screens.Select
{
selectedGroup = null;
selectedPanel = null;
SelectionChanged?.Invoke(null);
return;
}
@ -284,6 +285,7 @@ namespace osu.Game.Screens.Select
private void load(BeatmapDatabase database, OsuConfigManager config)
{
this.database = database;
randomType = config.GetBindable<SelectionRandomType>(OsuSetting.SelectionRandomType);
}

View File

@ -45,6 +45,12 @@ namespace osu.Game.Screens.Select
};
}
protected override void LoadComplete()
{
base.LoadComplete();
AlwaysPresent = true;
}
protected override bool HideOnEscape => false;
protected override bool BlockPassThroughMouse => false;
@ -63,18 +69,6 @@ namespace osu.Game.Screens.Select
public void UpdateBeatmap(WorkingBeatmap beatmap)
{
if (beatmap?.BeatmapInfo == null)
{
State = Visibility.Hidden;
beatmapInfoContainer?.FadeOut(250);
beatmapInfoContainer?.Expire();
beatmapInfoContainer = null;
return;
}
State = Visibility.Visible;
AlwaysPresent = true;
var lastContainer = beatmapInfoContainer;
float newDepth = lastContainer?.Depth + 1 ?? 0;

View File

@ -51,28 +51,27 @@ namespace osu.Game.Screens.Select
ValidForResume = false;
Push(new Editor());
}, Key.Number3);
Beatmap.ValueChanged += beatmap_ValueChanged;
}
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
private void beatmap_ValueChanged(WorkingBeatmap beatmap)
{
beatmap?.Mods.BindTo(modSelect.SelectedMods);
if (!IsCurrentScreen) return;
if (Beatmap?.Track != null)
Beatmap.Track.Looping = false;
beatmap.Mods.BindTo(modSelect.SelectedMods);
beatmapDetails.Beatmap = beatmap;
if (beatmap?.Track != null)
if (beatmap.Track != null)
beatmap.Track.Looping = true;
base.OnBeatmapChanged(beatmap);
}
protected override void OnResuming(Screen last)
{
player = null;
Beatmap.Track.Looping = true;
Beatmap.Value.Track.Looping = true;
base.OnResuming(last);
}
@ -95,8 +94,8 @@ namespace osu.Game.Screens.Select
if (base.OnExiting(next))
return true;
if (Beatmap?.Track != null)
Beatmap.Track.Looping = false;
if (Beatmap.Value.Track != null)
Beatmap.Value.Track.Looping = false;
return false;
}
@ -105,12 +104,9 @@ namespace osu.Game.Screens.Select
{
if (player != null) return;
Beatmap.Track.Looping = false;
Beatmap.Value.Track.Looping = false;
LoadComponentAsync(player = new PlayerLoader(new Player
{
Beatmap = Beatmap, //eagerly set this so it's present before push.
}), l => Push(player));
LoadComponentAsync(player = new PlayerLoader(new Player()), l => Push(player));
}
}
}

View File

@ -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.Threading;
using OpenTK;
using OpenTK.Input;
@ -28,7 +29,7 @@ namespace osu.Game.Screens.Select
{
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private BeatmapDatabase database;
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap);
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap();
private readonly BeatmapCarousel carousel;
private TrackManager trackManager;
@ -107,8 +108,9 @@ namespace osu.Game.Screens.Select
Size = new Vector2(carousel_width, 1),
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
SelectionChanged = selectionChanged,
StartRequested = raiseSelect
SelectionChanged = carouselSelectionChanged,
BeatmapsChanged = carouselBeatmapsLoaded,
StartRequested = carouselRaisedStart
});
Add(FilterControl = new FilterControl
{
@ -127,7 +129,6 @@ namespace osu.Game.Screens.Select
Top = left_area_padding,
Right = left_area_padding,
},
X = -50,
});
if (ShowFooter)
@ -146,7 +147,7 @@ namespace osu.Game.Screens.Select
Add(Footer = new Footer
{
OnBack = Exit,
OnStart = raiseSelect,
OnStart = carouselRaisedStart,
});
FooterPanels.Add(BeatmapOptions = new BeatmapOptionsOverlay());
@ -181,34 +182,79 @@ namespace osu.Game.Screens.Select
initialAddSetsTask = new CancellationTokenSource();
carousel.BeatmapsChanged = beatmapsLoaded;
carousel.Beatmaps = database.GetAllWithChildren<BeatmapSetInfo>(b => !b.DeletePending);
Beatmap.ValueChanged += beatmap_ValueChanged;
}
private void beatmapsLoaded()
private void carouselBeatmapsLoaded()
{
if (Beatmap != null)
carousel.SelectBeatmap(Beatmap.BeatmapInfo, false);
if (Beatmap.Value != null && !Beatmap.Value.BeatmapSetInfo.DeletePending)
carousel.SelectBeatmap(Beatmap.Value.BeatmapInfo, false);
else
carousel.SelectNext();
}
private void raiseSelect()
private void carouselRaisedStart()
{
var pendingSelection = selectionChangedDebounce;
selectionChangedDebounce = null;
if (pendingSelection?.Completed == false)
{
pendingSelection?.RunTask();
pendingSelection?.Cancel(); // cancel the already scheduled task.
pendingSelection.RunTask();
pendingSelection.Cancel(); // cancel the already scheduled task.
}
if (Beatmap == null) return;
OnSelected();
}
private ScheduledDelegate selectionChangedDebounce;
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo beatmapNoDebounce;
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
private void carouselSelectionChanged(BeatmapInfo beatmap)
{
Action performLoad = delegate
{
bool preview = beatmap?.BeatmapSetInfoID != Beatmap.Value.BeatmapInfo.BeatmapSetInfoID;
Beatmap.Value = database.GetWorkingBeatmap(beatmap, Beatmap);
ensurePlayingSelected(preview);
changeBackground(Beatmap.Value);
};
if (beatmap == null)
{
if (!Beatmap.IsDefault)
performLoad();
}
else
{
selectionChangedDebounce?.Cancel();
if (beatmap.Equals(beatmapNoDebounce))
return;
if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID)
sampleChangeDifficulty.Play();
else
sampleChangeBeatmap.Play();
beatmapNoDebounce = beatmap;
if (beatmap == Beatmap.Value.BeatmapInfo)
performLoad();
else
selectionChangedDebounce = Scheduler.AddDelayed(performLoad, 100);
}
}
private void triggerRandom(UserInputManager input)
{
if (input.CurrentState.Keyboard.ShiftPressed)
@ -231,23 +277,27 @@ namespace osu.Game.Screens.Select
protected override void OnEntering(Screen last)
{
base.OnEntering(last);
ensurePlayingSelected();
changeBackground(Beatmap);
selectionChangeNoBounce = Beatmap?.BeatmapInfo;
Content.FadeInFromZero(250);
beatmapInfoWedge.State = Visibility.Visible;
FilterControl.Activate();
}
private void beatmap_ValueChanged(WorkingBeatmap beatmap)
{
if (!IsCurrentScreen) return;
carousel.SelectBeatmap(beatmap?.BeatmapInfo);
}
protected override void OnResuming(Screen last)
{
changeBackground(Beatmap);
ensurePlayingSelected();
if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending)
{
changeBackground(Beatmap);
ensurePlayingSelected();
}
base.OnResuming(last);
Content.FadeIn(250);
@ -300,72 +350,25 @@ namespace osu.Game.Screens.Select
backgroundModeBeatmap.FadeTo(1, 250);
}
beatmapInfoWedge.State = Visibility.Visible;
beatmapInfoWedge.UpdateBeatmap(beatmap);
}
/// <summary>
/// The global Beatmap was changed.
/// </summary>
protected override void OnBeatmapChanged(WorkingBeatmap beatmap)
{
base.OnBeatmapChanged(beatmap);
//todo: change background in selectionChanged instead; support per-difficulty backgrounds.
changeBackground(beatmap);
carousel.SelectBeatmap(beatmap?.BeatmapInfo);
}
private ScheduledDelegate selectionChangedDebounce;
// We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds.
private BeatmapInfo selectionChangeNoBounce;
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
private void selectionChanged(BeatmapInfo beatmap)
{
selectionChangedDebounce?.Cancel();
if (beatmap.Equals(Beatmap?.BeatmapInfo))
return;
bool beatmapSetChange = false;
if (beatmap.BeatmapSetInfoID == selectionChangeNoBounce?.BeatmapSetInfoID)
sampleChangeDifficulty.Play();
else
{
sampleChangeBeatmap.Play();
beatmapSetChange = true;
}
selectionChangeNoBounce = beatmap;
selectionChangedDebounce = Scheduler.AddDelayed(delegate
{
Beatmap = database.GetWorkingBeatmap(beatmap, Beatmap);
ensurePlayingSelected(beatmapSetChange);
}, 100);
}
private void ensurePlayingSelected(bool preview = false)
{
Track track = Beatmap?.Track;
Track track = Beatmap.Value.Track;
if (track != null)
{
trackManager.SetExclusive(track);
if (preview)
track.Seek(Beatmap.Metadata.PreviewTime);
track.Start();
}
trackManager.SetExclusive(track);
if (preview) track.Seek(Beatmap.Value.Metadata.PreviewTime);
track.Start();
}
private void removeBeatmapSet(BeatmapSetInfo beatmapSet)
{
carousel.RemoveBeatmap(beatmapSet);
if (carousel.SelectedBeatmap == null)
Beatmap = null;
Beatmap.SetDefault();
}
private void promptDelete()
@ -382,7 +385,7 @@ namespace osu.Game.Screens.Select
{
case Key.KeypadEnter:
case Key.Enter:
raiseSelect();
carouselRaisedStart();
return true;
case Key.Delete:
if (state.Keyboard.ShiftPressed)

View File

@ -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 Newtonsoft.Json;
using osu.Framework.Configuration;
@ -11,17 +12,20 @@ namespace osu.Game.Users
[JsonProperty(@"id")]
public long Id = 1;
[JsonProperty(@"join_date")]
public DateTimeOffset JoinDate;
[JsonProperty(@"username")]
public string Username;
[JsonProperty(@"country_code")]
public string CountryCode;
[JsonProperty(@"country")]
public Country Country;
public Bindable<UserStatus> Status = new Bindable<UserStatus>();
[JsonProperty(@"age")]
public int? Age;
public int GlobalRank;
public int CountryRank;
@ -51,5 +55,101 @@ namespace osu.Game.Users
[JsonProperty(@"id")]
public int? Id;
}
[JsonProperty(@"isAdmin")]
public bool IsAdmin;
[JsonProperty(@"isSupporter")]
public bool IsSupporter;
[JsonProperty(@"isGMT")]
public bool IsGMT;
[JsonProperty(@"isQAT")]
public bool IsQAT;
[JsonProperty(@"isBNG")]
public bool IsBNG;
[JsonProperty(@"is_active")]
public bool Active;
[JsonProperty(@"interests")]
public string Intrerests;
[JsonProperty(@"occupation")]
public string Occupation;
[JsonProperty(@"title")]
public string Title;
[JsonProperty(@"location")]
public string Location;
[JsonProperty(@"lastvisit")]
public DateTimeOffset LastVisit;
[JsonProperty(@"twitter")]
public string Twitter;
[JsonProperty(@"lastfm")]
public string Lastfm;
[JsonProperty(@"skype")]
public string Skype;
[JsonProperty(@"website")]
public string Website;
[JsonProperty(@"playstyle")]
public string[] PlayStyle;
[JsonProperty(@"playmode")]
public string PlayMode;
[JsonProperty(@"profileOrder")]
public string[] ProfileOrder;
[JsonProperty(@"kudosu")]
public KudosuCount Kudosu;
public class KudosuCount
{
[JsonProperty(@"total")]
public int Total;
[JsonProperty(@"available")]
public int Available;
}
[JsonProperty(@"defaultStatistics")]
public UserStatistics Statistics;
public class RankHistories
{
[JsonProperty(@"osu")]
public RankHistory Osu;
[JsonProperty(@"taiko")]
public RankHistory Taiko;
[JsonProperty(@"fruits")]
public RankHistory Fruits;
[JsonProperty(@"mania")]
public RankHistory Mania;
}
public class RankHistory
{
[JsonProperty(@"mode")]
public string Mode;
[JsonProperty(@"data")]
public int[] Data;
}
[JsonProperty(@"allRankHistories")]
public RankHistories AllRankHistories;
}
}

View File

@ -0,0 +1,26 @@
// 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.Sprites;
using osu.Framework.Graphics.Textures;
namespace osu.Game.Users
{
public class UserCoverBackground : Sprite
{
private readonly User user;
public UserCoverBackground(User user)
{
this.user = user;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
if (!string.IsNullOrEmpty(user.CoverUrl))
Texture = textures.Get(user.CoverUrl);
}
}
}

View File

@ -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 OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
@ -9,29 +10,31 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
namespace osu.Game.Users
{
public class UserPanel : Container
public class UserPanel : ClickableContainer
{
private readonly User user;
private const float height = 100;
private const float content_padding = 10;
private const float status_height = 30;
private OsuColour colours;
private readonly Container statusBar;
private readonly Box statusBg;
private readonly OsuSpriteText statusMessage;
public readonly Bindable<UserStatus> Status = new Bindable<UserStatus>();
public new Action Action;
public UserPanel(User user)
{
this.user = user;
Height = height - status_height;
Masking = true;
CornerRadius = 5;
@ -44,7 +47,7 @@ namespace osu.Game.Users
Children = new Drawable[]
{
new AsyncLoadWrapper(new CoverBackgroundSprite(user)
new AsyncLoadWrapper(new UserCoverBackground(user)
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
@ -162,11 +165,17 @@ namespace osu.Game.Users
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
[BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, UserProfileOverlay profile)
{
this.colours = colours;
Status.ValueChanged += displayStatus;
Status.ValueChanged += status => statusBg.FadeColour(status?.GetAppropriateColour(colours) ?? colours.Gray5, 500, EasingTypes.OutQuint);
base.Action = () =>
{
Action?.Invoke();
profile?.ShowUser(user);
};
}
protected override void LoadComplete()
@ -191,26 +200,8 @@ namespace osu.Game.Users
statusBar.FadeIn(transition_duration, EasingTypes.OutQuint);
ResizeHeightTo(height, transition_duration, EasingTypes.OutQuint);
statusBg.FadeColour(status.GetAppropriateColour(colours), 500, EasingTypes.OutQuint);
statusMessage.Text = status.Message;
}
}
private class CoverBackgroundSprite : Sprite
{
private readonly User user;
public CoverBackgroundSprite(User user)
{
this.user = user;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
if (!string.IsNullOrEmpty(user.CoverUrl))
Texture = textures.Get(user.CoverUrl);
}
}
}
}

View File

@ -0,0 +1,64 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
namespace osu.Game.Users
{
public class UserStatistics
{
[JsonProperty(@"level")]
public LevelInfo Level;
public struct LevelInfo
{
[JsonProperty(@"current")]
public int Current;
[JsonProperty(@"progress")]
public int Progress;
}
[JsonProperty(@"pp")]
public decimal? PP;
[JsonProperty(@"pp_rank")]
public int Rank;
[JsonProperty(@"ranked_score")]
public long RankedScore;
[JsonProperty(@"hit_accuracy")]
public decimal Accuracy;
[JsonProperty(@"play_count")]
public int PlayCount;
[JsonProperty(@"total_score")]
public long TotalScore;
[JsonProperty(@"total_hits")]
public int TotalHits;
[JsonProperty(@"maximum_combo")]
public int MaxCombo;
[JsonProperty(@"replays_watched_by_others")]
public int ReplayWatched;
[JsonProperty(@"grade_counts")]
public Grades GradesCount;
public struct Grades
{
[JsonProperty(@"ss")]
public int SS;
[JsonProperty(@"s")]
public int S;
[JsonProperty(@"a")]
public int A;
}
}
}

View File

@ -76,12 +76,15 @@
<Compile Include="Audio\SampleInfoList.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
<Compile Include="Beatmaps\DummyWorkingBeatmap.cs" />
<Compile Include="Graphics\Containers\OsuClickableContainer.cs" />
<Compile Include="Graphics\Containers\OsuFocusedOverlayContainer.cs" />
<Compile Include="Graphics\Containers\OsuScrollContainer.cs" />
<Compile Include="Graphics\Cursor\OsuContextMenuContainer.cs" />
<Compile Include="Graphics\Containers\OsuTextFlowContainer.cs" />
<Compile Include="Graphics\UserInterface\IconButton.cs" />
<Compile Include="Configuration\SelectionRandomType.cs" />
<Compile Include="Graphics\UserInterface\LineGraph.cs" />
<Compile Include="Graphics\UserInterface\MenuItemType.cs" />
<Compile Include="Graphics\UserInterface\OsuContextMenu.cs" />
<Compile Include="Graphics\UserInterface\OsuContextMenuItem.cs" />
@ -98,6 +101,18 @@
<Compile Include="Overlays\Settings\SettingsHeader.cs" />
<Compile Include="Overlays\Settings\Sections\Audio\MainMenuSettings.cs" />
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
<Compile Include="Overlays\Profile\Sections\AboutSection.cs" />
<Compile Include="Overlays\Profile\Sections\BeatmapsSection.cs" />
<Compile Include="Overlays\Profile\Sections\HistoricalSection.cs" />
<Compile Include="Overlays\Profile\Sections\KudosuSection.cs" />
<Compile Include="Overlays\Profile\Sections\MedalsSection.cs" />
<Compile Include="Overlays\Profile\RankChart.cs" />
<Compile Include="Overlays\Profile\Sections\RanksSection.cs" />
<Compile Include="Overlays\Profile\Sections\RecentSection.cs" />
<Compile Include="Users\UserCoverBackground.cs" />
<Compile Include="Overlays\UserProfileOverlay.cs" />
<Compile Include="Overlays\Profile\ProfileHeader.cs" />
<Compile Include="Overlays\Profile\ProfileSection.cs" />
<Compile Include="Overlays\Toolbar\ToolbarSocialButton.cs" />
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
@ -216,7 +231,6 @@
<Compile Include="Online\API\Requests\GetScoresRequest.cs" />
<Compile Include="Online\API\Requests\GetBeatmapDetailsRequest.cs" />
<Compile Include="Online\API\Requests\GetUserRequest.cs" />
<Compile Include="Overlays\DragBar.cs" />
<Compile Include="Overlays\LoginOverlay.cs" />
<Compile Include="Overlays\MusicController.cs" />
<Compile Include="Beatmaps\Beatmap.cs" />
@ -466,6 +480,7 @@
<Compile Include="Online\Multiplayer\Room.cs" />
<Compile Include="Online\Multiplayer\RoomStatus.cs" />
<Compile Include="Users\UserPanel.cs" />
<Compile Include="Users\UserStatistics.cs" />
<Compile Include="Users\UserStatus.cs" />
<Compile Include="Overlays\DirectOverlay.cs" />
<Compile Include="Overlays\Direct\FilterControl.cs" />
@ -516,11 +531,6 @@
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup />
<ItemGroup />
<ItemGroup />
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -192,6 +192,11 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RNG/@EntryIndexedValue">RNG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SRGB/@EntryIndexedValue">SRGB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TK/@EntryIndexedValue">TK</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SS/@EntryIndexedValue">SS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PP/@EntryIndexedValue">PP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GMT/@EntryIndexedValue">GMT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QAT/@EntryIndexedValue">QAT</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BNG/@EntryIndexedValue">BNG</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&#xD;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;