mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 15:17:27 +08:00
Merge branch 'master' into results-screen-sfx
This commit is contained in:
commit
8fda04c2d9
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.607.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.608.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -4,10 +4,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Rulesets.Catch.Mods;
|
using osu.Game.Rulesets.Catch.Mods;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
@ -21,12 +19,6 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
{
|
{
|
||||||
public class TestSceneCatchModHidden : ModTestScene
|
public class TestSceneCatchModHidden : ModTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
LocalConfig.SetValue(OsuSetting.IncreaseFirstObjectVisibility, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestJuiceStream()
|
public void TestJuiceStream()
|
||||||
{
|
{
|
||||||
|
@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
=> ApplyNormalVisibilityState(hitObject, state);
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state)
|
||||||
{
|
{
|
||||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
isLegacySkin = new Lazy<bool>(() => FindProvider(s => s.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version) != null) != null);
|
isLegacySkin = new Lazy<bool>(() => FindProvider(s => s.GetConfig<LegacySkinConfiguration.LegacySetting, decimal>(LegacySkinConfiguration.LegacySetting.Version) != null) != null);
|
||||||
hasKeyTexture = new Lazy<bool>(() => FindProvider(s => s.GetAnimation(
|
hasKeyTexture = new Lazy<bool>(() => FindProvider(s => s.GetAnimation(
|
||||||
this.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.KeyImage, 0)?.Value
|
s.GetManiaSkinConfig<string>(LegacyManiaSkinConfigurationLookups.KeyImage, 0)?.Value
|
||||||
?? "mania-key1", true, true) != null) != null);
|
?? "mania-key1", true, true) != null) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@ -30,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
private static readonly float border_distance_x = OsuPlayfield.BASE_SIZE.X * playfield_edge_ratio;
|
private static readonly float border_distance_x = OsuPlayfield.BASE_SIZE.X * playfield_edge_ratio;
|
||||||
private static readonly float border_distance_y = OsuPlayfield.BASE_SIZE.Y * playfield_edge_ratio;
|
private static readonly float border_distance_y = OsuPlayfield.BASE_SIZE.Y * playfield_edge_ratio;
|
||||||
|
|
||||||
private static readonly Vector2 playfield_middle = Vector2.Divide(OsuPlayfield.BASE_SIZE, 2);
|
private static readonly Vector2 playfield_middle = OsuPlayfield.BASE_SIZE / 2;
|
||||||
|
|
||||||
private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast;
|
private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast;
|
||||||
|
|
||||||
@ -74,23 +75,9 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
// update end position as it may have changed as a result of the position update.
|
// update end position as it may have changed as a result of the position update.
|
||||||
current.EndPositionRandomised = current.PositionRandomised;
|
current.EndPositionRandomised = current.PositionRandomised;
|
||||||
|
|
||||||
switch (hitObject)
|
if (hitObject is Slider slider)
|
||||||
{
|
|
||||||
case Slider slider:
|
|
||||||
// Shift nested objects the same distance as the slider got shifted in the randomisation process
|
|
||||||
// so that moveSliderIntoPlayfield() can determine their relative distances to slider.Position and thus minMargin
|
|
||||||
shiftNestedObjects(slider, Vector2.Subtract(slider.Position, current.PositionOriginal));
|
|
||||||
|
|
||||||
var oldPos = new Vector2(slider.Position.X, slider.Position.Y);
|
|
||||||
|
|
||||||
moveSliderIntoPlayfield(slider, current);
|
moveSliderIntoPlayfield(slider, current);
|
||||||
|
|
||||||
// Shift them again to move them to their final position after the slider got moved into the playfield
|
|
||||||
shiftNestedObjects(slider, Vector2.Subtract(slider.Position, oldPos));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = current;
|
previous = current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,7 +118,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
|
|
||||||
current.AngleRad = (float)Math.Atan2(posRelativeToPrev.Y, posRelativeToPrev.X);
|
current.AngleRad = (float)Math.Atan2(posRelativeToPrev.Y, posRelativeToPrev.X);
|
||||||
|
|
||||||
var position = Vector2.Add(previous.EndPositionRandomised, posRelativeToPrev);
|
var position = previous.EndPositionRandomised + posRelativeToPrev;
|
||||||
|
|
||||||
// Move hit objects back into the playfield if they are outside of it,
|
// Move hit objects back into the playfield if they are outside of it,
|
||||||
// which would sometimes happen during big jumps otherwise.
|
// which would sometimes happen during big jumps otherwise.
|
||||||
@ -146,34 +133,41 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void moveSliderIntoPlayfield(Slider slider, RandomObjectInfo currentObjectInfo)
|
private void moveSliderIntoPlayfield(Slider slider, RandomObjectInfo currentObjectInfo)
|
||||||
{
|
{
|
||||||
// Min. distances from the slider's position to the playfield border
|
var minMargin = getMinSliderMargin(slider);
|
||||||
var minMargin = new MarginPadding();
|
|
||||||
|
|
||||||
foreach (var hitObject in slider.NestedHitObjects.Where(o => o is SliderTick || o is SliderEndCircle))
|
slider.Position = new Vector2(
|
||||||
{
|
Math.Clamp(slider.Position.X, minMargin.Left, OsuPlayfield.BASE_SIZE.X - minMargin.Right),
|
||||||
if (!(hitObject is OsuHitObject osuHitObject))
|
Math.Clamp(slider.Position.Y, minMargin.Top, OsuPlayfield.BASE_SIZE.Y - minMargin.Bottom)
|
||||||
continue;
|
);
|
||||||
|
|
||||||
var relativePos = Vector2.Subtract(osuHitObject.Position, slider.Position);
|
|
||||||
|
|
||||||
minMargin.Left = Math.Max(minMargin.Left, -relativePos.X);
|
|
||||||
minMargin.Right = Math.Max(minMargin.Right, relativePos.X);
|
|
||||||
minMargin.Top = Math.Max(minMargin.Top, -relativePos.Y);
|
|
||||||
minMargin.Bottom = Math.Max(minMargin.Bottom, relativePos.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slider.Position.X < minMargin.Left)
|
|
||||||
slider.Position = new Vector2(minMargin.Left, slider.Position.Y);
|
|
||||||
else if (slider.Position.X + minMargin.Right > OsuPlayfield.BASE_SIZE.X)
|
|
||||||
slider.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - minMargin.Right, slider.Position.Y);
|
|
||||||
|
|
||||||
if (slider.Position.Y < minMargin.Top)
|
|
||||||
slider.Position = new Vector2(slider.Position.X, minMargin.Top);
|
|
||||||
else if (slider.Position.Y + minMargin.Bottom > OsuPlayfield.BASE_SIZE.Y)
|
|
||||||
slider.Position = new Vector2(slider.Position.X, OsuPlayfield.BASE_SIZE.Y - minMargin.Bottom);
|
|
||||||
|
|
||||||
currentObjectInfo.PositionRandomised = slider.Position;
|
currentObjectInfo.PositionRandomised = slider.Position;
|
||||||
currentObjectInfo.EndPositionRandomised = slider.EndPosition;
|
currentObjectInfo.EndPositionRandomised = slider.EndPosition;
|
||||||
|
|
||||||
|
shiftNestedObjects(slider, currentObjectInfo.PositionRandomised - currentObjectInfo.PositionOriginal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the min. distances from the <see cref="Slider"/>'s position to the playfield border for the slider to be fully inside of the playfield.
|
||||||
|
/// </summary>
|
||||||
|
private MarginPadding getMinSliderMargin(Slider slider)
|
||||||
|
{
|
||||||
|
var pathPositions = new List<Vector2>();
|
||||||
|
slider.Path.GetPathToProgress(pathPositions, 0, 1);
|
||||||
|
|
||||||
|
var minMargin = new MarginPadding();
|
||||||
|
|
||||||
|
foreach (var pos in pathPositions)
|
||||||
|
{
|
||||||
|
minMargin.Left = Math.Max(minMargin.Left, -pos.X);
|
||||||
|
minMargin.Right = Math.Max(minMargin.Right, pos.X);
|
||||||
|
minMargin.Top = Math.Max(minMargin.Top, -pos.Y);
|
||||||
|
minMargin.Bottom = Math.Max(minMargin.Bottom, pos.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
minMargin.Left = Math.Min(minMargin.Left, OsuPlayfield.BASE_SIZE.X - minMargin.Right);
|
||||||
|
minMargin.Top = Math.Min(minMargin.Top, OsuPlayfield.BASE_SIZE.Y - minMargin.Bottom);
|
||||||
|
|
||||||
|
return minMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -188,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
if (!(hitObject is OsuHitObject osuHitObject))
|
if (!(hitObject is OsuHitObject osuHitObject))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
osuHitObject.Position = Vector2.Add(osuHitObject.Position, shift);
|
osuHitObject.Position += shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,5 +128,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
spmContainer.FadeIn(drawableSpinner.HitObject.TimeFadeIn);
|
spmContainer.FadeIn(drawableSpinner.HitObject.TimeFadeIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (drawableSpinner != null)
|
||||||
|
drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
{
|
{
|
||||||
public class MainCirclePiece : CompositeDrawable
|
public class MainCirclePiece : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
private readonly CirclePiece circle;
|
private readonly CirclePiece circle;
|
||||||
private readonly RingPiece ring;
|
private readonly RingPiece ring;
|
||||||
private readonly FlashPiece flash;
|
private readonly FlashPiece flash;
|
||||||
|
@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
public class LegacyMainCirclePiece : CompositeDrawable
|
public class LegacyMainCirclePiece : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
private readonly string priorityLookup;
|
private readonly string priorityLookup;
|
||||||
private readonly bool hasNumber;
|
private readonly bool hasNumber;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -11,6 +12,7 @@ using osu.Game.Graphics.Backgrounds;
|
|||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Background
|
namespace osu.Game.Tests.Visual.Background
|
||||||
@ -23,6 +25,9 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
|
|
||||||
private Graphics.Backgrounds.Background getCurrentBackground() => screen.ChildrenOfType<Graphics.Backgrounds.Background>().FirstOrDefault();
|
private Graphics.Backgrounds.Background getCurrentBackground() => screen.ChildrenOfType<Graphics.Backgrounds.Background>().FirstOrDefault();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private SkinManager skins { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuConfigManager config { get; set; }
|
private OsuConfigManager config { get; set; }
|
||||||
|
|
||||||
@ -35,7 +40,7 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestTogglingStoryboardSwitchesBackgroundType()
|
public void TestBackgroundTypeSwitch()
|
||||||
{
|
{
|
||||||
setSupporter(true);
|
setSupporter(true);
|
||||||
|
|
||||||
@ -44,6 +49,12 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
|
|
||||||
setSourceMode(BackgroundSource.BeatmapWithStoryboard);
|
setSourceMode(BackgroundSource.BeatmapWithStoryboard);
|
||||||
AddUntilStep("is storyboard background", () => getCurrentBackground() is BeatmapBackgroundWithStoryboard);
|
AddUntilStep("is storyboard background", () => getCurrentBackground() is BeatmapBackgroundWithStoryboard);
|
||||||
|
|
||||||
|
setSourceMode(BackgroundSource.Skin);
|
||||||
|
AddUntilStep("is default background", () => getCurrentBackground().GetType() == typeof(Graphics.Backgrounds.Background));
|
||||||
|
|
||||||
|
setCustomSkin();
|
||||||
|
AddUntilStep("is skin background", () => getCurrentBackground() is SkinBackground);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -61,15 +72,19 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
AddUntilStep("is beatmap background", () => getCurrentBackground() is BeatmapBackground);
|
AddUntilStep("is beatmap background", () => getCurrentBackground() is BeatmapBackground);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[TestCase(BackgroundSource.Beatmap, typeof(BeatmapBackground))]
|
||||||
public void TestBeatmapDoesntReloadOnNoChange()
|
[TestCase(BackgroundSource.BeatmapWithStoryboard, typeof(BeatmapBackgroundWithStoryboard))]
|
||||||
|
[TestCase(BackgroundSource.Skin, typeof(SkinBackground))]
|
||||||
|
public void TestBackgroundDoesntReloadOnNoChange(BackgroundSource source, Type backgroundType)
|
||||||
{
|
{
|
||||||
BeatmapBackground last = null;
|
Graphics.Backgrounds.Background last = null;
|
||||||
|
|
||||||
setSourceMode(BackgroundSource.Beatmap);
|
setSourceMode(source);
|
||||||
setSupporter(true);
|
setSupporter(true);
|
||||||
|
if (source == BackgroundSource.Skin)
|
||||||
|
setCustomSkin();
|
||||||
|
|
||||||
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground() as BeatmapBackground) != null);
|
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == backgroundType);
|
||||||
AddAssert("next doesn't load new background", () => screen.Next() == false);
|
AddAssert("next doesn't load new background", () => screen.Next() == false);
|
||||||
|
|
||||||
// doesn't really need to be checked but might as well.
|
// doesn't really need to be checked but might as well.
|
||||||
@ -77,8 +92,25 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
AddUntilStep("ensure same background instance", () => last == getCurrentBackground());
|
AddUntilStep("ensure same background instance", () => last == getCurrentBackground());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBackgroundCyclingOnDefaultSkin([Values] bool supporter)
|
||||||
|
{
|
||||||
|
Graphics.Backgrounds.Background last = null;
|
||||||
|
|
||||||
|
setSourceMode(BackgroundSource.Skin);
|
||||||
|
setSupporter(supporter);
|
||||||
|
setDefaultSkin();
|
||||||
|
|
||||||
|
AddUntilStep("wait for beatmap background to be loaded", () => (last = getCurrentBackground())?.GetType() == typeof(Graphics.Backgrounds.Background));
|
||||||
|
AddAssert("next cycles background", () => screen.Next());
|
||||||
|
|
||||||
|
// doesn't really need to be checked but might as well.
|
||||||
|
AddWaitStep("wait a bit", 5);
|
||||||
|
AddUntilStep("ensure different background instance", () => last != getCurrentBackground());
|
||||||
|
}
|
||||||
|
|
||||||
private void setSourceMode(BackgroundSource source) =>
|
private void setSourceMode(BackgroundSource source) =>
|
||||||
AddStep("set background mode to beatmap", () => config.SetValue(OsuSetting.MenuBackgroundSource, source));
|
AddStep($"set background mode to {source}", () => config.SetValue(OsuSetting.MenuBackgroundSource, source));
|
||||||
|
|
||||||
private void setSupporter(bool isSupporter) =>
|
private void setSupporter(bool isSupporter) =>
|
||||||
AddStep($"set supporter {isSupporter}", () => ((DummyAPIAccess)API).LocalUser.Value = new User
|
AddStep($"set supporter {isSupporter}", () => ((DummyAPIAccess)API).LocalUser.Value = new User
|
||||||
@ -86,5 +118,16 @@ namespace osu.Game.Tests.Visual.Background
|
|||||||
IsSupporter = isSupporter,
|
IsSupporter = isSupporter,
|
||||||
Id = API.LocalUser.Value.Id + 1,
|
Id = API.LocalUser.Value.Id + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private void setCustomSkin()
|
||||||
|
{
|
||||||
|
// feign a skin switch. this doesn't do anything except force CurrentSkin to become a LegacySkin.
|
||||||
|
AddStep("set custom skin", () => skins.CurrentSkinInfo.Value = new SkinInfo { ID = 5 });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDefaultSkin() => AddStep("set default skin", () => skins.CurrentSkinInfo.SetDefault());
|
||||||
|
|
||||||
|
[TearDownSteps]
|
||||||
|
public void TearDown() => setDefaultSkin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,16 +9,19 @@ using osu.Framework.Screens;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Mods;
|
using osu.Game.Overlays.Mods;
|
||||||
using osu.Game.Overlays.Toolbar;
|
using osu.Game.Overlays.Toolbar;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Screens.OnlinePlay.Components;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Screens.Ranking;
|
using osu.Game.Screens.Ranking;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Screens.Select.Options;
|
using osu.Game.Screens.Select.Options;
|
||||||
using osu.Game.Tests.Beatmaps.IO;
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
|
using osu.Game.Tests.Visual.Multiplayer;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
@ -152,6 +155,14 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddUntilStep("wait for track", () => !Game.MusicController.CurrentTrack.IsDummyDevice && Game.MusicController.IsPlaying);
|
AddUntilStep("wait for track", () => !Game.MusicController.CurrentTrack.IsDummyDevice && Game.MusicController.IsPlaying);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPushSongSelectAndPressBackButtonImmediately()
|
||||||
|
{
|
||||||
|
AddStep("push song select", () => Game.ScreenStack.Push(new TestPlaySongSelect()));
|
||||||
|
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
|
||||||
|
AddWaitStep("wait two frames", 2);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestExitSongSelectWithClick()
|
public void TestExitSongSelectWithClick()
|
||||||
{
|
{
|
||||||
@ -298,6 +309,18 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
|
AddAssert("Toolbar is hidden", () => Game.Toolbar.State.Value == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPushMatchSubScreenAndPressBackButtonImmediately()
|
||||||
|
{
|
||||||
|
TestMultiplayer multiplayer = null;
|
||||||
|
|
||||||
|
PushAndConfirm(() => multiplayer = new TestMultiplayer());
|
||||||
|
|
||||||
|
AddStep("open room", () => multiplayer.OpenNewRoom());
|
||||||
|
AddStep("press back button", () => Game.ChildrenOfType<BackButton>().First().Action());
|
||||||
|
AddWaitStep("wait two frames", 2);
|
||||||
|
}
|
||||||
|
|
||||||
private void pushEscape() =>
|
private void pushEscape() =>
|
||||||
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
AddStep("Press escape", () => InputManager.Key(Key.Escape));
|
||||||
|
|
||||||
@ -322,5 +345,18 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
protected override bool DisplayStableImportPrompt => false;
|
protected override bool DisplayStableImportPrompt => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
|
||||||
|
{
|
||||||
|
[Cached(typeof(MultiplayerClient))]
|
||||||
|
public readonly TestMultiplayerClient Client;
|
||||||
|
|
||||||
|
public TestMultiplayer()
|
||||||
|
{
|
||||||
|
Client = new TestMultiplayerClient((TestMultiplayerRoomManager)RoomManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override RoomManager CreateRoomManager() => new TestMultiplayerRoomManager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,14 +264,18 @@ namespace osu.Game.Collections
|
|||||||
using (var sw = new SerializationWriter(storage.GetStream(database_name, FileAccess.Write)))
|
using (var sw = new SerializationWriter(storage.GetStream(database_name, FileAccess.Write)))
|
||||||
{
|
{
|
||||||
sw.Write(database_version);
|
sw.Write(database_version);
|
||||||
sw.Write(Collections.Count);
|
|
||||||
|
|
||||||
foreach (var c in Collections)
|
var collectionsCopy = Collections.ToArray();
|
||||||
|
sw.Write(collectionsCopy.Length);
|
||||||
|
|
||||||
|
foreach (var c in collectionsCopy)
|
||||||
{
|
{
|
||||||
sw.Write(c.Name.Value);
|
sw.Write(c.Name.Value);
|
||||||
sw.Write(c.Beatmaps.Count);
|
|
||||||
|
|
||||||
foreach (var b in c.Beatmaps)
|
var beatmapsCopy = c.Beatmaps.ToArray();
|
||||||
|
sw.Write(beatmapsCopy.Length);
|
||||||
|
|
||||||
|
foreach (var b in beatmapsCopy)
|
||||||
sw.Write(b.MD5Hash);
|
sw.Write(b.MD5Hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -14,7 +15,7 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A background which offers blurring via a <see cref="BufferedContainer"/> on demand.
|
/// A background which offers blurring via a <see cref="BufferedContainer"/> on demand.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Background : CompositeDrawable
|
public class Background : CompositeDrawable, IEquatable<Background>
|
||||||
{
|
{
|
||||||
private const float blur_scale = 0.5f;
|
private const float blur_scale = 0.5f;
|
||||||
|
|
||||||
@ -71,5 +72,14 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
|
|
||||||
bufferedContainer?.BlurTo(newBlurSigma * blur_scale, duration, easing);
|
bufferedContainer?.BlurTo(newBlurSigma * blur_scale, duration, easing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool Equals(Background other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return other.GetType() == GetType()
|
||||||
|
&& other.textureName == textureName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,5 +24,14 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
{
|
{
|
||||||
Sprite.Texture = Beatmap?.Background ?? textures.Get(fallbackTextureName);
|
Sprite.Texture = Beatmap?.Background ?? textures.Get(fallbackTextureName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(Background other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return other.GetType() == GetType()
|
||||||
|
&& ((BeatmapBackground)other).Beatmap == Beatmap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
osu.Game/Graphics/Backgrounds/SkinBackground.cs
Normal file
34
osu.Game/Graphics/Backgrounds/SkinBackground.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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.Game.Skinning;
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.Backgrounds
|
||||||
|
{
|
||||||
|
internal class SkinBackground : Background
|
||||||
|
{
|
||||||
|
private readonly Skin skin;
|
||||||
|
|
||||||
|
public SkinBackground(Skin skin, string fallbackTextureName)
|
||||||
|
: base(fallbackTextureName)
|
||||||
|
{
|
||||||
|
this.skin = skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(Background other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other)) return false;
|
||||||
|
if (ReferenceEquals(this, other)) return true;
|
||||||
|
|
||||||
|
return other.GetType() == GetType()
|
||||||
|
&& ((SkinBackground)other).skin.SkinInfo.Equals(skin.SkinInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -57,12 +57,6 @@ namespace osu.Game.Graphics.Backgrounds
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether we want to expire triangles as they exit our draw area completely.
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("Unused.")] // Can be removed 20210518
|
|
||||||
protected virtual bool ExpireOffScreenTriangles => true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether we should create new triangles as others expire.
|
/// Whether we should create new triangles as others expire.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -21,7 +21,12 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
{
|
{
|
||||||
var ruleset = rulesets.GetRuleset(OnlineRulesetID);
|
var ruleset = rulesets.GetRuleset(OnlineRulesetID);
|
||||||
|
|
||||||
var mods = Mods != null ? ruleset.CreateInstance().GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
|
||||||
|
var mods = Mods != null ? rulesetInstance.GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
|
||||||
|
|
||||||
|
// all API scores provided by this class are considered to be legacy.
|
||||||
|
mods = mods.Append(rulesetInstance.GetAllMods().OfType<ModClassic>().Single()).ToArray();
|
||||||
|
|
||||||
var scoreInfo = new ScoreInfo
|
var scoreInfo = new ScoreInfo
|
||||||
{
|
{
|
||||||
@ -38,7 +43,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
Rank = Rank,
|
Rank = Rank,
|
||||||
Ruleset = ruleset,
|
Ruleset = ruleset,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
IsLegacyScore = true
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Statistics != null)
|
if (Statistics != null)
|
||||||
|
@ -651,9 +651,10 @@ namespace osu.Game
|
|||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
var currentScreen = ScreenStack.CurrentScreen as IOsuScreen;
|
if (!(ScreenStack.CurrentScreen is IOsuScreen currentScreen))
|
||||||
|
return;
|
||||||
|
|
||||||
if (currentScreen?.AllowBackButton == true && !currentScreen.OnBackButton())
|
if (!((Drawable)currentScreen).IsLoaded || (currentScreen.AllowBackButton && !currentScreen.OnBackButton()))
|
||||||
ScreenStack.Exit();
|
ScreenStack.Exit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -32,18 +31,6 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
|
|
||||||
private readonly Container aboveHitObjectsContent;
|
private readonly Container aboveHitObjectsContent;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Duration of initial fade in.
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("Apply any animations manually via ApplyHitAnimations / ApplyMissAnimations. Defaults were moved inside skinned components.")]
|
|
||||||
protected virtual double FadeInDuration => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Duration to wait until fade out begins. Defaults to <see cref="FadeInDuration"/>.
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("Apply any animations manually via ApplyHitAnimations / ApplyMissAnimations. Defaults were moved inside skinned components.")]
|
|
||||||
protected virtual double FadeOutDelay => FadeInDuration;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
/// Creates a drawable which visualises a <see cref="Judgements.Judgement"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
@ -69,14 +68,6 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double MaxHealthIncrease => HealthIncreaseFor(MaxResult);
|
public double MaxHealthIncrease => HealthIncreaseFor(MaxResult);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the numeric score representation of a <see cref="HitResult"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
|
|
||||||
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
|
||||||
[Obsolete("Has no effect. Use ToNumericResult(HitResult) (standardised across all rulesets).")] // Can be made non-virtual 20210328
|
|
||||||
protected virtual int NumericResultFor(HitResult result) => ToNumericResult(result);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -192,7 +192,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies a hit object to be represented by this <see cref="DrawableHitObject"/>.
|
/// Applies a hit object to be represented by this <see cref="DrawableHitObject"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("Use either overload of Apply that takes a single argument of type HitObject or HitObjectLifetimeEntry")]
|
[Obsolete("Use either overload of Apply that takes a single argument of type HitObject or HitObjectLifetimeEntry")] // Can be removed 20211021.
|
||||||
public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEntry lifetimeEntry)
|
public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEntry lifetimeEntry)
|
||||||
{
|
{
|
||||||
if (lifetimeEntry != null)
|
if (lifetimeEntry != null)
|
||||||
@ -409,11 +409,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
using (BeginAbsoluteSequence(StateUpdateTime, true))
|
using (BeginAbsoluteSequence(StateUpdateTime, true))
|
||||||
UpdateStartTimeStateTransforms();
|
UpdateStartTimeStateTransforms();
|
||||||
|
|
||||||
#pragma warning disable 618
|
|
||||||
using (BeginAbsoluteSequence(StateUpdateTime + (Result?.TimeOffset ?? 0), true))
|
|
||||||
UpdateStateTransforms(newState);
|
|
||||||
#pragma warning restore 618
|
|
||||||
|
|
||||||
using (BeginAbsoluteSequence(HitStateUpdateTime, true))
|
using (BeginAbsoluteSequence(HitStateUpdateTime, true))
|
||||||
UpdateHitStateTransforms(newState);
|
UpdateHitStateTransforms(newState);
|
||||||
|
|
||||||
@ -447,7 +442,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// By default, this will fade in the object from zero with no duration.
|
/// By default, this will fade in the object from zero with no duration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This is called once before every <see cref="UpdateStateTransforms"/>. This is to ensure a good state in the case
|
/// This is called once before every <see cref="UpdateHitStateTransforms"/>. This is to ensure a good state in the case
|
||||||
/// the <see cref="JudgementResult.TimeOffset"/> was negative and potentially altered the pre-hit transforms.
|
/// the <see cref="JudgementResult.TimeOffset"/> was negative and potentially altered the pre-hit transforms.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected virtual void UpdateInitialTransforms()
|
protected virtual void UpdateInitialTransforms()
|
||||||
@ -455,16 +450,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
this.FadeInFromZero();
|
this.FadeInFromZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Apply transforms based on the current <see cref="ArmedState"/>. Previous states are automatically cleared.
|
|
||||||
/// In the case of a non-idle <see cref="ArmedState"/>, and if <see cref="Drawable.LifetimeEnd"/> was not set during this call, <see cref="Drawable.Expire"/> will be invoked.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="state">The new armed state.</param>
|
|
||||||
[Obsolete("Use UpdateStartTimeStateTransforms and UpdateHitStateTransforms instead")] // Can be removed 20210504
|
|
||||||
protected virtual void UpdateStateTransforms(ArmedState state)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply passive transforms at the <see cref="HitObject"/>'s StartTime.
|
/// Apply passive transforms at the <see cref="HitObject"/>'s StartTime.
|
||||||
/// This is called each time <see cref="State"/> changes.
|
/// This is called each time <see cref="State"/> changes.
|
||||||
@ -520,23 +505,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
AccentColour.Value = combo.GetComboColour(comboColours);
|
AccentColour.Value = combo.GetComboColour(comboColours);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to retrieve the combo colour. Automatically assigned to <see cref="AccentColour"/>.
|
|
||||||
/// Defaults to using <see cref="IHasComboInformation.ComboIndex"/> to decide on a colour.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This will only be called if the <see cref="HitObject"/> implements <see cref="IHasComboInformation"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="comboColours">A list of combo colours provided by the beatmap or skin. Can be null if not available.</param>
|
|
||||||
[Obsolete("Unused. Implement IHasComboInformation and IHasComboInformation.GetComboColour() on the HitObject model instead.")] // Can be removed 20210527
|
|
||||||
protected virtual Color4 GetComboColour(IReadOnlyList<Color4> comboColours)
|
|
||||||
{
|
|
||||||
if (!(HitObject is IHasComboInformation combo))
|
|
||||||
throw new InvalidOperationException($"{nameof(HitObject)} must implement {nameof(IHasComboInformation)}");
|
|
||||||
|
|
||||||
return comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a change is made to the skin.
|
/// Called when a change is made to the skin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -630,7 +598,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time at which state transforms should be applied that line up to <see cref="HitObject"/>'s StartTime.
|
/// The time at which state transforms should be applied that line up to <see cref="HitObject"/>'s StartTime.
|
||||||
/// This is used to offset calls to <see cref="UpdateStateTransforms"/>.
|
/// This is used to offset calls to <see cref="UpdateStartTimeStateTransforms"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double StateUpdateTime => HitObject.StartTime;
|
public double StateUpdateTime => HitObject.StartTime;
|
||||||
|
|
||||||
|
@ -65,6 +65,10 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
|
|
||||||
scoreInfo.Mods = currentRuleset.ConvertFromLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();
|
scoreInfo.Mods = currentRuleset.ConvertFromLegacyMods((LegacyMods)sr.ReadInt32()).ToArray();
|
||||||
|
|
||||||
|
// lazer replays get a really high version number.
|
||||||
|
if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION)
|
||||||
|
scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.GetAllMods().OfType<ModClassic>().Single()).ToArray();
|
||||||
|
|
||||||
currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods);
|
currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods);
|
||||||
scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;
|
scoreInfo.Beatmap = currentBeatmap.BeatmapInfo;
|
||||||
|
|
||||||
|
@ -15,7 +15,16 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
{
|
{
|
||||||
public class LegacyScoreEncoder
|
public class LegacyScoreEncoder
|
||||||
{
|
{
|
||||||
public const int LATEST_VERSION = 128;
|
/// <summary>
|
||||||
|
/// Database version in stable-compatible YYYYMMDD format.
|
||||||
|
/// Should be incremented if any changes are made to the format/usage.
|
||||||
|
/// </summary>
|
||||||
|
public const int LATEST_VERSION = FIRST_LAZER_VERSION;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The first stable-compatible YYYYMMDD format version given to lazer usage of replays.
|
||||||
|
/// </summary>
|
||||||
|
public const int FIRST_LAZER_VERSION = 30000000;
|
||||||
|
|
||||||
private readonly Score score;
|
private readonly Score score;
|
||||||
private readonly IBeatmap beatmap;
|
private readonly IBeatmap beatmap;
|
||||||
|
@ -76,9 +76,6 @@ namespace osu.Game.Scoring
|
|||||||
else if (localAPIMods != null)
|
else if (localAPIMods != null)
|
||||||
scoreMods = apiMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
|
scoreMods = apiMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
|
||||||
|
|
||||||
if (IsLegacyScore)
|
|
||||||
scoreMods = scoreMods.Append(rulesetInstance.GetAllMods().OfType<ModClassic>().Single()).ToArray();
|
|
||||||
|
|
||||||
return scoreMods;
|
return scoreMods;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@ -201,33 +198,12 @@ namespace osu.Game.Scoring
|
|||||||
[JsonProperty("position")]
|
[JsonProperty("position")]
|
||||||
public int? Position { get; set; }
|
public int? Position { get; set; }
|
||||||
|
|
||||||
private bool isLegacyScore;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="ScoreInfo"/> represents a legacy (osu!stable) score.
|
/// Whether this <see cref="ScoreInfo"/> represents a legacy (osu!stable) score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsLegacyScore
|
public bool IsLegacyScore => Mods.OfType<ModClassic>().Any();
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (isLegacyScore)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// The above check will catch legacy online scores that have an appropriate UserString + UserId.
|
|
||||||
// For non-online scores such as those imported in, a heuristic is used based on the following table:
|
|
||||||
//
|
|
||||||
// Mode | UserString | UserId
|
|
||||||
// --------------- | ---------- | ---------
|
|
||||||
// stable | <username> | 1
|
|
||||||
// lazer | <username> | <userid>
|
|
||||||
// lazer (offline) | Guest | 1
|
|
||||||
|
|
||||||
return ID > 0 && UserID == 1 && UserString != "Guest";
|
|
||||||
}
|
|
||||||
set => isLegacyScore = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<HitResultDisplayStatistic> GetStatisticsForDisplay()
|
public IEnumerable<HitResultDisplayStatistic> GetStatisticsForDisplay()
|
||||||
{
|
{
|
||||||
|
@ -112,16 +112,23 @@ namespace osu.Game.Screens.Backgrounds
|
|||||||
newBackground = new BeatmapBackgroundWithStoryboard(beatmap.Value, getBackgroundTextureName());
|
newBackground = new BeatmapBackgroundWithStoryboard(beatmap.Value, getBackgroundTextureName());
|
||||||
newBackground ??= new BeatmapBackground(beatmap.Value, getBackgroundTextureName());
|
newBackground ??= new BeatmapBackground(beatmap.Value, getBackgroundTextureName());
|
||||||
|
|
||||||
// this method is called in many cases where the beatmap hasn't changed (ie. on screen transitions).
|
break;
|
||||||
// if a background is already displayed for the requested beatmap, we don't want to load it again.
|
}
|
||||||
if (background?.GetType() == newBackground.GetType() &&
|
|
||||||
(background as BeatmapBackground)?.Beatmap == beatmap.Value)
|
|
||||||
return background;
|
|
||||||
|
|
||||||
|
case BackgroundSource.Skin:
|
||||||
|
// default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them.
|
||||||
|
if (skin.Value is DefaultSkin || skin.Value is DefaultLegacySkin)
|
||||||
|
break;
|
||||||
|
|
||||||
|
newBackground = new SkinBackground(skin.Value, getBackgroundTextureName());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// this method is called in many cases where the background might not necessarily need to change.
|
||||||
|
// if an equivalent background is currently being shown, we don't want to load it again.
|
||||||
|
if (newBackground?.Equals(background) == true)
|
||||||
|
return background;
|
||||||
|
|
||||||
newBackground ??= new Background(getBackgroundTextureName());
|
newBackground ??= new Background(getBackgroundTextureName());
|
||||||
newBackground.Depth = currentDisplay;
|
newBackground.Depth = currentDisplay;
|
||||||
@ -140,22 +147,5 @@ namespace osu.Game.Screens.Backgrounds
|
|||||||
return $@"Menu/menu-background-{currentDisplay % background_count + 1}";
|
return $@"Menu/menu-background-{currentDisplay % background_count + 1}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SkinnedBackground : Background
|
|
||||||
{
|
|
||||||
private readonly Skin skin;
|
|
||||||
|
|
||||||
public SkinnedBackground(Skin skin, string fallbackTextureName)
|
|
||||||
: base(fallbackTextureName)
|
|
||||||
{
|
|
||||||
this.skin = skin;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
|
||||||
Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,11 @@ namespace osu.Game.Screens
|
|||||||
/// Invoked when the back button has been pressed to close any overlays before exiting this <see cref="IOsuScreen"/>.
|
/// Invoked when the back button has been pressed to close any overlays before exiting this <see cref="IOsuScreen"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
/// If this <see cref="IOsuScreen"/> has not yet finished loading, the exit will occur immediately without this method being invoked.
|
||||||
|
/// <para>
|
||||||
/// Return <c>true</c> to block this <see cref="IOsuScreen"/> from being exited after closing an overlay.
|
/// Return <c>true</c> to block this <see cref="IOsuScreen"/> from being exited after closing an overlay.
|
||||||
/// Return <c>false</c> if this <see cref="IOsuScreen"/> should continue exiting.
|
/// Return <c>false</c> if this <see cref="IOsuScreen"/> should continue exiting.
|
||||||
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
bool OnBackButton();
|
bool OnBackButton();
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
|
|||||||
// Isolates beatmap/ruleset to this screen.
|
// Isolates beatmap/ruleset to this screen.
|
||||||
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
public override bool DisallowExternalBeatmapRulesetChanges => true;
|
||||||
|
|
||||||
|
// We are managing our own adjustments. For now, this happens inside the Player instances themselves.
|
||||||
|
public override bool AllowRateAdjustments => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether all spectating players have finished loading.
|
/// Whether all spectating players have finished loading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -253,7 +253,10 @@ namespace osu.Game.Screens.OnlinePlay
|
|||||||
|
|
||||||
public override bool OnBackButton()
|
public override bool OnBackButton()
|
||||||
{
|
{
|
||||||
if ((screenStack.CurrentScreen as IOnlinePlaySubScreen)?.OnBackButton() == true)
|
if (!(screenStack.CurrentScreen is IOnlinePlaySubScreen onlineSubScreen))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (((Drawable)onlineSubScreen).IsLoaded && onlineSubScreen.AllowBackButton && onlineSubScreen.OnBackButton())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (screenStack.CurrentScreen != null && !(screenStack.CurrentScreen is LoungeSubScreen))
|
if (screenStack.CurrentScreen != null && !(screenStack.CurrentScreen is LoungeSubScreen))
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
@ -70,22 +71,48 @@ namespace osu.Game.Skinning
|
|||||||
updateSample();
|
updateSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
CurrentSkin.SourceChanged += skinChangedImmediate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void skinChangedImmediate()
|
||||||
|
{
|
||||||
|
// Clean up the previous sample immediately on a source change.
|
||||||
|
// This avoids a potential call to Play() of an already disposed sample (samples are disposed along with the skin, but SkinChanged is scheduled).
|
||||||
|
clearPreviousSamples();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void SkinChanged(ISkinSource skin)
|
protected override void SkinChanged(ISkinSource skin)
|
||||||
{
|
{
|
||||||
base.SkinChanged(skin);
|
base.SkinChanged(skin);
|
||||||
updateSample();
|
updateSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this sample was playing before a skin source change.
|
||||||
|
/// </summary>
|
||||||
|
private bool wasPlaying;
|
||||||
|
|
||||||
|
private void clearPreviousSamples()
|
||||||
|
{
|
||||||
|
// only run if the samples aren't already cleared.
|
||||||
|
// this ensures the "wasPlaying" state is stored correctly even if multiple clear calls are executed.
|
||||||
|
if (!sampleContainer.Any()) return;
|
||||||
|
|
||||||
|
wasPlaying = Playing;
|
||||||
|
|
||||||
|
sampleContainer.Clear();
|
||||||
|
Sample = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateSample()
|
private void updateSample()
|
||||||
{
|
{
|
||||||
if (sampleInfo == null)
|
if (sampleInfo == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool wasPlaying = Playing;
|
|
||||||
|
|
||||||
sampleContainer.Clear();
|
|
||||||
Sample = null;
|
|
||||||
|
|
||||||
var sample = CurrentSkin.GetSample(sampleInfo);
|
var sample = CurrentSkin.GetSample(sampleInfo);
|
||||||
|
|
||||||
if (sample == null)
|
if (sample == null)
|
||||||
@ -146,6 +173,14 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (CurrentSkin != null)
|
||||||
|
CurrentSkin.SourceChanged -= skinChangedImmediate;
|
||||||
|
}
|
||||||
|
|
||||||
#region Re-expose AudioContainer
|
#region Re-expose AudioContainer
|
||||||
|
|
||||||
public BindableNumber<double> Volume => sampleContainer.Volume;
|
public BindableNumber<double> Volume => sampleContainer.Volume;
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.607.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.608.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0"/>
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0"/>
|
||||||
<PackageReference Include="Sentry" Version="3.4.0" />
|
<PackageReference Include="Sentry" Version="3.4.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.607.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2021.608.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0"/>
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.604.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
|
||||||
@ -93,7 +93,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2021.607.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2021.608.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
<PackageReference Include="SharpCompress" Version="0.28.2" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user