1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 06:47:24 +08:00

Extract room request handling logic to its own class

This commit is contained in:
Salman Ahmed 2021-08-19 06:24:06 +03:00
parent 0e2f3dff4d
commit f4ae587a33
2 changed files with 159 additions and 126 deletions

View File

@ -1,150 +1,36 @@
// 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 osu.Framework.Allocation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Tests.Visual.OnlinePlay;
namespace osu.Game.Tests.Visual.Multiplayer
{
/// <summary>
/// A <see cref="RoomManager"/> for use in multiplayer test scenes. Should generally not be used by itself outside of a <see cref="MultiplayerTestScene"/>.
/// A <see cref="RoomManager"/> for use in multiplayer test scenes, backed by a <see cref="TestRoomRequestsHandler"/>.
/// Should generally not be used by itself outside of a <see cref="MultiplayerTestScene"/>.
/// </summary>
/// <remarks>
/// This implementation will pretend 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.
/// </remarks>
public class TestRequestHandlingMultiplayerRoomManager : MultiplayerRoomManager
{
[Resolved]
private IAPIProvider api { get; set; }
public IReadOnlyList<Room> ServerSideRooms => handler.ServerSideRooms;
[Resolved]
private OsuGameBase game { get; set; }
public IReadOnlyList<Room> ServerSideRooms => serverSideRooms;
private readonly List<Room> serverSideRooms = new List<Room>();
private int currentRoomId;
private int currentPlaylistItemId;
private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler();
[BackgroundDependencyLoader]
private void load()
private void load(IAPIProvider api, OsuGameBase game)
{
int currentScoreId = 0;
// Handling here is pretending to be a server, while also updating the local state to match
// how the server would eventually respond and update the RoomManager.
((DummyAPIAccess)api).HandleRequest = req =>
{
switch (req)
{
case CreateRoomRequest createRoomRequest:
var apiRoom = new Room();
apiRoom.CopyFrom(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;
AddServerSideRoom(apiRoom);
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 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 GetBeatmapSetRequest getBeatmapSetRequest:
var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type);
onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res);
onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e);
// Get the online API from the game's dependencies.
game.Dependencies.Get<IAPIProvider>().Queue(onlineReq);
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 = api.LocalUser.Value,
Statistics = new Dictionary<HitResult, int>()
});
return true;
}
return false;
};
((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game);
}
public void AddServerSideRoom(Room room)
{
room.RoomID.Value ??= currentRoomId++;
for (int i = 0; i < room.Playlist.Count; i++)
room.Playlist[i].ID = currentPlaylistItemId++;
serverSideRooms.Add(room);
}
private Room createResponseRoom(Room room, bool withParticipants)
{
var responseRoom = new Room();
responseRoom.CopyFrom(room);
responseRoom.Password.Value = null;
if (!withParticipants)
responseRoom.RecentParticipants.Clear();
return responseRoom;
}
/// <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>
public void AddServerSideRoom(Room room) => handler.AddServerSideRoom(room);
}
}

View File

@ -0,0 +1,147 @@
// 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 osu.Framework.Allocation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Users;
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>();
private int currentRoomId;
private int currentPlaylistItemId;
private int currentScoreId;
/// <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="game">The game base for cases where actual online requests need to be sent.</param>
/// <returns>Whether the request was successfully handled.</returns>
public bool HandleRequest(APIRequest request, User localUser, OsuGameBase game)
{
switch (request)
{
case CreateRoomRequest createRoomRequest:
var apiRoom = new Room();
apiRoom.CopyFrom(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;
AddServerSideRoom(apiRoom);
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 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 GetBeatmapSetRequest getBeatmapSetRequest:
var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type);
onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res);
onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e);
// Get the online API from the game's dependencies.
game.Dependencies.Get<IAPIProvider>().Queue(onlineReq);
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;
}
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>
public void AddServerSideRoom(Room room)
{
room.RoomID.Value ??= currentRoomId++;
for (int i = 0; i < room.Playlist.Count; i++)
room.Playlist[i].ID = currentPlaylistItemId++;
serverSideRooms.Add(room);
}
private Room createResponseRoom(Room room, bool withParticipants)
{
var responseRoom = new Room();
responseRoom.CopyFrom(room);
responseRoom.Password.Value = null;
if (!withParticipants)
responseRoom.RecentParticipants.Clear();
return responseRoom;
}
}
}