1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 09:07:25 +08:00

Merge branch 'master' into beatmapset-refactor

This commit is contained in:
Dan Balasescu 2021-01-21 12:38:34 +09:00 committed by GitHub
commit c3675293fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 154 additions and 29 deletions

View File

@ -17,10 +17,12 @@ using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI;
using osuTK;
using osuTK.Graphics;
@ -129,6 +131,31 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("no DHOs shown", () => !this.ChildrenOfType<DrawableTestHitObject>().Any());
}
[Test]
public void TestApplyHitResultOnKilled()
{
ManualClock clock = null;
bool anyJudged = false;
void onNewResult(JudgementResult _) => anyJudged = true;
var beatmap = new Beatmap();
beatmap.HitObjects.Add(new TestKilledHitObject { Duration = 20 });
createTest(beatmap, 10, () => new FramedClock(clock = new ManualClock()));
AddStep("subscribe to new result", () =>
{
anyJudged = false;
drawableRuleset.NewResult += onNewResult;
});
AddStep("skip past object", () => clock.CurrentTime = beatmap.HitObjects[0].GetEndTime() + 1000);
AddAssert("object judged", () => anyJudged);
AddStep("clean up", () => drawableRuleset.NewResult -= onNewResult);
}
private void createTest(IBeatmap beatmap, int poolSize, Func<IFrameBasedClock> createClock = null) => AddStep("create test", () =>
{
var ruleset = new TestPoolingRuleset();
@ -192,6 +219,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void load()
{
RegisterPool<TestHitObject, DrawableTestHitObject>(poolSize);
RegisterPool<TestKilledHitObject, DrawableTestKilledHitObject>(poolSize);
}
protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new TestHitObjectLifetimeEntry(hitObject);
@ -220,19 +248,30 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken)
{
yield return new TestHitObject
switch (original)
{
StartTime = original.StartTime,
Duration = 250
};
case TestKilledHitObject h:
yield return h;
break;
default:
yield return new TestHitObject
{
StartTime = original.StartTime,
Duration = 250
};
break;
}
}
}
#endregion
#region HitObject
#region HitObjects
private class TestHitObject : ConvertHitObject
private class TestHitObject : ConvertHitObject, IHasDuration
{
public double EndTime => StartTime + Duration;
@ -287,6 +326,30 @@ namespace osu.Game.Tests.Visual.Gameplay
}
}
private class TestKilledHitObject : TestHitObject
{
}
private class DrawableTestKilledHitObject : DrawableHitObject<TestKilledHitObject>
{
public DrawableTestKilledHitObject()
: base(null)
{
}
protected override void UpdateHitStateTransforms(ArmedState state)
{
base.UpdateHitStateTransforms(state);
Expire();
}
public override void OnKilled()
{
base.OnKilled();
ApplyResult(r => r.Type = r.Judgement.MinResult);
}
}
#endregion
}
}

View File

@ -11,12 +11,10 @@ using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Beatmaps;
using osu.Game.Users;
@ -85,8 +83,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("move mouse to create button", () =>
{
var footer = match.ChildrenOfType<Footer>().Single();
InputManager.MoveMouseTo(footer.ChildrenOfType<OsuButton>().Single());
InputManager.MoveMouseTo(this.ChildrenOfType<PlaylistsMatchSettingsOverlay.CreateRoomButton>().Single());
});
AddStep("click", () => InputManager.Click(MouseButton.Left));

View File

@ -327,6 +327,7 @@ namespace osu.Game
if (!SelectedMods.Disabled)
SelectedMods.Value = Array.Empty<Mod>();
AvailableMods.Value = dict;
}

View File

