1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 22:07:25 +08:00

Merge branch 'master' into iskincomponent

This commit is contained in:
Dean Herbert 2019-09-02 22:38:57 +09:00 committed by GitHub
commit 09097f7680
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 622 additions and 9 deletions

View File

@ -117,7 +117,13 @@ namespace osu.Game.Rulesets.Osu.Skinning
public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration
=> configuration.Value is TConfiguration conf ? query.Invoke(conf) : source.GetValue(query);
{
TValue val;
if (configuration.Value is TConfiguration conf && (val = query.Invoke(conf)) != null)
return val;
return source.GetValue(query);
}
private bool hasFont(string fontName) => source.GetTexture($"{fontName}-0") != null;
}

View File

@ -0,0 +1,246 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Overlays.Profile.Sections.Kudosu;
using System.Collections.Generic;
using System;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Extensions.IEnumerableExtensions;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneKudosuHistory : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(DrawableKudosuHistoryItem),
};
private readonly Box background;
public TestSceneKudosuHistory()
{
FillFlowContainer<DrawableKudosuHistoryItem> content;
AddRange(new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
content = new FillFlowContainer<DrawableKudosuHistoryItem>
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
Width = 0.7f,
AutoSizeAxes = Axes.Y,
}
});
items.ForEach(t => content.Add(new DrawableKudosuHistoryItem(t)));
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.GreySeafoam;
}
private readonly IEnumerable<APIKudosuHistory> items = new[]
{
new APIKudosuHistory
{
Amount = 10,
CreatedAt = new DateTimeOffset(new DateTime(2011, 11, 11)),
Source = KudosuSource.DenyKudosu,
Action = KudosuAction.Reset,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 1",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username1",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 5,
CreatedAt = new DateTimeOffset(new DateTime(2012, 10, 11)),
Source = KudosuSource.Forum,
Action = KudosuAction.Give,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 2",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username2",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 8,
CreatedAt = new DateTimeOffset(new DateTime(2013, 9, 11)),
Source = KudosuSource.Forum,
Action = KudosuAction.Reset,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 3",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username3",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 7,
CreatedAt = new DateTimeOffset(new DateTime(2014, 8, 11)),
Source = KudosuSource.Forum,
Action = KudosuAction.Revoke,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 4",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username4",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 100,
CreatedAt = new DateTimeOffset(new DateTime(2015, 7, 11)),
Source = KudosuSource.Vote,
Action = KudosuAction.Give,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 5",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username5",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 20,
CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)),
Source = KudosuSource.Vote,
Action = KudosuAction.Reset,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 6",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username6",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 11,
CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)),
Source = KudosuSource.AllowKudosu,
Action = KudosuAction.Give,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 7",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username7",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 24,
CreatedAt = new DateTimeOffset(new DateTime(2014, 6, 11)),
Source = KudosuSource.Delete,
Action = KudosuAction.Reset,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 8",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username8",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 12,
CreatedAt = new DateTimeOffset(new DateTime(2016, 6, 11)),
Source = KudosuSource.Restore,
Action = KudosuAction.Give,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 9",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username9",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 2,
CreatedAt = new DateTimeOffset(new DateTime(2012, 6, 11)),
Source = KudosuSource.Recalculate,
Action = KudosuAction.Give,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 10",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username10",
Url = @"https://osu.ppy.sh/u/1234"
}
},
new APIKudosuHistory
{
Amount = 32,
CreatedAt = new DateTimeOffset(new DateTime(2019, 8, 11)),
Source = KudosuSource.Recalculate,
Action = KudosuAction.Reset,
Post = new APIKudosuHistory.ModdingPost
{
Title = @"Random post 11",
Url = @"https://osu.ppy.sh/b/1234",
},
Giver = new APIKudosuHistory.KudosuGiver
{
Username = @"Username11",
Url = @"https://osu.ppy.sh/u/1234"
}
}
};
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetUserKudosuHistoryRequest : PaginatedAPIRequest<List<APIKudosuHistory>>
{
private readonly long userId;
public GetUserKudosuHistoryRequest(long userId, int page = 0, int itemsPerPage = 5)
: base(page, itemsPerPage)
{
this.userId = userId;
}
protected override string Target => $"users/{userId}/kudosu";
}
}

View File

