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

Merge branch 'master' into auto-restart

This commit is contained in:
Dan Balasescu 2021-08-16 12:34:04 +09:00 committed by GitHub
commit 989d337532
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 149 additions and 74 deletions

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -19,6 +20,7 @@ namespace osu.Game.Tests.Chat
{ {
private ChannelManager channelManager; private ChannelManager channelManager;
private int currentMessageId; private int currentMessageId;
private List<Message> sentMessages;
[SetUp] [SetUp]
public void Setup() => Schedule(() => public void Setup() => Schedule(() =>
@ -34,6 +36,7 @@ namespace osu.Game.Tests.Chat
AddStep("register request handling", () => AddStep("register request handling", () =>
{ {
currentMessageId = 0; currentMessageId = 0;
sentMessages = new List<Message>();
((DummyAPIAccess)API).HandleRequest = req => ((DummyAPIAccess)API).HandleRequest = req =>
{ {
@ -44,16 +47,11 @@ namespace osu.Game.Tests.Chat
return true; return true;
case PostMessageRequest postMessage: case PostMessageRequest postMessage:
postMessage.TriggerSuccess(new Message(++currentMessageId) handlePostMessageRequest(postMessage);
{ return true;
IsAction = postMessage.Message.IsAction,
ChannelId = postMessage.Message.ChannelId,
Content = postMessage.Message.Content,
Links = postMessage.Message.Links,
Timestamp = postMessage.Message.Timestamp,
Sender = postMessage.Message.Sender
});
case MarkChannelAsReadRequest markRead:
handleMarkChannelAsReadRequest(markRead);
return true; return true;
} }
@ -83,12 +81,65 @@ namespace osu.Game.Tests.Chat
AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to")); AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to"));
} }
[Test]
public void TestMarkAsReadIgnoringLocalMessages()
{
Channel channel = null;
AddStep("join channel and select it", () =>
{
channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public));
channelManager.CurrentChannel.Value = channel;
});
AddStep("post message", () => channelManager.PostMessage("Something interesting"));
AddStep("post /help command", () => channelManager.PostCommand("help", channel));
AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel));
AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel));
AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel));
AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel));
AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel));
AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id);
}
private void handlePostMessageRequest(PostMessageRequest request)
{
var message = new Message(++currentMessageId)
{
IsAction = request.Message.IsAction,
ChannelId = request.Message.ChannelId,
Content = request.Message.Content,
Links = request.Message.Links,
Timestamp = request.Message.Timestamp,
Sender = request.Message.Sender
};
sentMessages.Add(message);
request.TriggerSuccess(message);
}
private void handleMarkChannelAsReadRequest(MarkChannelAsReadRequest request)
{
// only accept messages that were sent through the API
if (sentMessages.Contains(request.Message))
{
request.TriggerSuccess();
}
else
{
request.TriggerFailure(new APIException("unknown message!", null));
}
}
private Channel createChannel(int id, ChannelType type) => new Channel(new User()) private Channel createChannel(int id, ChannelType type) => new Channel(new User())
{ {
Id = id, Id = id,
Name = $"Channel {id}", Name = $"Channel {id}",
Topic = $"Topic of channel {id} with type {type}", Topic = $"Topic of channel {id} with type {type}",
Type = type, Type = type,
LastMessageId = 0,
}; };
private class ChannelManagerContainer : CompositeDrawable private class ChannelManagerContainer : CompositeDrawable

View File

