mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 03:47:04 +08:00
0988552567
I don't really have much to say here. Instead, I'll give a brief history rundown that lists many pages of documentation you can read, if interested. - Started off as BTMC + Happy24 (Vivi)'s ["The Vision"](https://docs.google.com/document/d/1p1IpPmd2RICp8G4OqkCSs7u8Ug8FbFv8qqP0mfSrHf0/edit?tab=t.0#heading=h.fol093d9f9xi) - Initial [designs](https://www.figma.com/design/f5qqC57t9jFlgpzhRqUNVX/The-Vision?node-id=0-1&p=f) were led by Vivi. - Designs [morphed](https://www.figma.com/design/vtFmLrXKvWNyYiRjTezFTM/Untitled--Copy-?node-id=0-1&p=f) during development into what's currently present, led by @minetoblend. - There is some more ongoing work creating a [game design document](https://docs.google.com/document/d/1iffJFCsIBfYF0D4ogItSBEj6YBmbp-rdCpItAeaJiTA/edit?tab=t.0). **tl;dr:** Create something with the mechanics of a trading card game within osu!. The name of this is "ranked play". --- To be frank, a lot of stuff is missing here. Some of it I don't want to mention, because the point of this exercise is to get the system into the hands of players, gather feedback especially around mechanics, and discuss any further direction with the team. I am expecting a blanket approval on all of the new code, with particular attention to changes in existing components that I'll point out in a self review. There is also some [ongoing work](https://github.com/smoogipoo/osu/pulls) that may arrive in this branch prior to being merged. --------- Co-authored-by: maarvin <minetoblend@gmail.com> Co-authored-by: Marvin <m.schuerz@hautzy.com> Co-authored-by: Jamie Taylor <me@nekodex.net> Co-authored-by: ArijanJ <arijanj@proton.me> Co-authored-by: Dean Herbert <pe@ppy.sh> Co-authored-by: Tim Oliver <git@tim.dev> Co-authored-by: Joseph Madamba <madamba.joehu@outlook.com> Co-authored-by: Bartłomiej Dach <dach.bartlomiej@gmail.com> Co-authored-by: nil <25884226+voidstar0@users.noreply.github.com> Co-authored-by: Ботников Максим <mr.botnikoff@ya.ru> Co-authored-by: Denis Titovets <den232titovets@yandex.ru> Co-authored-by: Michael Middlezong <119022671+mmiddlezong@users.noreply.github.com> Co-authored-by: SupDos <6813986+SupDos@users.noreply.github.com> Co-authored-by: failaip12 <86018517+failaip12@users.noreply.github.com>
332 lines
11 KiB
C#
332 lines
11 KiB
C#
// 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 MessagePack;
|
|
using osu.Game.Beatmaps;
|
|
using osu.Game.Graphics;
|
|
using osu.Game.Online;
|
|
using osu.Game.Online.Multiplayer;
|
|
using osu.Game.Online.Rooms;
|
|
using osu.Game.Rulesets;
|
|
using osu.Game.Scoring;
|
|
using osuTK.Graphics;
|
|
|
|
namespace osu.Game.Users
|
|
{
|
|
/// <summary>
|
|
/// Base class for all structures describing the user's current activity.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Warning: keep <see cref="UnionAttribute"/> specs consistent with
|
|
/// <see cref="SignalRWorkaroundTypes.BASE_TYPE_MAPPING"/>.
|
|
/// </remarks>
|
|
[Serializable]
|
|
[MessagePackObject]
|
|
[Union(11, typeof(ChoosingBeatmap))]
|
|
[Union(12, typeof(InSoloGame))]
|
|
[Union(13, typeof(WatchingReplay))]
|
|
[Union(14, typeof(SpectatingUser))]
|
|
[Union(21, typeof(SearchingForLobby))]
|
|
[Union(22, typeof(InLobby))]
|
|
[Union(23, typeof(InMultiplayerGame))]
|
|
[Union(24, typeof(SpectatingMultiplayerGame))]
|
|
[Union(31, typeof(InPlaylistGame))]
|
|
[Union(41, typeof(EditingBeatmap))]
|
|
[Union(42, typeof(ModdingBeatmap))]
|
|
[Union(43, typeof(TestingBeatmap))]
|
|
[Union(51, typeof(InDailyChallengeLobby))]
|
|
[Union(52, typeof(PlayingDailyChallenge))]
|
|
public abstract class UserActivity
|
|
{
|
|
public abstract string GetStatus(bool hideIdentifiableInformation = false);
|
|
public virtual string? GetDetails(bool hideIdentifiableInformation = false) => null;
|
|
|
|
public virtual Color4 GetAppropriateColour(OsuColour colours) => colours.GreenDarker;
|
|
|
|
/// <summary>
|
|
/// Returns the ID of the beatmap involved in this activity, if applicable and/or available.
|
|
/// </summary>
|
|
/// <param name="hideIdentifiableInformation"></param>
|
|
public virtual int? GetBeatmapID(bool hideIdentifiableInformation = false) => null;
|
|
|
|
[MessagePackObject]
|
|
public class ChoosingBeatmap : UserActivity
|
|
{
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => "Choosing a beatmap";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
[Union(12, typeof(InSoloGame))]
|
|
[Union(23, typeof(InMultiplayerGame))]
|
|
[Union(24, typeof(SpectatingMultiplayerGame))]
|
|
[Union(31, typeof(InPlaylistGame))]
|
|
[Union(52, typeof(PlayingDailyChallenge))]
|
|
public abstract class InGame : UserActivity
|
|
{
|
|
[Key(0)]
|
|
public int BeatmapID { get; set; }
|
|
|
|
[Key(1)]
|
|
public string BeatmapDisplayTitle { get; set; } = string.Empty;
|
|
|
|
[Key(2)]
|
|
public int RulesetID { get; set; }
|
|
|
|
[Key(3)]
|
|
public string RulesetPlayingVerb { get; set; } = string.Empty; // TODO: i'm going with this for now, but this is wasteful
|
|
|
|
protected InGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
|
{
|
|
BeatmapID = beatmapInfo.OnlineID;
|
|
BeatmapDisplayTitle = beatmapInfo.GetDisplayTitle();
|
|
|
|
RulesetID = ruleset.OnlineID;
|
|
RulesetPlayingVerb = ruleset.CreateInstance().PlayingVerb;
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
protected InGame() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => RulesetPlayingVerb;
|
|
public override string GetDetails(bool hideIdentifiableInformation = false) => BeatmapDisplayTitle;
|
|
public override int? GetBeatmapID(bool hideIdentifiableInformation = false) => BeatmapID;
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class InSoloGame : InGame
|
|
{
|
|
public InSoloGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
|
: base(beatmapInfo, ruleset)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public InSoloGame() { }
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class InMultiplayerGame : InGame
|
|
{
|
|
public InMultiplayerGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
|
: base(beatmapInfo, ruleset)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public InMultiplayerGame()
|
|
{
|
|
}
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => $@"{base.GetStatus(hideIdentifiableInformation)} with others";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class InPlaylistGame : InGame
|
|
{
|
|
public InPlaylistGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
|
: base(beatmapInfo, ruleset)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public InPlaylistGame() { }
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class TestingBeatmap : EditingBeatmap
|
|
{
|
|
public TestingBeatmap(IBeatmapInfo beatmapInfo)
|
|
: base(beatmapInfo)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public TestingBeatmap() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => "Testing a beatmap";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class EditingBeatmap : UserActivity
|
|
{
|
|
[Key(0)]
|
|
public int BeatmapID { get; set; }
|
|
|
|
[Key(1)]
|
|
public string BeatmapDisplayTitle { get; set; } = string.Empty;
|
|
|
|
public EditingBeatmap(IBeatmapInfo info)
|
|
{
|
|
BeatmapID = info.OnlineID;
|
|
BeatmapDisplayTitle = info.GetDisplayTitle();
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public EditingBeatmap() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => @"Editing a beatmap";
|
|
|
|
public override string GetDetails(bool hideIdentifiableInformation = false) => hideIdentifiableInformation
|
|
// For now let's assume that showing the beatmap a user is editing could reveal unwanted information.
|
|
? string.Empty
|
|
: BeatmapDisplayTitle;
|
|
|
|
public override int? GetBeatmapID(bool hideIdentifiableInformation = false) => hideIdentifiableInformation
|
|
// For now let's assume that showing the beatmap a user is editing could reveal unwanted information.
|
|
? null
|
|
: BeatmapID;
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class ModdingBeatmap : EditingBeatmap
|
|
{
|
|
public ModdingBeatmap(IBeatmapInfo info)
|
|
: base(info)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public ModdingBeatmap() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => "Modding a beatmap";
|
|
public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark;
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class WatchingReplay : UserActivity
|
|
{
|
|
[Key(0)]
|
|
public long ScoreID { get; set; }
|
|
|
|
[Key(1)]
|
|
public string PlayerName { get; set; } = string.Empty;
|
|
|
|
[Key(2)]
|
|
public int BeatmapID { get; set; }
|
|
|
|
[Key(3)]
|
|
public string? BeatmapDisplayTitle { get; set; }
|
|
|
|
public WatchingReplay(ScoreInfo score)
|
|
{
|
|
ScoreID = score.OnlineID;
|
|
PlayerName = score.User.Username;
|
|
BeatmapID = score.BeatmapInfo?.OnlineID ?? -1;
|
|
BeatmapDisplayTitle = score.BeatmapInfo?.GetDisplayTitle();
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public WatchingReplay() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Watching a replay" : $@"Watching {PlayerName}'s replay";
|
|
public override string? GetDetails(bool hideIdentifiableInformation = false) => BeatmapDisplayTitle;
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class SpectatingUser : WatchingReplay
|
|
{
|
|
public SpectatingUser(ScoreInfo score)
|
|
: base(score)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public SpectatingUser() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => hideIdentifiableInformation ? @"Spectating a user" : $@"Spectating {PlayerName}";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class SpectatingMultiplayerGame : InGame
|
|
{
|
|
public SpectatingMultiplayerGame(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
|
: base(beatmapInfo, ruleset)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public SpectatingMultiplayerGame() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => @"Spectating a multiplayer game";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class SearchingForLobby : UserActivity
|
|
{
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => @"Looking for a lobby";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class InLobby : UserActivity
|
|
{
|
|
[Key(0)]
|
|
public long RoomID { get; set; }
|
|
|
|
[Key(1)]
|
|
public string RoomName { get; set; } = string.Empty;
|
|
|
|
public InLobby(Room room)
|
|
{
|
|
RoomID = room.RoomID ?? -1;
|
|
RoomName = room.Name;
|
|
}
|
|
|
|
public InLobby(MultiplayerRoom room)
|
|
{
|
|
switch (room.Settings.MatchType)
|
|
{
|
|
case MatchType.Matchmaking:
|
|
RoomID = -1;
|
|
RoomName = "Quick Play";
|
|
break;
|
|
|
|
case MatchType.RankedPlay:
|
|
RoomID = -1;
|
|
RoomName = "Ranked Play";
|
|
break;
|
|
|
|
default:
|
|
RoomID = room.RoomID;
|
|
RoomName = room.Settings.Name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public InLobby() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => @"In a lobby";
|
|
|
|
public override string? GetDetails(bool hideIdentifiableInformation = false) => hideIdentifiableInformation
|
|
? null
|
|
: RoomName;
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class InDailyChallengeLobby : UserActivity
|
|
{
|
|
[SerializationConstructor]
|
|
public InDailyChallengeLobby() { }
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => @"In daily challenge lobby";
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class PlayingDailyChallenge : InGame
|
|
{
|
|
public PlayingDailyChallenge(IBeatmapInfo beatmapInfo, IRulesetInfo ruleset)
|
|
: base(beatmapInfo, ruleset)
|
|
{
|
|
}
|
|
|
|
[SerializationConstructor]
|
|
public PlayingDailyChallenge()
|
|
{
|
|
}
|
|
|
|
public override string GetStatus(bool hideIdentifiableInformation = false) => @$"{RulesetPlayingVerb} in daily challenge";
|
|
}
|
|
}
|
|
}
|