public async Task JoinRoom(Room room)
        {
            var cancellationSource = joinCancellationSource = new CancellationTokenSource();

            await joinOrLeaveTaskChain.Add(async() =>
            {
                if (Room != null)
                {
                    throw new InvalidOperationException("Cannot join a multiplayer room while already in one.");
                }

                Debug.Assert(room.RoomID.Value != null);

                // Join the server-side room.
                var joinedRoom = await JoinRoom(room.RoomID.Value.Value).ConfigureAwait(false);
                Debug.Assert(joinedRoom != null);

                // Populate users.
                Debug.Assert(joinedRoom.Users != null);
                await Task.WhenAll(joinedRoom.Users.Select(PopulateUser)).ConfigureAwait(false);

                // Update the stored room (must be done on update thread for thread-safety).
                await scheduleAsync(() =>
                {
                    Room    = joinedRoom;
                    apiRoom = room;
                    defaultPlaylistItemId = apiRoom.Playlist.FirstOrDefault()?.ID ?? 0;
                }, cancellationSource.Token).ConfigureAwait(false);

                // Update room settings.
                await updateLocalRoomSettings(joinedRoom.Settings, cancellationSource.Token).ConfigureAwait(false);
            }, cancellationSource.Token).ConfigureAwait(false);
        }
Example #2
0
        /// <summary>
        /// Joins the <see cref="MultiplayerRoom"/> for a given API <see cref="Room"/>.
        /// </summary>
        /// <param name="room">The API <see cref="Room"/>.</param>
        /// <param name="password">An optional password to use for the join operation.</param>
        public async Task JoinRoom(Room room, string?password = null)
        {
            if (Room != null)
            {
                throw new InvalidOperationException("Cannot join a multiplayer room while already in one.");
            }

            var cancellationSource = joinCancellationSource = new CancellationTokenSource();

            await joinOrLeaveTaskChain.Add(async() =>
            {
                Debug.Assert(room.RoomID.Value != null);

                // Join the server-side room.
                var joinedRoom = await JoinRoom(room.RoomID.Value.Value, password ?? room.Password.Value).ConfigureAwait(false);
                Debug.Assert(joinedRoom != null);

                // Populate users.
                Debug.Assert(joinedRoom.Users != null);
                await Task.WhenAll(joinedRoom.Users.Select(PopulateUser)).ConfigureAwait(false);

                // Update the stored room (must be done on update thread for thread-safety).
                await runOnUpdateThreadAsync(() =>
                {
                    Debug.Assert(Room == null);

                    Room    = joinedRoom;
                    APIRoom = room;

                    Debug.Assert(joinedRoom.Playlist.Count > 0);

                    APIRoom.Playlist.Clear();
                    APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(createPlaylistItem));
                    APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == joinedRoom.Settings.PlaylistItemId);

                    Debug.Assert(LocalUser != null);
                    addUserToAPIRoom(LocalUser);

                    foreach (var user in joinedRoom.Users)
                    {
                        updateUserPlayingState(user.UserID, user.State);
                    }

                    updateLocalRoomSettings(joinedRoom.Settings);

                    OnRoomJoined();
                }, cancellationSource.Token).ConfigureAwait(false);
            }, cancellationSource.Token).ConfigureAwait(false);
        }
Example #3
0
        public async Task TestChainedTaskDoesNotCompleteBeforeChildTasks()
        {
            var mutex = new ManualResetEventSlim(false);

            var task = taskChain.Add(async() => await Task.Run(() => mutex.Wait(globalCancellationToken.Token)));

            // Allow task to potentially complete
            Thread.Sleep(1000);

            Assert.That(task.IsCompleted, Is.False);

            // Allow the task to complete.
            mutex.Set();

            await task;
        }
Example #4
0
        public async Task JoinRoom(Room room, string?password = null)
        {
            var cancellationSource = joinCancellationSource = new CancellationTokenSource();

            await joinOrLeaveTaskChain.Add(async() =>
            {
                if (Room != null)
                {
                    throw new InvalidOperationException("Cannot join a multiplayer room while already in one.");
                }

                Debug.Assert(room.RoomID.Value != null);

                // Join the server-side room.
                var joinedRoom = await JoinRoom(room.RoomID.Value.Value, password ?? room.Password.Value).ConfigureAwait(false);
                Debug.Assert(joinedRoom != null);

                // Populate users.
                Debug.Assert(joinedRoom.Users != null);
                await Task.WhenAll(joinedRoom.Users.Select(PopulateUser)).ConfigureAwait(false);

                // Update the stored room (must be done on update thread for thread-safety).
                await scheduleAsync(() =>
                {
                    Room    = joinedRoom;
                    APIRoom = room;

                    Debug.Assert(LocalUser != null);
                    addUserToAPIRoom(LocalUser);

                    foreach (var user in joinedRoom.Users)
                    {
                        updateUserPlayingState(user.UserID, user.State);
                    }

                    OnRoomJoined();
                }, cancellationSource.Token).ConfigureAwait(false);

                // Update room settings.
                await updateLocalRoomSettings(joinedRoom.Settings, cancellationSource.Token).ConfigureAwait(false);
            }, cancellationSource.Token).ConfigureAwait(false);
        }