mirror of
https://github.com/ppy/osu.git
synced 2025-01-19 02:52:54 +08:00
Merge branch 'master' into results-screen
This commit is contained in:
commit
dd3f9c1cdd
@ -1 +1 @@
|
|||||||
Subproject commit 21a97586f7fa8d9aa65b4131824151d88a70b520
|
Subproject commit dc4ea5be425d37f3a0dd09f6acdf6799d42e3d74
|
33
osu.Game/Online/API/Requests/PostMessageRequest.cs
Normal file
33
osu.Game/Online/API/Requests/PostMessageRequest.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// 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.Extensions;
|
||||||
|
using osu.Framework.IO.Network;
|
||||||
|
using osu.Game.Online.Chat;
|
||||||
|
|
||||||
|
namespace osu.Game.Online.API.Requests
|
||||||
|
{
|
||||||
|
public class PostMessageRequest : APIRequest<Message>
|
||||||
|
{
|
||||||
|
private readonly Message message;
|
||||||
|
|
||||||
|
public PostMessageRequest(Message message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override WebRequest CreateWebRequest()
|
||||||
|
{
|
||||||
|
var req = base.CreateWebRequest();
|
||||||
|
|
||||||
|
req.Method = HttpMethod.POST;
|
||||||
|
req.AddParameter(@"target_type", message.TargetType.GetDescription());
|
||||||
|
req.AddParameter(@"target_id", message.TargetId.ToString());
|
||||||
|
req.AddParameter(@"message", message.Content);
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string Target => @"chat/messages";
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Lists;
|
||||||
|
|
||||||
namespace osu.Game.Online.Chat
|
namespace osu.Game.Online.Chat
|
||||||
{
|
{
|
||||||
@ -21,7 +23,7 @@ namespace osu.Game.Online.Chat
|
|||||||
[JsonProperty(@"channel_id")]
|
[JsonProperty(@"channel_id")]
|
||||||
public int Id;
|
public int Id;
|
||||||
|
|
||||||
public List<Message> Messages = new List<Message>();
|
public SortedList<Message> Messages = new SortedList<Message>((m1, m2) => m1.Id.CompareTo(m2.Id));
|
||||||
|
|
||||||
//internal bool Joined;
|
//internal bool Joined;
|
||||||
|
|
||||||
@ -36,7 +38,10 @@ namespace osu.Game.Online.Chat
|
|||||||
|
|
||||||
public void AddNewMessages(IEnumerable<Message> messages)
|
public void AddNewMessages(IEnumerable<Message> messages)
|
||||||
{
|
{
|
||||||
|
messages = messages.Except(Messages).ToList();
|
||||||
|
|
||||||
Messages.AddRange(messages);
|
Messages.AddRange(messages);
|
||||||
|
|
||||||
purgeOldMessages();
|
purgeOldMessages();
|
||||||
|
|
||||||
NewMessagesArrived?.Invoke(messages);
|
NewMessagesArrived?.Invoke(messages);
|
||||||
|
@ -55,6 +55,9 @@ namespace osu.Game.Online.Chat.Drawables
|
|||||||
|
|
||||||
private Color4 getUsernameColour(Message message)
|
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.
|
//todo: use User instead of Message when user_id is correctly populated.
|
||||||
return username_colours[message.UserId % username_colours.Length];
|
return username_colours[message.UserId % username_colours.Length];
|
||||||
}
|
}
|
||||||
@ -91,7 +94,7 @@ namespace osu.Game.Online.Chat.Drawables
|
|||||||
new OsuSpriteText
|
new OsuSpriteText
|
||||||
{
|
{
|
||||||
Font = @"Exo2.0-BoldItalic",
|
Font = @"Exo2.0-BoldItalic",
|
||||||
Text = $@"{Message.User.Username}:",
|
Text = $@"{Message.Sender.Username}:",
|
||||||
Colour = getUsernameColour(Message),
|
Colour = getUsernameColour(Message),
|
||||||
TextSize = text_size,
|
TextSize = text_size,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
@ -10,14 +11,17 @@ namespace osu.Game.Online.Chat
|
|||||||
public class Message
|
public class Message
|
||||||
{
|
{
|
||||||
[JsonProperty(@"message_id")]
|
[JsonProperty(@"message_id")]
|
||||||
public long Id;
|
public readonly long Id;
|
||||||
|
|
||||||
//todo: this should be inside sender.
|
//todo: this should be inside sender.
|
||||||
[JsonProperty(@"user_id")]
|
[JsonProperty(@"sender_id")]
|
||||||
public int UserId;
|
public int UserId;
|
||||||
|
|
||||||
[JsonProperty(@"channel_id")]
|
[JsonProperty(@"target_type")]
|
||||||
public int ChannelId;
|
public TargetType TargetType;
|
||||||
|
|
||||||
|
[JsonProperty(@"target_id")]
|
||||||
|
public int TargetId;
|
||||||
|
|
||||||
[JsonProperty(@"timestamp")]
|
[JsonProperty(@"timestamp")]
|
||||||
public DateTimeOffset Timestamp;
|
public DateTimeOffset Timestamp;
|
||||||
@ -26,11 +30,31 @@ namespace osu.Game.Online.Chat
|
|||||||
public string Content;
|
public string Content;
|
||||||
|
|
||||||
[JsonProperty(@"sender")]
|
[JsonProperty(@"sender")]
|
||||||
public User User;
|
public User Sender;
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public Message()
|
public Message()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
var objMessage = obj as Message;
|
||||||
|
|
||||||
|
return Id == objMessage?.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Id.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TargetType
|
||||||
|
{
|
||||||
|
[Description(@"channel")]
|
||||||
|
Channel,
|
||||||
|
[Description(@"user")]
|
||||||
|
User
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,6 +194,7 @@ namespace osu.Game
|
|||||||
};
|
};
|
||||||
|
|
||||||
Dependencies.Cache(options);
|
Dependencies.Cache(options);
|
||||||
|
Dependencies.Cache(chat);
|
||||||
Dependencies.Cache(musicController);
|
Dependencies.Cache(musicController);
|
||||||
Dependencies.Cache(notificationManager);
|
Dependencies.Cache(notificationManager);
|
||||||
Dependencies.Cache(dialogOverlay);
|
Dependencies.Cache(dialogOverlay);
|
||||||
|
@ -38,6 +38,10 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private APIAccess api;
|
private APIAccess api;
|
||||||
|
|
||||||
|
private const int transition_length = 500;
|
||||||
|
|
||||||
|
private GetMessagesRequest fetchReq;
|
||||||
|
|
||||||
public ChatOverlay()
|
public ChatOverlay()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -82,94 +86,6 @@ namespace osu.Game.Overlays
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnFocus(InputState state)
|
|
||||||
{
|
|
||||||
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
|
||||||
inputTextBox.TriggerFocus();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void postMessage(TextBox sender, bool newText)
|
|
||||||
{
|
|
||||||
var postText = sender.Text;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(postText) && api.LocalUser.Value != null)
|
|
||||||
{
|
|
||||||
//todo: actually send to server
|
|
||||||
careChannels.FirstOrDefault()?.AddNewMessages(new[]
|
|
||||||
{
|
|
||||||
new Message
|
|
||||||
{
|
|
||||||
User = api.LocalUser.Value,
|
|
||||||
Timestamp = DateTimeOffset.Now,
|
|
||||||
Content = postText
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sender.Text = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(APIAccess api)
|
|
||||||
{
|
|
||||||
this.api = api;
|
|
||||||
api.Register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long? lastMessageId;
|
|
||||||
|
|
||||||
private List<Channel> careChannels;
|
|
||||||
|
|
||||||
private void addChannel(Channel channel)
|
|
||||||
{
|
|
||||||
Add(new DrawableChannel(channel));
|
|
||||||
careChannels.Add(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private GetMessagesRequest fetchReq;
|
|
||||||
|
|
||||||
public void FetchNewMessages(APIAccess api)
|
|
||||||
{
|
|
||||||
if (fetchReq != null) return;
|
|
||||||
|
|
||||||
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
|
|
||||||
fetchReq.Success += delegate (List<Message> messages)
|
|
||||||
{
|
|
||||||
var ids = messages.Select(m => m.ChannelId).Distinct();
|
|
||||||
|
|
||||||
//batch messages per channel.
|
|
||||||
foreach (var id in ids)
|
|
||||||
careChannels.Find(c => c.Id == id)?.AddNewMessages(messages.Where(m => m.ChannelId == id));
|
|
||||||
|
|
||||||
lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId;
|
|
||||||
|
|
||||||
Debug.Write("success!");
|
|
||||||
fetchReq = null;
|
|
||||||
};
|
|
||||||
fetchReq.Failure += delegate
|
|
||||||
{
|
|
||||||
Debug.Write("failure!");
|
|
||||||
fetchReq = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
api.Queue(fetchReq);
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int transition_length = 500;
|
|
||||||
|
|
||||||
protected override void PopIn()
|
|
||||||
{
|
|
||||||
MoveToY(0, transition_length, EasingTypes.OutQuint);
|
|
||||||
FadeIn(transition_length, EasingTypes.OutQuint);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PopOut()
|
|
||||||
{
|
|
||||||
MoveToY(DrawSize.Y, transition_length, EasingTypes.InSine);
|
|
||||||
FadeOut(transition_length, EasingTypes.InSine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void APIStateChanged(APIAccess api, APIState state)
|
public void APIStateChanged(APIAccess api, APIState state)
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
@ -183,19 +99,46 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnFocus(InputState state)
|
||||||
|
{
|
||||||
|
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
||||||
|
inputTextBox.TriggerFocus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopIn()
|
||||||
|
{
|
||||||
|
MoveToY(0, transition_length, EasingTypes.OutQuint);
|
||||||
|
FadeIn(transition_length, EasingTypes.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PopOut()
|
||||||
|
{
|
||||||
|
MoveToY(DrawSize.Y, transition_length, EasingTypes.InSine);
|
||||||
|
FadeOut(transition_length, EasingTypes.InSine);
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(APIAccess api)
|
||||||
|
{
|
||||||
|
this.api = api;
|
||||||
|
api.Register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long? lastMessageId;
|
||||||
|
|
||||||
|
private List<Channel> careChannels;
|
||||||
|
|
||||||
private void initializeChannels()
|
private void initializeChannels()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
careChannels = new List<Channel>();
|
careChannels = new List<Channel>();
|
||||||
|
|
||||||
//if (api.State != APIAccess.APIState.Online)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
SpriteText loading;
|
SpriteText loading;
|
||||||
Add(loading = new OsuSpriteText
|
Add(loading = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = @"Loading available channels...",
|
Text = @"initialising chat...",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
TextSize = 40,
|
TextSize = 40,
|
||||||
@ -211,15 +154,85 @@ namespace osu.Game.Overlays
|
|||||||
Scheduler.Add(delegate
|
Scheduler.Add(delegate
|
||||||
{
|
{
|
||||||
loading.FadeOut(100);
|
loading.FadeOut(100);
|
||||||
addChannel(channels.Find(c => c.Name == @"#osu"));
|
addChannel(channels.Find(c => c.Name == @"#lazer"));
|
||||||
});
|
});
|
||||||
|
|
||||||
//addChannel(channels.Find(c => c.Name == @"#lobby"));
|
messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
|
||||||
//addChannel(channels.Find(c => c.Name == @"#english"));
|
|
||||||
|
|
||||||
messageRequest = Scheduler.AddDelayed(() => FetchNewMessages(api), 1000, true);
|
|
||||||
};
|
};
|
||||||
api.Queue(req);
|
api.Queue(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addChannel(Channel channel)
|
||||||
|
{
|
||||||
|
Add(new DrawableChannel(channel));
|
||||||
|
careChannels.Add(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchNewMessages()
|
||||||
|
{
|
||||||
|
if (fetchReq != null) return;
|
||||||
|
|
||||||
|
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
|
||||||
|
fetchReq.Success += delegate (List<Message> messages)
|
||||||
|
{
|
||||||
|
var ids = messages.Where(m => m.TargetType == TargetType.Channel).Select(m => m.TargetId).Distinct();
|
||||||
|
|
||||||
|
//batch messages per channel.
|
||||||
|
foreach (var id in ids)
|
||||||
|
careChannels.Find(c => c.Id == id)?.AddNewMessages(messages.Where(m => m.TargetId == id));
|
||||||
|
|
||||||
|
lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId;
|
||||||
|
|
||||||
|
Debug.Write("success!");
|
||||||
|
fetchReq = null;
|
||||||
|
};
|
||||||
|
fetchReq.Failure += delegate
|
||||||
|
{
|
||||||
|
Debug.Write("failure!");
|
||||||
|
fetchReq = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
api.Queue(fetchReq);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void postMessage(TextBox textbox, bool newText)
|
||||||
|
{
|
||||||
|
var postText = textbox.Text;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(postText) && api.LocalUser.Value != null)
|
||||||
|
{
|
||||||
|
var currentChannel = careChannels.FirstOrDefault();
|
||||||
|
|
||||||
|
if (currentChannel == null) return;
|
||||||
|
|
||||||
|
var message = new Message
|
||||||
|
{
|
||||||
|
Sender = api.LocalUser.Value,
|
||||||
|
Timestamp = DateTimeOffset.Now,
|
||||||
|
TargetType = TargetType.Channel, //TODO: read this from currentChannel
|
||||||
|
TargetId = currentChannel.Id,
|
||||||
|
Content = postText
|
||||||
|
};
|
||||||
|
|
||||||
|
textbox.ReadOnly = true;
|
||||||
|
var req = new PostMessageRequest(message);
|
||||||
|
|
||||||
|
req.Failure += e =>
|
||||||
|
{
|
||||||
|
textbox.FlashColour(Color4.Red, 1000);
|
||||||
|
textbox.ReadOnly = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
req.Success += m =>
|
||||||
|
{
|
||||||
|
currentChannel.AddNewMessages(new[] { m });
|
||||||
|
|
||||||
|
textbox.ReadOnly = false;
|
||||||
|
textbox.Text = string.Empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
api.Queue(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,7 @@ namespace osu.Game.Overlays.Toolbar
|
|||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
new ToolbarChatButton(),
|
||||||
new ToolbarMusicButton(),
|
new ToolbarMusicButton(),
|
||||||
new ToolbarButton
|
new ToolbarButton
|
||||||
{
|
{
|
||||||
|
23
osu.Game/Overlays/Toolbar/ToolbarChatButton.cs
Normal file
23
osu.Game/Overlays/Toolbar/ToolbarChatButton.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Toolbar
|
||||||
|
{
|
||||||
|
internal class ToolbarChatButton : ToolbarOverlayToggleButton
|
||||||
|
{
|
||||||
|
public ToolbarChatButton()
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.fa_comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ChatOverlay chat)
|
||||||
|
{
|
||||||
|
StateContainer = chat;
|
||||||
|
Action = chat.ToggleVisibility;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -72,6 +72,8 @@
|
|||||||
<Compile Include="Audio\SampleInfo.cs" />
|
<Compile Include="Audio\SampleInfo.cs" />
|
||||||
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
|
<Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
|
||||||
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
|
<Compile Include="Beatmaps\DifficultyCalculator.cs" />
|
||||||
|
<Compile Include="Online\API\Requests\PostMessageRequest.cs" />
|
||||||
|
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
|
||||||
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
|
<Compile Include="Rulesets\Beatmaps\BeatmapConverter.cs" />
|
||||||
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
|
<Compile Include="Rulesets\Beatmaps\BeatmapProcessor.cs" />
|
||||||
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
|
<Compile Include="Beatmaps\Legacy\LegacyBeatmap.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user