@ -0,0 +1,83 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using Newtonsoft.Json;
namespace osu.Game.Online.API.Requests.Responses
{
public class APIKudosuHistory
{
[JsonProperty("created_at")]
public DateTimeOffset CreatedAt;
[JsonProperty("amount")]
public int Amount;
[JsonProperty("post")]
public ModdingPost Post;
public class ModdingPost
{
[JsonProperty("url")]
public string Url;
[JsonProperty("title")]
public string Title;
}
[JsonProperty("giver")]
public KudosuGiver Giver;
public class KudosuGiver
{
[JsonProperty("url")]
public string Url;
[JsonProperty("username")]
public string Username;
}
public KudosuSource Source;
public KudosuAction Action;
[JsonProperty("action")]
private string action
{
set
{
// incoming action may contain a prefix. if it doesn't, it's a legacy forum event.
string[] split = value.Split('.');
if (split.Length > 1)
Enum.TryParse(split.First().Replace("_", ""), true, out Source);
else
Source = KudosuSource.Forum;
Enum.TryParse(split.Last(), true, out Action);
}
}
}
public enum KudosuSource
{
Unknown,
AllowKudosu,
Delete,
DenyKudosu,
Forum,
Recalculate,
Restore,
Vote
}
public enum KudosuAction
{
Give,
Reset,
Revoke,
}
}

View File

@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Direct
private BeatmapSetOverlay beatmapSetOverlay;
public PreviewTrack Preview => PlayButton.Preview;
public Bindable<bool> PreviewPlaying => PlayButton.Playing;
public Bindable<bool> PreviewPlaying => PlayButton?.Playing;
protected abstract PlayButton PlayButton { get; }
protected abstract Box PreviewBar { get; }

View File

@ -0,0 +1,147 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using System;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Kudosu
{
public class DrawableKudosuHistoryItem : CompositeDrawable
{
private const int height = 25;
[Resolved]
private OsuColour colours { get; set; }
private readonly APIKudosuHistory historyItem;
private readonly LinkFlowContainer linkFlowContainer;
private readonly DrawableDate date;
public DrawableKudosuHistoryItem(APIKudosuHistory historyItem)
{
this.historyItem = historyItem;
Height = height;
RelativeSizeAxes = Axes.X;
AddRangeInternal(new Drawable[]
{
linkFlowContainer = new LinkFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(0, 3),
},
date = new DrawableDate(historyItem.CreatedAt)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
}
});
}
[BackgroundDependencyLoader]
private void load()
{
date.Colour = colours.GreySeafoamLighter;
var formattedSource = MessageFormatter.FormatText(getString(historyItem));
linkFlowContainer.AddLinks(formattedSource.Text, formattedSource.Links);
}
private string getString(APIKudosuHistory item)
{
string amount = $"{Math.Abs(item.Amount)} kudosu";
string post = $"[{item.Post.Title}]({item.Post.Url})";
switch (item.Source)
{
case KudosuSource.AllowKudosu:
switch (item.Action)
{
case KudosuAction.Give:
return $"Received {amount} from kudosu deny repeal of modding post {post}";
}
break;
case KudosuSource.DenyKudosu:
switch (item.Action)
{
case KudosuAction.Reset:
return $"Denied {amount} from modding post {post}";
}
break;
case KudosuSource.Delete:
switch (item.Action)
{
case KudosuAction.Reset:
return $"Lost {amount} from modding post deletion of {post}";
}
break;
case KudosuSource.Restore:
switch (item.Action)
{
case KudosuAction.Give:
return $"Received {amount} from modding post restoration of {post}";
}
break;
case KudosuSource.Vote:
switch (item.Action)
{
case KudosuAction.Give:
return $"Received {amount} from obtaining votes in modding post of {post}";
case KudosuAction.Reset:
return $"Lost {amount} from losing votes in modding post of {post}";
}
break;
case KudosuSource.Recalculate:
switch (item.Action)
{
case KudosuAction.Give:
return $"Received {amount} from votes recalculation in modding post of {post}";
case KudosuAction.Reset:
return $"Lost {amount} from votes recalculation in modding post of {post}";
}
break;
case KudosuSource.Forum:
string giver = $"[{item.Giver?.Username}]({item.Giver?.Url})";
switch (historyItem.Action)
{
case KudosuAction.Give:
return $"Received {amount} from {giver} for a post at {post}";
case KudosuAction.Reset:
return $"Kudosu reset by {giver} for the post {post}";
case KudosuAction.Revoke:
return $"Denied kudosu by {giver} for the post {post}";
}
break;
}
return $"Unknown event ({amount} change)";
}
}
}

View File