@ -30,6 +30,7 @@ namespace osu.Game.Overlays.Mods
{
public class ModSelectOverlay : WaveOverlayContainer
{
private readonly Func<Mod, bool> isValidMod;
public const float HEIGHT = 510;
protected readonly TriangleButton DeselectAllButton;
@ -60,8 +61,10 @@ namespace osu.Game.Overlays.Mods
private SampleChannel sampleOn, sampleOff;
public ModSelectOverlay()
public ModSelectOverlay(Func<Mod, bool> isValidMod = null)
{
this.isValidMod = isValidMod ?? (m => true);
Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2");
Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2");
Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774");
@ -403,7 +406,7 @@ namespace osu.Game.Overlays.Mods
if (mods.NewValue == null) return;
foreach (var section in ModSectionsContainer.Children)
section.Mods = mods.NewValue[section.ModType];
section.Mods = mods.NewValue[section.ModType].Where(isValidMod);
}
private void selectedModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)

View File

@ -38,6 +38,18 @@ namespace osu.Game.Overlays.Settings.Sections
private List<SkinInfo> skinItems;
private int firstNonDefaultSkinIndex
{
get
{
var index = skinItems.FindIndex(s => s.ID > 0);
if (index < 0)
index = skinItems.Count;
return index;
}
}
[Resolved]
private SkinManager skins { get; set; }
@ -112,21 +124,22 @@ namespace osu.Game.Overlays.Settings.Sections
private void updateItems()
{
skinItems = skins.GetAllUsableSkins();
// insert after lazer built-in skins
int firstNonDefault = skinItems.FindIndex(s => s.ID > 0);
if (firstNonDefault < 0)
firstNonDefault = skinItems.Count;
skinItems.Insert(firstNonDefault, random_skin_info);
skinItems.Insert(firstNonDefaultSkinIndex, random_skin_info);
sortUserSkins(skinItems);
skinDropdown.Items = skinItems;
}
private void itemUpdated(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
{
if (weakItem.NewValue.TryGetTarget(out var item))
Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => !i.Equals(item)).Append(item).ToArray());
{
Schedule(() =>
{
List<SkinInfo> newDropdownItems = skinDropdown.Items.Where(i => !i.Equals(item)).Append(item).ToList();
sortUserSkins(newDropdownItems);
skinDropdown.Items = newDropdownItems;
});
}
}
private void itemRemoved(ValueChangedEvent<WeakReference<SkinInfo>> weakItem)
@ -135,6 +148,13 @@ namespace osu.Game.Overlays.Settings.Sections
Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != item.ID).ToArray());
}
private void sortUserSkins(List<SkinInfo> skinsList)
{
// Sort user skins separately from built-in skins
skinsList.Sort(firstNonDefaultSkinIndex, skinsList.Count - firstNonDefaultSkinIndex,
Comparer<SkinInfo>.Create((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)));
}
private class SkinSettingsDropdown : SettingsDropdown<SkinInfo>
{
protected override OsuDropdown<SkinInfo> CreateDropdown() => new SkinDropdownControl();

View File

@ -124,9 +124,11 @@ namespace osu.Game.Rulesets.UI
Debug.Assert(drawableMap.ContainsKey(entry));
var drawable = drawableMap[entry];
// OnKilled can potentially change the hitobject's result, so it needs to run first before unbinding.
drawable.OnKilled();
drawable.OnNewResult -= onNewResult;
drawable.OnRevertResult -= onRevertResult;
drawable.OnKilled();
drawableMap.Remove(entry);

View File

@ -13,6 +13,7 @@ using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select;
@ -109,5 +110,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
}
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod);
private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true;
}
}

View File

@ -44,6 +44,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
[CanBeNull]
private IDisposable readyClickOperation;
private GridContainer mainContent;
public MultiplayerMatchSubScreen(Room room)
{
Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
@ -55,7 +57,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
InternalChildren = new Drawable[]
{
new GridContainer
mainContent = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
@ -178,6 +180,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden }
}
};
if (client.Room == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.State.BindValueChanged(visibility =>
{
if (visibility.NewValue == Visibility.Hidden)
mainContent.Show();
}, true);
}
}
protected override void LoadComplete()

View File

@ -33,6 +33,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private OverlinedHeader participantsHeader;
private GridContainer mainContent;
public PlaylistsRoomSubScreen(Room room)
{
Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value;
@ -44,7 +46,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
{
InternalChildren = new Drawable[]
{
new GridContainer
mainContent = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
@ -190,6 +192,19 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden }
}
};
if (roomId.Value == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.State.BindValueChanged(visibility =>
{
if (visibility.NewValue == Visibility.Hidden)
mainContent.Show();
}, true);
}
}
[Resolved]

View File

@ -10,6 +10,8 @@ using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Components;
@ -78,5 +80,9 @@ namespace osu.Game.Screens.Select
item.RequiredMods.Clear();
item.RequiredMods.AddRange(Mods.Value.Select(m => m.CreateCopy()));
}
protected override ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay(isValidMod);
private bool isValidMod(Mod mod) => !(mod is ModAutoplay) && (mod as MultiMod)?.Mods.Any(mm => mm is ModAutoplay) != true;
}
}

View File

@ -251,11 +251,7 @@ namespace osu.Game.Screens.Select
Children = new Drawable[]
{
BeatmapOptions = new BeatmapOptionsOverlay(),
ModSelect = new ModSelectOverlay
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
}
ModSelect = CreateModSelectOverlay()
}
}
}
@ -305,6 +301,8 @@ namespace osu.Game.Screens.Select
}
}
protected virtual ModSelectOverlay CreateModSelectOverlay() => new ModSelectOverlay();
protected virtual void ApplyFilterToCarousel(FilterCriteria criteria)
{
// if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter).