mirror of
https://github.com/ppy/osu.git
synced 2026-05-28 20:40:46 +08:00
Merge branch 'master' into remove-selectedroom
This commit is contained in:
@@ -171,6 +171,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != firstDifficultyName;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("created difficulty has timing point", () =>
|
||||
{
|
||||
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPoints.Single();
|
||||
@@ -215,6 +217,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != previousDifficultyName;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = previousDifficultyName = Guid.NewGuid().ToString());
|
||||
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
||||
AddStep("add effect points", () =>
|
||||
@@ -239,6 +243,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != previousDifficultyName;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("created difficulty has timing point", () =>
|
||||
{
|
||||
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPoints.Single();
|
||||
@@ -287,6 +293,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != firstDifficultyName;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("created difficulty has timing point", () =>
|
||||
{
|
||||
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPoints.Single();
|
||||
@@ -367,6 +375,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != originalDifficultyName;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("created difficulty has copy suffix in name", () => EditorBeatmap.BeatmapInfo.DifficultyName == copyDifficultyName);
|
||||
AddAssert("created difficulty has timing point", () =>
|
||||
{
|
||||
@@ -377,7 +387,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
|
||||
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
|
||||
|
||||
ensureEditorLoaded();
|
||||
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
|
||||
|
||||
AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1);
|
||||
|
||||
AddStep("save beatmap", () => Editor.Save());
|
||||
@@ -440,6 +452,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != originalDifficultyName;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddStep("save without changes", () => Editor.Save());
|
||||
|
||||
AddAssert("collection still points to old beatmap", () => !collection.BeatmapMD5Hashes.Contains(EditorBeatmap.BeatmapInfo.MD5Hash)
|
||||
@@ -477,6 +491,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
|
||||
return difficultyName != null && difficultyName != "New Difficulty";
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("new difficulty has correct name", () => EditorBeatmap.BeatmapInfo.DifficultyName == "New Difficulty (1)");
|
||||
AddAssert("new difficulty persisted", () =>
|
||||
{
|
||||
@@ -514,6 +531,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return difficultyName != null && difficultyName != duplicate_difficulty_name;
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddStep("set difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = duplicate_difficulty_name);
|
||||
AddStep("try to save beatmap", () => Editor.Save());
|
||||
AddAssert("beatmap set not corrupted", () =>
|
||||
@@ -540,6 +559,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
return set != null && set.PerformRead(s => s.Beatmaps.Count == 1 && s.Files.Count == 1);
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddStep("create new difficulty", () => Editor.CreateNewDifficulty(new CatchRuleset().RulesetInfo));
|
||||
|
||||
AddUntilStep("wait for created", () =>
|
||||
@@ -547,7 +568,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
|
||||
return difficultyName != null && difficultyName != duplicate_difficulty_name;
|
||||
});
|
||||
AddUntilStep("wait for editor load", () => Editor.IsLoaded && DialogOverlay.IsLoaded);
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
|
||||
{
|
||||
@@ -584,6 +606,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
|
||||
return difficultyName != null && difficultyName == "New Difficulty";
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("new difficulty persisted", () =>
|
||||
{
|
||||
var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId);
|
||||
@@ -610,6 +635,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
|
||||
return difficultyName != null && difficultyName == "New Difficulty (1)";
|
||||
});
|
||||
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddAssert("new difficulty persisted", () =>
|
||||
{
|
||||
var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId);
|
||||
@@ -735,6 +763,8 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddAssert("other audio not removed", () => Beatmap.Value.BeatmapSetInfo.Files.Any(f => f.Filename == "audio (1).mp3"));
|
||||
}
|
||||
|
||||
private void ensureEditorLoaded() => AddUntilStep("wait for editor load", () => Editor.IsLoaded && DialogOverlay.IsLoaded);
|
||||
|
||||
private void createNewDifficulty()
|
||||
{
|
||||
string? currentDifficulty = null;
|
||||
@@ -748,13 +778,14 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog is CreateNewDifficultyDialog);
|
||||
AddStep("confirm creation with no objects", () => DialogOverlay.CurrentDialog!.PerformOkAction());
|
||||
|
||||
AddUntilStep("wait for created", () =>
|
||||
{
|
||||
string? difficultyName = Editor.ChildrenOfType<EditorBeatmap>().SingleOrDefault()?.BeatmapInfo.DifficultyName;
|
||||
return difficultyName != null && difficultyName != currentDifficulty;
|
||||
});
|
||||
ensureEditorLoaded();
|
||||
|
||||
AddUntilStep("wait for editor load", () => Editor.IsLoaded);
|
||||
AddStep("enter setup mode", () => Editor.Mode.Value = EditorScreenMode.SongSetup);
|
||||
AddUntilStep("wait for load", () => Editor.ChildrenOfType<SetupScreen>().Any());
|
||||
}
|
||||
@@ -765,7 +796,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
AddStep($"switch to difficulty #{index + 1}", () =>
|
||||
Editor.SwitchToDifficulty(Beatmap.Value.BeatmapSetInfo.Beatmaps.ElementAt(index)));
|
||||
|
||||
AddUntilStep("wait for editor load", () => Editor.IsLoaded);
|
||||
ensureEditorLoaded();
|
||||
AddStep("enter setup mode", () => Editor.Mode.Value = EditorScreenMode.SongSetup);
|
||||
AddUntilStep("wait for load", () => Editor.ChildrenOfType<SetupScreen>().Any());
|
||||
}
|
||||
|
||||
@@ -319,11 +319,13 @@ namespace osu.Game.Beatmaps.Formats
|
||||
SampleControlPoint createSampleControlPointFor(double time, IList<HitSampleInfo> samples)
|
||||
{
|
||||
int volume = samples.Max(o => o.Volume);
|
||||
string bank = samples.Where(s => s.Name == HitSampleInfo.HIT_NORMAL).Select(s => s.Bank).FirstOrDefault()
|
||||
?? samples.Select(s => s.Bank).First();
|
||||
int customIndex = samples.Any(o => o is ConvertHitObjectParser.LegacyHitSampleInfo)
|
||||
? samples.OfType<ConvertHitObjectParser.LegacyHitSampleInfo>().Max(o => o.CustomSampleBank)
|
||||
: -1;
|
||||
|
||||
return new LegacyBeatmapDecoder.LegacySampleControlPoint { Time = time, SampleVolume = volume, CustomSampleBank = customIndex };
|
||||
return new LegacyBeatmapDecoder.LegacySampleControlPoint { Time = time, SampleVolume = volume, SampleBank = bank, CustomSampleBank = customIndex };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -487,18 +487,44 @@ namespace osu.Game.Online.Multiplayer
|
||||
}, false);
|
||||
}
|
||||
|
||||
Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user) =>
|
||||
handleUserLeft(user, UserLeft);
|
||||
Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user)
|
||||
{
|
||||
Scheduler.Add(() => handleUserLeft(user, UserLeft), false);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Task IMultiplayerClient.UserKicked(MultiplayerRoomUser user)
|
||||
{
|
||||
if (LocalUser == null)
|
||||
return Task.CompletedTask;
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
if (LocalUser == null)
|
||||
return;
|
||||
|
||||
if (user.Equals(LocalUser))
|
||||
LeaveRoom();
|
||||
if (user.Equals(LocalUser))
|
||||
LeaveRoom();
|
||||
|
||||
return handleUserLeft(user, UserKicked);
|
||||
handleUserLeft(user, UserKicked);
|
||||
}, false);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void handleUserLeft(MultiplayerRoomUser user, Action<MultiplayerRoomUser>? callback)
|
||||
{
|
||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||
|
||||
if (Room == null)
|
||||
return;
|
||||
|
||||
Room.Users.Remove(user);
|
||||
PlayingUserIds.Remove(user.UserID);
|
||||
|
||||
Debug.Assert(APIRoom != null);
|
||||
APIRoom.RecentParticipants = APIRoom.RecentParticipants.Where(u => u.Id != user.UserID).ToArray();
|
||||
APIRoom.ParticipantCount--;
|
||||
|
||||
callback?.Invoke(user);
|
||||
RoomUpdated?.Invoke();
|
||||
}
|
||||
|
||||
async Task IMultiplayerClient.Invited(int invitedBy, long roomID, string password)
|
||||
@@ -545,27 +571,6 @@ namespace osu.Game.Online.Multiplayer
|
||||
APIRoom.ParticipantCount++;
|
||||
}
|
||||
|
||||
private Task handleUserLeft(MultiplayerRoomUser user, Action<MultiplayerRoomUser>? callback)
|
||||
{
|
||||
Scheduler.Add(() =>
|
||||
{
|
||||
if (Room == null)
|
||||
return;
|
||||
|
||||
Room.Users.Remove(user);
|
||||
PlayingUserIds.Remove(user.UserID);
|
||||
|
||||
Debug.Assert(APIRoom != null);
|
||||
APIRoom.RecentParticipants = APIRoom.RecentParticipants.Where(u => u.Id != user.UserID).ToArray();
|
||||
APIRoom.ParticipantCount--;
|
||||
|
||||
callback?.Invoke(user);
|
||||
RoomUpdated?.Invoke();
|
||||
}, false);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
Task IMultiplayerClient.HostChanged(int userId)
|
||||
{
|
||||
Scheduler.Add(() =>
|
||||
|
||||
@@ -45,14 +45,20 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
private readonly ScrollContainer<Drawable> scroll;
|
||||
private readonly FillFlowContainer<DrawableLoungeRoom> roomFlow;
|
||||
|
||||
private const float display_scale = 0.8f;
|
||||
|
||||
// handle deselection
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
public RoomListing()
|
||||
{
|
||||
InternalChild = scroll = new OsuScrollContainer
|
||||
InternalChild = scroll = new Scroll
|
||||
{
|
||||
Masking = false,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = display_scale,
|
||||
ScrollbarOverlapsContent = false,
|
||||
Padding = new MarginPadding { Right = 5 },
|
||||
Child = new OsuContextMenuContainer
|
||||
@@ -64,12 +70,18 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(10),
|
||||
Spacing = new Vector2(5),
|
||||
Margin = new MarginPadding { Vertical = 10 },
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private partial class Scroll : OsuScrollContainer
|
||||
{
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
SelectedRoom.BindValueChanged(onSelectedRoomChanged, true);
|
||||
@@ -171,7 +183,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
|
||||
{
|
||||
foreach (var room in rooms)
|
||||
{
|
||||
var drawableRoom = new DrawableLoungeRoom(room) { SelectedRoom = selectedRoom };
|
||||
var drawableRoom = new DrawableLoungeRoom(room)
|
||||
{
|
||||
SelectedRoom = selectedRoom,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(display_scale),
|
||||
Width = 1 / display_scale,
|
||||
};
|
||||
|
||||
roomFlow.Add(drawableRoom);
|
||||
|
||||
|
||||
@@ -8,9 +8,12 @@ using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Logging;
|
||||
@@ -27,6 +30,7 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components;
|
||||
using osu.Game.Screens.OnlinePlay.Match;
|
||||
using osu.Game.Users;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
{
|
||||
@@ -85,11 +89,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load()
|
||||
{
|
||||
Masking = true;
|
||||
|
||||
const float controls_area_height = 25f;
|
||||
|
||||
if (idleTracker != null)
|
||||
isIdle.BindTo(idleTracker.IsIdle);
|
||||
|
||||
Color4 bg = Color4Extensions.FromHex("#070405");
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
listingPoller = new LoungeListingPoller
|
||||
@@ -113,56 +121,80 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
||||
}
|
||||
},
|
||||
loadingLayer = new LoadingLayer(true),
|
||||
new FillFlowContainer
|
||||
new Container
|
||||
{
|
||||
Name = @"Header area flow",
|
||||
Name = "Header area",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = Header.HEIGHT,
|
||||
Child = searchTextBox = new BasicSearchTextBox
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.6f,
|
||||
},
|
||||
Colour = ColourInfo.GradientVertical(bg, bg.Opacity(0.75f)),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.8f,
|
||||
},
|
||||
new Container
|
||||
new Box
|
||||
{
|
||||
Colour = ColourInfo.GradientVertical(bg.Opacity(0.75f), bg.Opacity(0)),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Y = 0.8f,
|
||||
// Intentionally taller than the header for a more gradual fade
|
||||
Height = 0.5f,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
Name = @"Header area flow",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = controls_area_height,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
||||
new Container
|
||||
{
|
||||
d.Anchor = Anchor.BottomLeft;
|
||||
d.Origin = Anchor.BottomLeft;
|
||||
d.Size = new Vector2(150, 37.5f);
|
||||
d.Action = () => Open();
|
||||
})),
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10),
|
||||
ChildrenEnumerable = CreateFilterControls().Select(f => f.With(d =>
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = Header.HEIGHT,
|
||||
Child = searchTextBox = new BasicSearchTextBox
|
||||
{
|
||||
d.Anchor = Anchor.TopRight;
|
||||
d.Origin = Anchor.TopRight;
|
||||
}))
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.6f,
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = controls_area_height,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Buttons.WithChild(CreateNewRoomButton().With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.BottomLeft;
|
||||
d.Origin = Anchor.BottomLeft;
|
||||
d.Size = new Vector2(150, 37.5f);
|
||||
d.Action = () => Open();
|
||||
})),
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10),
|
||||
ChildrenEnumerable = CreateFilterControls().Select(f => f.With(d =>
|
||||
{
|
||||
d.Anchor = Anchor.TopRight;
|
||||
d.Origin = Anchor.TopRight;
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,11 +28,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
|
||||
private void onRoomUpdated()
|
||||
{
|
||||
if (client.Room == null)
|
||||
if (client.Room == null || client.LocalUser == null)
|
||||
return;
|
||||
|
||||
Debug.Assert(client.LocalUser != null);
|
||||
|
||||
// If the user exits gameplay before score submission completes, we'll transition to idle when results has been prepared.
|
||||
if (client.LocalUser.State == MultiplayerUserState.Results && this.IsCurrentScreen())
|
||||
transitionFromResults();
|
||||
@@ -62,11 +60,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
||||
{
|
||||
base.OnResuming(e);
|
||||
|
||||
if (client.Room == null)
|
||||
if (client.Room == null || client.LocalUser == null)
|
||||
return;
|
||||
|
||||
Debug.Assert(client.LocalUser != null);
|
||||
|
||||
if (!(e.Last is MultiplayerPlayerLoader playerLoader))
|
||||
return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user