@ -0,0 +1,27 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.API;
using System.Collections.Generic;
namespace osu.Game.Overlays.Profile.Sections.Kudosu
{
public class PaginatedKudosuHistoryContainer : PaginatedContainer<APIKudosuHistory>
{
public PaginatedKudosuHistoryContainer(Bindable<User> user, string header, string missing)
: base(user, header, missing)
{
ItemsPerPage = 5;
}
protected override APIRequest<List<APIKudosuHistory>> CreateRequest()
=> new GetUserKudosuHistoryRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
protected override Drawable CreateDrawableItem(APIKudosuHistory item) => new DrawableKudosuHistoryItem(item);
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Game.Overlays.Profile.Sections.Kudosu;
namespace osu.Game.Overlays.Profile.Sections
@ -13,9 +14,10 @@ namespace osu.Game.Overlays.Profile.Sections
public KudosuSection()
{
Children = new[]
Children = new Drawable[]
{
new KudosuInfo(User),
new PaginatedKudosuHistoryContainer(User, null, @"This user hasn't received any kudosu!"),
};
}
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.TypeExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Threading;
using osu.Game.Audio;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
@ -278,6 +279,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
UpdateResult(false);
}
/// <summary>
/// Schedules an <see cref="Action"/> to this <see cref="DrawableHitObject"/>.
/// </summary>
/// <remarks>
/// Only provided temporarily until hitobject pooling is implemented.
/// </remarks>
protected internal new ScheduledDelegate Schedule(Action action) => base.Schedule(action);
private double? lifetimeStart;
public override double LifetimeStart

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Caching;
@ -50,8 +51,13 @@ namespace osu.Game.Rulesets.UI.Scrolling
public override bool Remove(DrawableHitObject hitObject)
{
var result = base.Remove(hitObject);
if (result)
{
initialStateCache.Invalidate();
hitObjectInitialStateCache.Remove(hitObject);
}
return result;
}
@ -86,13 +92,34 @@ namespace osu.Game.Rulesets.UI.Scrolling
scrollingInfo.Algorithm.Reset();
foreach (var obj in Objects)
{
computeLifetimeStartRecursive(obj);
computeInitialStateRecursive(obj);
}
initialStateCache.Validate();
}
}
private void computeInitialStateRecursive(DrawableHitObject hitObject)
private void computeLifetimeStartRecursive(DrawableHitObject hitObject)
{
hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value);
foreach (var obj in hitObject.NestedHitObjects)
computeLifetimeStartRecursive(obj);
}
private readonly Dictionary<DrawableHitObject, Cached> hitObjectInitialStateCache = new Dictionary<DrawableHitObject, Cached>();
// Cant use AddOnce() since the delegate is re-constructed every invocation
private void computeInitialStateRecursive(DrawableHitObject hitObject) => hitObject.Schedule(() =>
{
if (!hitObjectInitialStateCache.TryGetValue(hitObject, out var cached))
cached = hitObjectInitialStateCache[hitObject] = new Cached();
if (cached.IsValid)
return;
double endTime = hitObject.HitObject.StartTime;
if (hitObject.HitObject is IHasEndTime e)
@ -113,7 +140,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
}
}
hitObject.LifetimeStart = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, timeRange.Value);
hitObject.LifetimeEnd = scrollingInfo.Algorithm.TimeAt(scrollLength * safe_lifetime_end_multiplier, endTime, timeRange.Value, scrollLength);
foreach (var obj in hitObject.NestedHitObjects)
@ -123,7 +149,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
// Nested hitobjects don't need to scroll, but they do need accurate positions
updatePosition(obj, hitObject.HitObject.StartTime);
}
}
cached.Validate();
});
protected override void UpdateAfterChildrenLife()
{

View File

@ -414,7 +414,11 @@ namespace osu.Game.Screens.Select
{
Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\"");
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
WorkingBeatmap previous = Beatmap.Value;
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous);
if (this.IsCurrentScreen() && Beatmap.Value?.Track != previous?.Track)
ensurePlayingSelected();
if (beatmap != null)
{
@ -425,8 +429,6 @@ namespace osu.Game.Screens.Select
}
}
if (this.IsCurrentScreen())
ensurePlayingSelected();
UpdateBeatmap(Beatmap.Value);
}
}

View File

@ -6,6 +6,7 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Audio;
@ -14,6 +15,9 @@ namespace osu.Game.Skinning
public class SkinnableSound : SkinReloadableDrawable
{
private readonly ISampleInfo[] hitSamples;
private List<(AdjustableProperty property, BindableDouble bindable)> adjustments;
private SampleChannel[] channels;
private AudioManager audio;
@ -34,8 +38,39 @@ namespace osu.Game.Skinning
this.audio = audio;
}
private bool looping;
public bool Looping
{
get => looping;
set
{
if (value == looping) return;
looping = value;
channels?.ForEach(c => c.Looping = looping);
}
}
public void Play() => channels?.ForEach(c => c.Play());
public void Stop() => channels?.ForEach(c => c.Stop());
public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
{
if (adjustments == null) adjustments = new List<(AdjustableProperty, BindableDouble)>();
adjustments.Add((type, adjustBindable));
channels?.ForEach(c => c.AddAdjustment(type, adjustBindable));
}
public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
{
adjustments?.Remove((type, adjustBindable));
channels?.ForEach(c => c.RemoveAdjustment(type, adjustBindable));
}
public override bool IsPresent => Scheduler.HasPendingTasks;
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
@ -50,8 +85,15 @@ namespace osu.Game.Skinning
break;
if (ch != null)
{
ch.Looping = looping;
ch.Volume.Value = s.Volume / 100.0;
if (adjustments != null)
foreach (var adjustment in adjustments)
ch.AddAdjustment(adjustment.property, adjustment.bindable);
}
return ch;
}).Where(c => c != null).ToArray();
}