RealtimeMultiplayer -> Multiplayer

This commit is contained in:
Dean Herbert
2020-12-25 13:38:11 +09:00
parent 12e4bbdc5b
commit 5d4b73baa5
127 changed files with 260 additions and 265 deletions

View File

@ -0,0 +1,50 @@
// 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 NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge.Components;
namespace osu.Game.Tests.Visual.Multiplayer
{
public abstract class MultiplayerTestScene : RoomTestScene
{
[Cached(typeof(StatefulMultiplayerClient))]
public TestMultiplayerClient Client { get; }
[Cached(typeof(IRoomManager))]
public TestMultiplayerRoomManager RoomManager { get; }
[Cached]
public Bindable<FilterCriteria> Filter { get; }
protected override Container<Drawable> Content => content;
private readonly TestMultiplayerRoomContainer content;
private readonly bool joinRoom;
protected MultiplayerTestScene(bool joinRoom = true)
{
this.joinRoom = joinRoom;
base.Content.Add(content = new TestMultiplayerRoomContainer { RelativeSizeAxes = Axes.Both });
Client = content.Client;
RoomManager = content.RoomManager;
Filter = content.Filter;
}
[SetUp]
public new void Setup() => Schedule(() =>
{
RoomManager.Schedule(() => RoomManager.PartRoom());
if (joinRoom)
RoomManager.Schedule(() => RoomManager.CreateRoom(Room));
});
}
}

View File

@ -0,0 +1,119 @@
// 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.
#nullable enable
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestMultiplayerClient : StatefulMultiplayerClient
{
public override IBindable<bool> IsConnected => isConnected;
private readonly Bindable<bool> isConnected = new Bindable<bool>(true);
[Resolved]
private IAPIProvider api { get; set; } = null!;
public void Connect() => isConnected.Value = true;
public void Disconnect() => isConnected.Value = false;
public void AddUser(User user) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(user.Id) { User = user });
public void RemoveUser(User user)
{
Debug.Assert(Room != null);
((IMultiplayerClient)this).UserLeft(new MultiplayerRoomUser(user.Id));
Schedule(() =>
{
if (Room.Users.Any())
TransferHost(Room.Users.First().UserID);
});
}
public void ChangeUserState(int userId, MultiplayerUserState newState)
{
Debug.Assert(Room != null);
((IMultiplayerClient)this).UserStateChanged(userId, newState);
Schedule(() =>
{
switch (newState)
{
case MultiplayerUserState.Loaded:
if (Room.Users.All(u => u.State != MultiplayerUserState.WaitingForLoad))
{
foreach (var u in Room.Users.Where(u => u.State == MultiplayerUserState.Loaded))
ChangeUserState(u.UserID, MultiplayerUserState.Playing);
((IMultiplayerClient)this).MatchStarted();
}
break;
case MultiplayerUserState.FinishedPlay:
if (Room.Users.All(u => u.State != MultiplayerUserState.Playing))
{
foreach (var u in Room.Users.Where(u => u.State == MultiplayerUserState.FinishedPlay))
ChangeUserState(u.UserID, MultiplayerUserState.Results);
((IMultiplayerClient)this).ResultsReady();
}
break;
}
});
}
protected override Task<MultiplayerRoom> JoinRoom(long roomId)
{
var user = new MultiplayerRoomUser(api.LocalUser.Value.Id) { User = api.LocalUser.Value };
var room = new MultiplayerRoom(roomId);
room.Users.Add(user);
if (room.Users.Count == 1)
room.Host = user;
return Task.FromResult(room);
}
public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId);
public override async Task ChangeSettings(MultiplayerRoomSettings settings)
{
Debug.Assert(Room != null);
await ((IMultiplayerClient)this).SettingsChanged(settings);
foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready))
ChangeUserState(user.UserID, MultiplayerUserState.Idle);
}
public override Task ChangeState(MultiplayerUserState newState)
{
ChangeUserState(api.LocalUser.Value.Id, newState);
return Task.CompletedTask;
}
public override Task StartMatch()
{
Debug.Assert(Room != null);
foreach (var user in Room.Users.Where(u => u.State == MultiplayerUserState.Ready))
ChangeUserState(user.UserID, MultiplayerUserState.WaitingForLoad);
return ((IMultiplayerClient)this).LoadRequested();
}
}
}

View File

@ -0,0 +1,40 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge.Components;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestMultiplayerRoomContainer : Container
{
protected override Container<Drawable> Content => content;
private readonly Container content;
[Cached(typeof(StatefulMultiplayerClient))]
public readonly TestMultiplayerClient Client;
[Cached(typeof(IRoomManager))]
public readonly TestMultiplayerRoomManager RoomManager;
[Cached]
public readonly Bindable<FilterCriteria> Filter = new Bindable<FilterCriteria>(new FilterCriteria());
public TestMultiplayerRoomContainer()
{
RelativeSizeAxes = Axes.Both;
AddRangeInternal(new Drawable[]
{
Client = new TestMultiplayerClient(),
RoomManager = new TestMultiplayerRoomManager(),
content = new Container { RelativeSizeAxes = Axes.Both }
});
}
}
}

View File

@ -0,0 +1,116 @@
// 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.Framework.Bindables;
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.Multi.Lounge.Components;
using osu.Game.Screens.Multi.Multiplayer;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestMultiplayerRoomManager : MultiplayerRoomManager
{
[Resolved]
private IAPIProvider api { get; set; }
[Resolved]
private OsuGameBase game { get; set; }
[Cached]
public readonly Bindable<FilterCriteria> Filter = new Bindable<FilterCriteria>(new FilterCriteria());
private readonly List<Room> rooms = new List<Room>();
protected override void LoadComplete()
{
base.LoadComplete();
int currentScoreId = 0;
int currentRoomId = 0;
((DummyAPIAccess)api).HandleRequest = req =>
{
switch (req)
{
case CreateRoomRequest createRoomRequest:
var createdRoom = new APICreatedRoom();
createdRoom.CopyFrom(createRoomRequest.Room);
createdRoom.RoomID.Value ??= currentRoomId++;
rooms.Add(createdRoom);
createRoomRequest.TriggerSuccess(createdRoom);
break;
case JoinRoomRequest joinRoomRequest:
joinRoomRequest.TriggerSuccess();
break;
case PartRoomRequest partRoomRequest:
partRoomRequest.TriggerSuccess();
break;
case GetRoomsRequest getRoomsRequest:
var roomsWithoutParticipants = new List<Room>();
foreach (var r in rooms)
{
var newRoom = new Room();
newRoom.CopyFrom(r);
newRoom.RecentParticipants.Clear();
roomsWithoutParticipants.Add(newRoom);
}
getRoomsRequest.TriggerSuccess(roomsWithoutParticipants);
break;
case GetRoomRequest getRoomRequest:
getRoomRequest.TriggerSuccess(rooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId));
break;
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);
break;
case CreateRoomScoreRequest createRoomScoreRequest:
createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 });
break;
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>()
});
break;
}
};
}
public new void ClearRooms() => base.ClearRooms();
public new void Schedule(Action action) => base.Schedule(action);
}
}