mirror of
https://github.com/ppy/osu.git
synced 2026-05-21 23:51:01 +08:00
Add ranked play models
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using MessagePack;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
@@ -16,6 +17,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
[MessagePackObject]
|
||||
[Union(0, typeof(TeamVersusRoomState))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types.
|
||||
[Union(1, typeof(MatchmakingRoomState))]
|
||||
[Union(2, typeof(RankedPlayRoomState))]
|
||||
public abstract class MatchRoomState
|
||||
{
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using MessagePack;
|
||||
using osu.Game.Online.Matchmaking.Events;
|
||||
using osu.Game.Online.Multiplayer.Countdown;
|
||||
using osu.Game.Online.RankedPlay;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
@@ -17,6 +18,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
[Union(0, typeof(CountdownStartedEvent))]
|
||||
[Union(1, typeof(CountdownStoppedEvent))]
|
||||
[Union(2, typeof(MatchmakingAvatarActionEvent))]
|
||||
[Union(3, typeof(RankedPlayCardHandReplayEvent))]
|
||||
public abstract class MatchServerEvent
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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.Diagnostics.CodeAnalysis;
|
||||
using MessagePack;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public class RankedPlayCardItem : IEquatable<RankedPlayCardItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// A unique identifier for this card.
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public Guid ID { get; set; } = Guid.NewGuid();
|
||||
|
||||
public bool Equals(RankedPlayCardItem? other)
|
||||
=> other != null && ID.Equals(other.ID);
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is RankedPlayCardItem other && Equals(other);
|
||||
|
||||
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ID.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// 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.Collections.Generic;
|
||||
using MessagePack;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public class RankedPlayRoomState : MatchRoomState
|
||||
{
|
||||
/// <summary>
|
||||
/// The current room stage.
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public RankedPlayStage Stage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current round number (1-based).
|
||||
/// </summary>
|
||||
[Key(1)]
|
||||
public int CurrentRound { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A multiplier applied to life point damage.
|
||||
/// </summary>
|
||||
[Key(2)]
|
||||
public double DamageMultiplier { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A dictionary containing all users in the room.
|
||||
/// </summary>
|
||||
[Key(3)]
|
||||
public Dictionary<int, RankedPlayUserInfo> Users { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the user currently playing a card.
|
||||
/// </summary>
|
||||
[Key(4)]
|
||||
public int ActiveUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The average star rating of all cards.
|
||||
/// </summary>
|
||||
[Key(5)]
|
||||
public double StarRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The winner of the match.
|
||||
/// </summary>
|
||||
[Key(6)]
|
||||
public int? WinningUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user currently playing a card.
|
||||
/// </summary>
|
||||
[IgnoreMember]
|
||||
public RankedPlayUserInfo ActiveUser => Users[ActiveUserId];
|
||||
|
||||
[IgnoreMember]
|
||||
public RankedPlayUserInfo? WinningUser => WinningUserId == null ? null : Users[WinningUserId.Value];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// 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.
|
||||
|
||||
namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay
|
||||
{
|
||||
public enum RankedPlayStage
|
||||
{
|
||||
/// <summary>
|
||||
/// Waiting for clients to join.
|
||||
/// </summary>
|
||||
WaitForJoin,
|
||||
|
||||
/// <summary>
|
||||
/// Period of time before the round starts.
|
||||
/// </summary>
|
||||
RoundWarmup,
|
||||
|
||||
/// <summary>
|
||||
/// Users are discarding cards and drawing new ones.
|
||||
/// </summary>
|
||||
CardDiscard,
|
||||
|
||||
/// <summary>
|
||||
/// Users have finished discarding their cards.
|
||||
/// </summary>
|
||||
FinishCardDiscard,
|
||||
|
||||
/// <summary>
|
||||
/// The active user is selecting a card to play.
|
||||
/// </summary>
|
||||
CardPlay,
|
||||
|
||||
/// <summary>
|
||||
/// The active user has made a selection, both players should now start downloading it.
|
||||
/// </summary>
|
||||
FinishCardPlay,
|
||||
|
||||
/// <summary>
|
||||
/// Period of time before gameplay starts.
|
||||
/// </summary>
|
||||
GameplayWarmup,
|
||||
|
||||
/// <summary>
|
||||
/// Gameplay is in progress.
|
||||
/// </summary>
|
||||
Gameplay,
|
||||
|
||||
/// <summary>
|
||||
/// Users are viewing the gameplay results
|
||||
/// </summary>
|
||||
Results,
|
||||
|
||||
/// <summary>
|
||||
/// The match has concluded.
|
||||
/// </summary>
|
||||
Ended
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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.Collections.Generic;
|
||||
using MessagePack;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer.MatchTypes.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public class RankedPlayUserInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// This user's matchmaking rating.
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public required int Rating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current life points.
|
||||
/// </summary>
|
||||
[Key(1)]
|
||||
public int Life { get; set; } = 1_000_000;
|
||||
|
||||
/// <summary>
|
||||
/// The cards in this user's hand.
|
||||
/// </summary>
|
||||
[Key(2)]
|
||||
public List<RankedPlayCardItem> Hand { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Rating after conclusion of the match.
|
||||
/// </summary>
|
||||
[Key(3)]
|
||||
public int RatingAfter { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using MessagePack;
|
||||
using osu.Game.Online.Matchmaking.Events;
|
||||
using osu.Game.Online.Multiplayer.Countdown;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
using osu.Game.Online.RankedPlay;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
@@ -19,6 +20,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
[Union(1, typeof(StartMatchCountdownRequest))]
|
||||
[Union(2, typeof(StopCountdownRequest))]
|
||||
[Union(3, typeof(MatchmakingAvatarActionRequest))]
|
||||
[Union(4, typeof(RankedPlayCardHandReplayRequest))]
|
||||
public abstract class MatchUserRequest
|
||||
{
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using MessagePack;
|
||||
using osu.Game.Online.Matchmaking;
|
||||
using osu.Game.Online.Multiplayer.Countdown;
|
||||
using osu.Game.Online.RankedPlay;
|
||||
|
||||
namespace osu.Game.Online.Multiplayer
|
||||
{
|
||||
@@ -16,6 +17,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
[Union(1, typeof(ForceGameplayStartCountdown))]
|
||||
[Union(2, typeof(ServerShuttingDownCountdown))]
|
||||
[Union(3, typeof(MatchmakingStageCountdown))]
|
||||
[Union(4, typeof(RankedPlayStageCountdown))]
|
||||
public abstract class MultiplayerCountdown
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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.Threading.Tasks;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
using osu.Game.Online.Rooms;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
public interface IRankedPlayClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a card has been added to a user's hand.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user whose hand has changed.</param>
|
||||
/// <param name="card">The card added to the user's hand.</param>
|
||||
Task RankedPlayCardAdded(int userId, RankedPlayCardItem card);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a card has been removed from a user's hand.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user whose hand has changed.</param>
|
||||
/// <param name="card">The card removed from the user's hand.</param>
|
||||
Task RankedPlayCardRemoved(int userId, RankedPlayCardItem card);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a card has been revealed to the local user.
|
||||
/// </summary>
|
||||
/// <param name="card">The card that was revealed.</param>
|
||||
/// <param name="item">The playlist item the card corresponds to.</param>
|
||||
Task RankedPlayCardRevealed(RankedPlayCardItem card, MultiplayerPlaylistItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a card was played.
|
||||
/// </summary>
|
||||
/// <param name="card">The card played.</param>
|
||||
Task RankedPlayCardPlayed(RankedPlayCardItem card);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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.Threading.Tasks;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
public interface IRankedPlayServer
|
||||
{
|
||||
Task DiscardCards(RankedPlayCardItem[] cards);
|
||||
|
||||
Task PlayCard(RankedPlayCardItem card);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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.Online.Multiplayer;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public class RankedPlayCardHandReplayEvent : MatchServerEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// The user performing the action.
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Key(1)]
|
||||
public required RankedPlayCardHandReplayFrame[] Frames { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MessagePack;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public readonly record struct RankedPlayCardHandReplayFrame
|
||||
{
|
||||
/// <summary>
|
||||
/// Duration in milliseconds since the previous frame.
|
||||
/// </summary>
|
||||
[Key(0)]
|
||||
public required double Delay { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary containing the state of each card.
|
||||
/// </summary>
|
||||
[Key(1)]
|
||||
public required Dictionary<Guid, RankedPlayCardState> Cards { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a replay frame that only contains state entries that differ from the previous frame
|
||||
/// </summary>
|
||||
public RankedPlayCardHandReplayFrame RelativeTo(RankedPlayCardHandReplayFrame other) => this with
|
||||
{
|
||||
Cards = Cards.Where(entry => !other.Cards.Contains(entry)).ToDictionary(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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.Online.Multiplayer;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public class RankedPlayCardHandReplayRequest : MatchUserRequest
|
||||
{
|
||||
[Key(0)]
|
||||
public required RankedPlayCardHandReplayFrame[] Frames { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
[Serializable]
|
||||
[MessagePackObject]
|
||||
public readonly record struct RankedPlayCardState
|
||||
{
|
||||
[Key(0)]
|
||||
public required bool Hovered { get; init; }
|
||||
|
||||
[Key(1)]
|
||||
public required bool Pressed { get; init; }
|
||||
|
||||
[Key(2)]
|
||||
public required bool Selected { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// 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 MessagePack;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
|
||||
namespace osu.Game.Online.RankedPlay
|
||||
{
|
||||
[MessagePackObject]
|
||||
public class RankedPlayStageCountdown : MultiplayerCountdown
|
||||
{
|
||||
[Key(2)]
|
||||
public RankedPlayStage Stage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,9 @@ using osu.Game.Online.Matchmaking.Events;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Online.Multiplayer.Countdown;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.Matchmaking;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.RankedPlay;
|
||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||
using osu.Game.Online.RankedPlay;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Online
|
||||
@@ -57,6 +59,12 @@ namespace osu.Game.Online
|
||||
(typeof(MatchmakingStageCountdown), typeof(MultiplayerCountdown)),
|
||||
(typeof(MatchmakingAvatarActionRequest), typeof(MatchUserRequest)),
|
||||
(typeof(MatchmakingAvatarActionEvent), typeof(MatchServerEvent)),
|
||||
|
||||
// ranked play
|
||||
(typeof(RankedPlayRoomState), typeof(MatchRoomState)),
|
||||
(typeof(RankedPlayStageCountdown), typeof(MultiplayerCountdown)),
|
||||
(typeof(RankedPlayCardHandReplayRequest), typeof(MatchUserRequest)),
|
||||
(typeof(RankedPlayCardHandReplayEvent), typeof(MatchServerEvent)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user