1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-16 04:27:52 +08:00
osu-lazer/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

299 lines
12 KiB
C#
Raw Normal View History

// 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.
2022-06-17 15:37:17 +08:00
#nullable disable
using System;
using System.Collections.Generic;
2022-06-03 20:12:09 +08:00
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json;
using osu.Game.Beatmaps;
2024-08-01 17:52:41 +08:00
using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Beatmaps;
using osu.Game.Utils;
namespace osu.Game.Tests.Visual.OnlinePlay
{
/// <summary>
/// Represents a handler which pretends to be a server, handling room retrieval and manipulation requests
/// and returning a roughly expected state, without the need for a server to be running.
/// </summary>
public class TestRoomRequestsHandler
{
public IReadOnlyList<Room> ServerSideRooms => serverSideRooms;
private readonly List<Room> serverSideRooms = new List<Room>();
2021-12-01 19:00:31 +08:00
private int currentRoomId = 1;
private int currentPlaylistItemId = 1;
private int currentScoreId = 1;
/// <summary>
/// Handles an API request, while also updating the local state to match
/// how the server would eventually respond and update an <see cref="RoomManager"/>.
/// </summary>
/// <param name="request">The API request to handle.</param>
/// <param name="localUser">The local user to store in responses where required.</param>
/// <param name="beatmapManager">The beatmap manager to attempt to retrieve beatmaps from, prior to returning dummy beatmaps.</param>
/// <returns>Whether the request was successfully handled.</returns>
public bool HandleRequest(APIRequest request, APIUser localUser, BeatmapManager beatmapManager)
{
switch (request)
{
case CreateRoomRequest createRoomRequest:
var apiRoom = cloneRoom(createRoomRequest.Room);
// Passwords are explicitly not copied between rooms.
apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value);
apiRoom.Password.Value = createRoomRequest.Room.Password.Value;
2021-11-26 16:23:50 +08:00
AddServerSideRoom(apiRoom, localUser);
var responseRoom = new APICreatedRoom();
responseRoom.CopyFrom(createResponseRoom(apiRoom, false));
createRoomRequest.TriggerSuccess(responseRoom);
return true;
case JoinRoomRequest joinRoomRequest:
{
var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value);
if (joinRoomRequest.Password != room.Password.Value)
{
joinRoomRequest.TriggerFailure(new InvalidOperationException("Invalid password."));
return true;
}
joinRoomRequest.TriggerSuccess();
return true;
}
case GetRoomLeaderboardRequest roomLeaderboardRequest:
roomLeaderboardRequest.TriggerSuccess(new APILeaderboard
{
Leaderboard = new List<APIUserScoreAggregate>
{
new APIUserScoreAggregate
{
TotalScore = 1000000,
TotalAttempts = 5,
CompletedBeatmaps = 2,
User = new APIUser { Username = "best user" }
},
new APIUserScoreAggregate
{
TotalScore = 50,
TotalAttempts = 1,
CompletedBeatmaps = 1,
User = new APIUser { Username = "worst user" }
}
}
});
return true;
case IndexPlaylistScoresRequest roomLeaderboardRequest:
roomLeaderboardRequest.TriggerSuccess(new IndexedMultiplayerScores
{
Scores =
{
new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 1,
Position = 1,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.S,
MaxCombo = 1000,
TotalScore = 1000000,
User = new APIUser { Username = "best user" },
2024-07-29 16:45:03 +08:00
Mods = [new APIMod { Acronym = @"DT" }],
Statistics = new Dictionary<HitResult, int>()
},
new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 0.7,
Position = 2,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.B,
MaxCombo = 100,
TotalScore = 200000,
User = new APIUser { Username = "worst user" },
Statistics = new Dictionary<HitResult, int>()
},
},
UserScore = new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 0.91,
Position = 4,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.A,
MaxCombo = 100,
TotalScore = 800000,
User = localUser,
Statistics = new Dictionary<HitResult, int>()
},
});
return true;
case PartRoomRequest partRoomRequest:
partRoomRequest.TriggerSuccess();
return true;
case GetRoomsRequest getRoomsRequest:
var roomsWithoutParticipants = new List<Room>();
foreach (var r in ServerSideRooms)
roomsWithoutParticipants.Add(createResponseRoom(r, false));
getRoomsRequest.TriggerSuccess(roomsWithoutParticipants);
return true;
case GetRoomRequest getRoomRequest:
getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true));
return true;
case CreateRoomScoreRequest createRoomScoreRequest:
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
return true;
case SubmitRoomScoreRequest submitRoomScoreRequest:
submitRoomScoreRequest.TriggerSuccess(new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 1,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.S,
MaxCombo = 1000,
TotalScore = 1000000,
User = localUser,
Statistics = new Dictionary<HitResult, int>()
});
return true;
case GetBeatmapRequest getBeatmapRequest:
{
getBeatmapRequest.TriggerSuccess(createResponseBeatmaps(getBeatmapRequest.BeatmapInfo.OnlineID).Single());
return true;
}
case GetBeatmapsRequest getBeatmapsRequest:
{
getBeatmapsRequest.TriggerSuccess(new GetBeatmapsResponse { Beatmaps = createResponseBeatmaps(getBeatmapsRequest.BeatmapIds.ToArray()) });
return true;
}
case GetBeatmapSetRequest getBeatmapSetRequest:
{
2024-08-01 17:52:41 +08:00
var baseBeatmap = getBeatmapSetRequest.Type == BeatmapSetLookupType.BeatmapId
? beatmapManager.QueryBeatmap(b => b.OnlineID == getBeatmapSetRequest.ID)
: beatmapManager.QueryBeatmapSet(s => s.OnlineID == getBeatmapSetRequest.ID)?.PerformRead(s => s.Beatmaps.First().Detach());
if (baseBeatmap == null)
{
baseBeatmap = new TestBeatmap(new RulesetInfo { OnlineID = 0 }).BeatmapInfo;
baseBeatmap.OnlineID = getBeatmapSetRequest.ID;
baseBeatmap.BeatmapSet!.OnlineID = getBeatmapSetRequest.ID;
}
getBeatmapSetRequest.TriggerSuccess(OsuTestScene.CreateAPIBeatmapSet(baseBeatmap));
return true;
}
}
List<APIBeatmap> createResponseBeatmaps(params int[] beatmapIds)
{
var result = new List<APIBeatmap>();
foreach (int id in beatmapIds)
{
var baseBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineID == id);
if (baseBeatmap == null)
{
baseBeatmap = new TestBeatmap(new RulesetInfo { OnlineID = 0 }).BeatmapInfo;
baseBeatmap.OnlineID = id;
baseBeatmap.BeatmapSet!.OnlineID = id;
}
result.Add(OsuTestScene.CreateAPIBeatmap(baseBeatmap));
}
return result;
}
return false;
}
/// <summary>
/// Adds a room to a local "server-side" list that's returned when a <see cref="GetRoomsRequest"/> is fired.
/// </summary>
/// <param name="room">The room.</param>
2021-11-26 16:23:50 +08:00
/// <param name="host">The room host.</param>
public void AddServerSideRoom(Room room, APIUser host)
{
room.RoomID.Value ??= currentRoomId++;
2021-11-26 16:23:50 +08:00
room.Host.Value = host;
2021-11-25 21:17:18 +08:00
for (int i = 0; i < room.Playlist.Count; i++)
2021-11-25 21:17:18 +08:00
{
room.Playlist[i].ID = currentPlaylistItemId++;
2021-11-25 21:17:18 +08:00
room.Playlist[i].OwnerID = room.Host.Value.OnlineID;
}
serverSideRooms.Add(room);
}
private Room createResponseRoom(Room room, bool withParticipants)
{
var responseRoom = cloneRoom(room);
// Password is hidden from the response, and is only propagated via HasPassword.
bool hadPassword = responseRoom.HasPassword.Value;
responseRoom.Password.Value = null;
responseRoom.HasPassword.Value = hadPassword;
if (!withParticipants)
responseRoom.RecentParticipants.Clear();
return responseRoom;
}
2022-06-03 20:12:09 +08:00
private Room cloneRoom(Room source)
{
var result = JsonConvert.DeserializeObject<Room>(JsonConvert.SerializeObject(source));
Debug.Assert(result != null);
// Playlist item IDs and beatmaps aren't serialised.
2022-06-03 20:12:09 +08:00
if (source.CurrentPlaylistItem.Value != null)
{
result.CurrentPlaylistItem.Value = result.CurrentPlaylistItem.Value.With(new Optional<IBeatmapInfo>(source.CurrentPlaylistItem.Value.Beatmap));
2022-06-03 20:12:09 +08:00
result.CurrentPlaylistItem.Value.ID = source.CurrentPlaylistItem.Value.ID;
}
2022-06-03 20:12:09 +08:00
for (int i = 0; i < source.Playlist.Count; i++)
{
result.Playlist[i] = result.Playlist[i].With(new Optional<IBeatmapInfo>(source.Playlist[i].Beatmap));
2022-06-03 20:12:09 +08:00
result.Playlist[i].ID = source.Playlist[i].ID;
}
2022-06-03 20:12:09 +08:00
return result;
}
}
}