@ -9,16 +9,16 @@ namespace osu.Game.Online.API.Requests
{ {
public class MarkChannelAsReadRequest : APIRequest public class MarkChannelAsReadRequest : APIRequest
{ {
private readonly Channel channel; public readonly Channel Channel;
private readonly Message message; public readonly Message Message;
public MarkChannelAsReadRequest(Channel channel, Message message) public MarkChannelAsReadRequest(Channel channel, Message message)
{ {
this.channel = channel; Channel = channel;
this.message = message; Message = message;
} }
protected override string Target => $"chat/channels/{channel.Id}/mark-as-read/{message.Id}"; protected override string Target => $"chat/channels/{Channel.Id}/mark-as-read/{Message.Id}";
protected override WebRequest CreateWebRequest() protected override WebRequest CreateWebRequest()
{ {

View File

@ -553,7 +553,7 @@ namespace osu.Game.Online.Chat
if (channel.LastMessageId == channel.LastReadId) if (channel.LastMessageId == channel.LastReadId)
return; return;
var message = channel.Messages.LastOrDefault(); var message = channel.Messages.FindLast(msg => !(msg is LocalMessage));
if (message == null) if (message == null)
return; return;

View File

@ -78,10 +78,10 @@ namespace osu.Game.Overlays.BeatmapSet
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Children = new[] Children = new[]
{ {
length = new Statistic(FontAwesome.Regular.Clock, "Length") { Width = 0.25f }, length = new Statistic(BeatmapStatisticsIconType.Length, "Length") { Width = 0.25f },
bpm = new Statistic(FontAwesome.Regular.Circle, "BPM") { Width = 0.25f }, bpm = new Statistic(BeatmapStatisticsIconType.Bpm, "BPM") { Width = 0.25f },
circleCount = new Statistic(FontAwesome.Regular.Circle, "Circle Count") { Width = 0.25f }, circleCount = new Statistic(BeatmapStatisticsIconType.Circles, "Circle Count") { Width = 0.25f },
sliderCount = new Statistic(FontAwesome.Regular.Circle, "Slider Count") { Width = 0.25f }, sliderCount = new Statistic(BeatmapStatisticsIconType.Sliders, "Slider Count") { Width = 0.25f },
}, },
}; };
} }
@ -104,7 +104,7 @@ namespace osu.Game.Overlays.BeatmapSet
set => this.value.Text = value; set => this.value.Text = value;
} }
public Statistic(IconUsage icon, string name) public Statistic(BeatmapStatisticsIconType icon, string name)
{ {
TooltipText = name; TooltipText = name;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -133,8 +133,16 @@ namespace osu.Game.Overlays.BeatmapSet
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = FontAwesome.Regular.Circle,
Size = new Vector2(12), Size = new Vector2(10),
Rotation = 0,
Colour = Color4Extensions.FromHex(@"f7dd55"),
},
new BeatmapStatisticIcon(icon)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Size = new Vector2(10),
Colour = Color4Extensions.FromHex(@"f7dd55"), Colour = Color4Extensions.FromHex(@"f7dd55"),
Scale = new Vector2(0.8f), Scale = new Vector2(0.8f),
}, },

View File

@ -10,12 +10,12 @@ namespace osu.Game.Screens.OnlinePlay.Components
{ {
public class OnlinePlayBackgroundSprite : OnlinePlayComposite public class OnlinePlayBackgroundSprite : OnlinePlayComposite
{ {
private readonly BeatmapSetCoverType beatmapSetCoverType; protected readonly BeatmapSetCoverType BeatmapSetCoverType;
private UpdateableBeatmapBackgroundSprite sprite; private UpdateableBeatmapBackgroundSprite sprite;
public OnlinePlayBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) public OnlinePlayBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover)
{ {
this.beatmapSetCoverType = beatmapSetCoverType; BeatmapSetCoverType = beatmapSetCoverType;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -33,6 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Components
sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value; sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value;
} }
protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
} }
} }

View File

@ -158,11 +158,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
Children = new Drawable[] Children = new Drawable[]
{ {
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -172,8 +167,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
}, },
}
},
new Container new Container
{ {
Name = @"Room content", Name = @"Room content",
@ -186,12 +179,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
Masking = true, Masking = true,
CornerRadius = corner_radius, CornerRadius = corner_radius,
Children = new Drawable[] Children = new Drawable[]
{
// This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites.
new BufferedContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{ {
new GridContainer new GridContainer
{ {
@ -217,8 +204,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
} }
} }
}, },
},
},
new Container new Container
{ {
Name = @"Left details", Name = @"Left details",

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Input; using osu.Game.Input;
@ -104,14 +105,9 @@ namespace osu.Game.Screens.OnlinePlay
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
new BufferedContainer new BeatmapBackgroundSprite
{
RelativeSizeAxes = Axes.Both,
BlurSigma = new Vector2(10),
Child = new BeatmapBackgroundSprite
{ {
RelativeSizeAxes = Axes.Both RelativeSizeAxes = Axes.Both
}
}, },
new Box new Box
{ {
@ -306,11 +302,46 @@ namespace osu.Game.Screens.OnlinePlay
private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite
{ {
protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BlurredBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite public class BlurredBackgroundSprite : UpdateableBeatmapBackgroundSprite
{ {
public BlurredBackgroundSprite(BeatmapSetCoverType type)
: base(type)
{
}
protected override double LoadDelay => 200; protected override double LoadDelay => 200;
protected override Drawable CreateDrawable(BeatmapInfo model) =>
new BufferedLoader(base.CreateDrawable(model));
}
// This class is an unfortunate requirement due to `LongRunningLoad` requiring direct async loading.
// It means that if the web request fetching the beatmap background takes too long, it will suddenly appear.
internal class BufferedLoader : BufferedContainer
{
private readonly Drawable drawable;
public BufferedLoader(Drawable drawable)
{
this.drawable = drawable;
RelativeSizeAxes = Axes.Both;
BlurSigma = new Vector2(10);
FrameBufferScale = new Vector2(0.5f);
CacheDrawnFrameBuffer = true;
}
[BackgroundDependencyLoader]
private void load()
{
LoadComponentAsync(drawable, d =>
{
Add(d);
ForceRedraw();
});
}
} }
} }