mirror of
https://github.com/osukey/osukey.git
synced 2025-04-29 10:47:22 +09:00
Merge branch 'master' into pp-counter-alloc-reduction
This commit is contained in:
commit
6fb06d69cc
@ -52,7 +52,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.304.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.304.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.308.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.314.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
|
@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new CatchLegacySkinTransformer(skin);
|
public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new CatchLegacySkinTransformer(skin);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator() => new CatchPerformanceCalculator(this);
|
public override PerformanceCalculator CreatePerformanceCalculator() => new CatchPerformanceCalculator();
|
||||||
|
|
||||||
public int LegacyID => 2;
|
public int LegacyID => 2;
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
private int tinyTicksMissed;
|
private int tinyTicksMissed;
|
||||||
private int misses;
|
private int misses;
|
||||||
|
|
||||||
public CatchPerformanceCalculator(Ruleset ruleset)
|
public CatchPerformanceCalculator()
|
||||||
: base(ruleset)
|
: base(new CatchRuleset())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public ManiaPerformanceCalculator(Ruleset ruleset)
|
public ManiaPerformanceCalculator()
|
||||||
: base(ruleset)
|
: base(new ManiaRuleset())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator() => new ManiaPerformanceCalculator(this);
|
public override PerformanceCalculator CreatePerformanceCalculator() => new ManiaPerformanceCalculator();
|
||||||
|
|
||||||
public const string SHORT_NAME = "mania";
|
public const string SHORT_NAME = "mania";
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
private double effectiveMissCount;
|
private double effectiveMissCount;
|
||||||
|
|
||||||
public OsuPerformanceCalculator(Ruleset ruleset)
|
public OsuPerformanceCalculator()
|
||||||
: base(ruleset)
|
: base(new OsuRuleset())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,23 +2,22 @@
|
|||||||
// 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 JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osuTK;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Skinning;
|
using osu.Game.Rulesets.Osu.Skinning;
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -126,18 +125,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
|
|
||||||
Samples.Samples = HitObject.TailSamples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
Samples.Samples = HitObject.TailSamples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||||
|
slidingSample.Samples = HitObject.CreateSlidingSamples().Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||||
var slidingSamples = new List<ISampleInfo>();
|
|
||||||
|
|
||||||
var normalSample = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL);
|
|
||||||
if (normalSample != null)
|
|
||||||
slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(normalSample).With("sliderslide"));
|
|
||||||
|
|
||||||
var whistleSample = HitObject.Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE);
|
|
||||||
if (whistleSample != null)
|
|
||||||
slidingSamples.Add(HitObject.SampleControlPoint.ApplyTo(whistleSample).With("sliderwhistle"));
|
|
||||||
|
|
||||||
slidingSample.Samples = slidingSamples.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void StopAllSamples()
|
public override void StopAllSamples()
|
||||||
|
@ -74,6 +74,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadSamples()
|
||||||
|
{
|
||||||
|
// Tail models don't actually get samples, as the playback is handled by DrawableSlider.
|
||||||
|
// This override is only here for visibility in explaining this weird flow.
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PlaySamples()
|
||||||
|
{
|
||||||
|
// Tail models don't actually get samples, as the playback is handled by DrawableSlider.
|
||||||
|
// This override is only here for visibility in explaining this weird flow.
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
{
|
{
|
||||||
base.UpdateInitialTransforms();
|
base.UpdateInitialTransforms();
|
||||||
|
@ -121,16 +121,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
{
|
{
|
||||||
base.LoadSamples();
|
base.LoadSamples();
|
||||||
|
|
||||||
var firstSample = HitObject.Samples.FirstOrDefault();
|
spinningSample.Samples = HitObject.CreateSpinningSamples().Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast<ISampleInfo>().ToArray();
|
||||||
|
|
||||||
if (firstSample != null)
|
|
||||||
{
|
|
||||||
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample).With("spinnerspin");
|
|
||||||
|
|
||||||
spinningSample.Samples = new ISampleInfo[] { clone };
|
|
||||||
spinningSample.Frequency.Value = spinning_sample_initial_frequency;
|
spinningSample.Frequency.Value = spinning_sample_initial_frequency;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,23 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IList<HitSampleInfo> AuxiliarySamples => CreateSlidingSamples().Concat(TailSamples).ToArray();
|
||||||
|
|
||||||
|
public IList<HitSampleInfo> CreateSlidingSamples()
|
||||||
|
{
|
||||||
|
var slidingSamples = new List<HitSampleInfo>();
|
||||||
|
|
||||||
|
var normalSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL);
|
||||||
|
if (normalSample != null)
|
||||||
|
slidingSamples.Add(normalSample.With("sliderslide"));
|
||||||
|
|
||||||
|
var whistleSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||||
|
if (whistleSample != null)
|
||||||
|
slidingSamples.Add(whistleSample.With("sliderwhistle"));
|
||||||
|
|
||||||
|
return slidingSamples;
|
||||||
|
}
|
||||||
|
|
||||||
private readonly Cached<Vector2> endPositionCache = new Cached<Vector2>();
|
private readonly Cached<Vector2> endPositionCache = new Cached<Vector2>();
|
||||||
|
|
||||||
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1);
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
// 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.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -73,5 +77,20 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||||
|
|
||||||
|
public override IList<HitSampleInfo> AuxiliarySamples => CreateSpinningSamples();
|
||||||
|
|
||||||
|
public HitSampleInfo[] CreateSpinningSamples()
|
||||||
|
{
|
||||||
|
var referenceSample = Samples.FirstOrDefault();
|
||||||
|
|
||||||
|
if (referenceSample == null)
|
||||||
|
return Array.Empty<HitSampleInfo>();
|
||||||
|
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
SampleControlPoint.ApplyTo(referenceSample).With("spinnerspin")
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(RulesetInfo, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator() => new OsuPerformanceCalculator(this);
|
public override PerformanceCalculator CreatePerformanceCalculator() => new OsuPerformanceCalculator();
|
||||||
|
|
||||||
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
public override HitObjectComposer CreateHitObjectComposer() => new OsuHitObjectComposer(this);
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
public TaikoPerformanceCalculator(Ruleset ruleset)
|
public TaikoPerformanceCalculator()
|
||||||
: base(ruleset)
|
: base(new TaikoRuleset())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new TaikoDifficultyCalculator(RulesetInfo, beatmap);
|
public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new TaikoDifficultyCalculator(RulesetInfo, beatmap);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator() => new TaikoPerformanceCalculator(this);
|
public override PerformanceCalculator CreatePerformanceCalculator() => new TaikoPerformanceCalculator();
|
||||||
|
|
||||||
public int LegacyID => 1;
|
public int LegacyID => 1;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@ -52,6 +53,49 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("skinnable sprite has correct size", () => sprites.Any(s => Precision.AlmostEquals(s.ChildrenOfType<SkinnableSprite>().Single().Size, new Vector2(128, 128))));
|
AddAssert("skinnable sprite has correct size", () => sprites.Any(s => Precision.AlmostEquals(s.ChildrenOfType<SkinnableSprite>().Single().Size, new Vector2(128, 128))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFlippedSprite()
|
||||||
|
{
|
||||||
|
const string lookup_name = "hitcircleoverlay";
|
||||||
|
|
||||||
|
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||||
|
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||||
|
AddStep("flip sprites", () => sprites.ForEach(s =>
|
||||||
|
{
|
||||||
|
s.FlipH = true;
|
||||||
|
s.FlipV = true;
|
||||||
|
}));
|
||||||
|
AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNegativeScale()
|
||||||
|
{
|
||||||
|
const string lookup_name = "hitcircleoverlay";
|
||||||
|
|
||||||
|
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||||
|
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||||
|
AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(-1)));
|
||||||
|
AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNegativeScaleWithFlippedSprite()
|
||||||
|
{
|
||||||
|
const string lookup_name = "hitcircleoverlay";
|
||||||
|
|
||||||
|
AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true);
|
||||||
|
AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero)));
|
||||||
|
AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(-1)));
|
||||||
|
AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight));
|
||||||
|
AddStep("flip sprites", () => sprites.ForEach(s =>
|
||||||
|
{
|
||||||
|
s.FlipH = true;
|
||||||
|
s.FlipV = true;
|
||||||
|
}));
|
||||||
|
AddAssert("origin back", () => sprites.All(s => s.Origin == Anchor.TopLeft));
|
||||||
|
}
|
||||||
|
|
||||||
private DrawableStoryboardSprite createSprite(string lookupName, Anchor origin, Vector2 initialPosition)
|
private DrawableStoryboardSprite createSprite(string lookupName, Anchor origin, Vector2 initialPosition)
|
||||||
=> new DrawableStoryboardSprite(
|
=> new DrawableStoryboardSprite(
|
||||||
new StoryboardSprite(lookupName, origin, initialPosition)
|
new StoryboardSprite(lookupName, origin, initialPosition)
|
||||||
|
@ -48,7 +48,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddStep("create display", () => recreateDisplay(new OsuHitWindows(), 5));
|
AddStep("create display", () => recreateDisplay(new OsuHitWindows(), 5));
|
||||||
|
|
||||||
AddRepeatStep("New random judgement", () => newJudgement(), 40);
|
AddRepeatStep("New random judgement", () =>
|
||||||
|
{
|
||||||
|
double offset = RNG.Next(-150, 150);
|
||||||
|
newJudgement(offset, drawableRuleset.HitWindows.ResultFor(offset));
|
||||||
|
}, 400);
|
||||||
|
|
||||||
AddRepeatStep("New max negative", () => newJudgement(-drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
|
AddRepeatStep("New max negative", () => newJudgement(-drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
|
||||||
AddRepeatStep("New max positive", () => newJudgement(drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
|
AddRepeatStep("New max positive", () => newJudgement(drawableRuleset.HitWindows.WindowFor(HitResult.Meh)), 20);
|
||||||
|
@ -6,6 +6,8 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Layout;
|
||||||
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Screens;
|
using osu.Game.Screens;
|
||||||
@ -66,7 +68,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
this.targetMode = targetMode;
|
this.targetMode = targetMode;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChild = sizableContainer = new AlwaysInputContainer
|
InternalChild = sizableContainer = new SizeableAlwaysInputContainer(targetMode == ScalingMode.Everything)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
@ -209,13 +211,50 @@ namespace osu.Game.Graphics.Containers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AlwaysInputContainer : Container
|
private class SizeableAlwaysInputContainer : Container
|
||||||
{
|
{
|
||||||
|
[Resolved]
|
||||||
|
private GameHost host { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISafeArea safeArea { get; set; }
|
||||||
|
|
||||||
|
private readonly bool confineHostCursor;
|
||||||
|
private readonly LayoutValue cursorRectCache = new LayoutValue(Invalidation.RequiredParentSizeToFit);
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
public AlwaysInputContainer()
|
/// <summary>
|
||||||
|
/// Container used for sizing/positioning purposes in <see cref="ScalingContainer"/>. Always receives mouse input.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="confineHostCursor">Whether to confine the host cursor to the draw area of this container.</param>
|
||||||
|
/// <remarks>Cursor confinement will abide by the <see cref="OsuSetting.ConfineMouseMode"/> setting.</remarks>
|
||||||
|
public SizeableAlwaysInputContainer(bool confineHostCursor)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
this.confineHostCursor = confineHostCursor;
|
||||||
|
|
||||||
|
if (confineHostCursor)
|
||||||
|
AddLayout(cursorRectCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (confineHostCursor && !cursorRectCache.IsValid)
|
||||||
|
{
|
||||||
|
updateHostCursorConfineRect();
|
||||||
|
cursorRectCache.Validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateHostCursorConfineRect()
|
||||||
|
{
|
||||||
|
if (host.Window == null) return;
|
||||||
|
|
||||||
|
bool coversWholeScreen = Size == Vector2.One && safeArea.SafeAreaPadding.Value.Total == Vector2.Zero;
|
||||||
|
host.Window.CursorConfineRect = coversWholeScreen ? (RectangleF?)null : ToScreenSpace(DrawRectangle).AABBFloat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1140,10 +1140,8 @@ namespace osu.Game
|
|||||||
MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
|
MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ScreenChanged(IScreen current, IScreen newScreen)
|
private void screenChanged(IScreen current, IScreen newScreen)
|
||||||
{
|
{
|
||||||
skinEditor.Reset();
|
|
||||||
|
|
||||||
switch (newScreen)
|
switch (newScreen)
|
||||||
{
|
{
|
||||||
case IntroScreen intro:
|
case IntroScreen intro:
|
||||||
@ -1185,13 +1183,15 @@ namespace osu.Game
|
|||||||
else
|
else
|
||||||
BackButton.Hide();
|
BackButton.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skinEditor.SetTarget((Screen)newScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void screenPushed(IScreen lastScreen, IScreen newScreen) => ScreenChanged(lastScreen, newScreen);
|
private void screenPushed(IScreen lastScreen, IScreen newScreen) => screenChanged(lastScreen, newScreen);
|
||||||
|
|
||||||
private void screenExited(IScreen lastScreen, IScreen newScreen)
|
private void screenExited(IScreen lastScreen, IScreen newScreen)
|
||||||
{
|
{
|
||||||
ScreenChanged(lastScreen, newScreen);
|
screenChanged(lastScreen, newScreen);
|
||||||
|
|
||||||
if (newScreen == null)
|
if (newScreen == null)
|
||||||
Exit();
|
Exit();
|
||||||
|
@ -69,7 +69,7 @@ namespace osu.Game
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const double global_track_volume_adjust = 0.8;
|
private const double global_track_volume_adjust = 0.8;
|
||||||
|
|
||||||
public bool UseDevelopmentServer { get; }
|
public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
|
||||||
|
|
||||||
public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version();
|
public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version();
|
||||||
|
|
||||||
@ -177,7 +177,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
public OsuGameBase()
|
public OsuGameBase()
|
||||||
{
|
{
|
||||||
UseDevelopmentServer = DebugUtils.IsDebugBuild;
|
|
||||||
Name = @"osu!";
|
Name = @"osu!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -67,6 +68,12 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Any samples which may be used by this hit object that are non-standard.
|
||||||
|
/// This is used only to preload these samples ahead of time.
|
||||||
|
/// </summary>
|
||||||
|
public virtual IList<HitSampleInfo> AuxiliarySamples => ImmutableList<HitSampleInfo>.Empty;
|
||||||
|
|
||||||
public SampleControlPoint SampleControlPoint = SampleControlPoint.DEFAULT;
|
public SampleControlPoint SampleControlPoint = SampleControlPoint.DEFAULT;
|
||||||
public DifficultyControlPoint DifficultyControlPoint = DifficultyControlPoint.DEFAULT;
|
public DifficultyControlPoint DifficultyControlPoint = DifficultyControlPoint.DEFAULT;
|
||||||
|
|
||||||
|
@ -500,12 +500,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
=> new LegacyHitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newVolume.GetOr(Volume), newCustomSampleBank.GetOr(CustomSampleBank), newIsLayered.GetOr(IsLayered));
|
=> new LegacyHitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newVolume.GetOr(Volume), newCustomSampleBank.GetOr(CustomSampleBank), newIsLayered.GetOr(IsLayered));
|
||||||
|
|
||||||
public bool Equals(LegacyHitSampleInfo? other)
|
public bool Equals(LegacyHitSampleInfo? other)
|
||||||
=> base.Equals(other) && CustomSampleBank == other.CustomSampleBank && IsLayered == other.IsLayered;
|
=> base.Equals(other) && CustomSampleBank == other.CustomSampleBank;
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
=> obj is LegacyHitSampleInfo other && Equals(other);
|
=> obj is LegacyHitSampleInfo other && Equals(other);
|
||||||
|
|
||||||
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), CustomSampleBank, IsLayered);
|
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), CustomSampleBank);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileHitSampleInfo : LegacyHitSampleInfo, IEquatable<FileHitSampleInfo>
|
private class FileHitSampleInfo : LegacyHitSampleInfo, IEquatable<FileHitSampleInfo>
|
||||||
|
@ -3,22 +3,22 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.UI
|
namespace osu.Game.Rulesets.UI
|
||||||
{
|
{
|
||||||
@ -264,10 +264,25 @@ namespace osu.Game.Rulesets.UI
|
|||||||
var entry = CreateLifetimeEntry(hitObject);
|
var entry = CreateLifetimeEntry(hitObject);
|
||||||
lifetimeEntryMap[entry.HitObject] = entry;
|
lifetimeEntryMap[entry.HitObject] = entry;
|
||||||
|
|
||||||
|
preloadSamples(hitObject);
|
||||||
|
|
||||||
HitObjectContainer.Add(entry);
|
HitObjectContainer.Add(entry);
|
||||||
OnHitObjectAdded(entry.HitObject);
|
OnHitObjectAdded(entry.HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void preloadSamples(HitObject hitObject)
|
||||||
|
{
|
||||||
|
// prepare sample pools ahead of time so we're not initialising at runtime.
|
||||||
|
foreach (var sample in hitObject.Samples)
|
||||||
|
prepareSamplePool(hitObject.SampleControlPoint.ApplyTo(sample));
|
||||||
|
|
||||||
|
foreach (var sample in hitObject.AuxiliarySamples)
|
||||||
|
prepareSamplePool(hitObject.SampleControlPoint.ApplyTo(sample));
|
||||||
|
|
||||||
|
foreach (var nestedObject in hitObject.NestedHitObjects)
|
||||||
|
preloadSamples(nestedObject);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes a <see cref="HitObjectLifetimeEntry"/> for a pooled <see cref="HitObject"/> from this <see cref="Playfield"/>.
|
/// Removes a <see cref="HitObjectLifetimeEntry"/> for a pooled <see cref="HitObject"/> from this <see cref="Playfield"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -330,22 +345,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
DrawableHitObject IPooledHitObjectProvider.GetPooledDrawableRepresentation(HitObject hitObject, DrawableHitObject parent)
|
DrawableHitObject IPooledHitObjectProvider.GetPooledDrawableRepresentation(HitObject hitObject, DrawableHitObject parent)
|
||||||
{
|
{
|
||||||
var lookupType = hitObject.GetType();
|
var pool = prepareDrawableHitObjectPool(hitObject);
|
||||||
|
|
||||||
IDrawablePool pool;
|
|
||||||
|
|
||||||
// Tests may add derived hitobject instances for which pools don't exist. Try to find any applicable pool and dynamically assign the type if the pool exists.
|
|
||||||
if (!pools.TryGetValue(lookupType, out pool))
|
|
||||||
{
|
|
||||||
foreach (var (t, p) in pools)
|
|
||||||
{
|
|
||||||
if (!t.IsInstanceOfType(hitObject))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pools[lookupType] = pool = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (DrawableHitObject)pool?.Get(d =>
|
return (DrawableHitObject)pool?.Get(d =>
|
||||||
{
|
{
|
||||||
@ -372,14 +372,39 @@ namespace osu.Game.Rulesets.UI
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IDrawablePool prepareDrawableHitObjectPool(HitObject hitObject)
|
||||||
|
{
|
||||||
|
var lookupType = hitObject.GetType();
|
||||||
|
|
||||||
|
IDrawablePool pool;
|
||||||
|
|
||||||
|
// Tests may add derived hitobject instances for which pools don't exist. Try to find any applicable pool and dynamically assign the type if the pool exists.
|
||||||
|
if (!pools.TryGetValue(lookupType, out pool))
|
||||||
|
{
|
||||||
|
foreach (var (t, p) in pools)
|
||||||
|
{
|
||||||
|
if (!t.IsInstanceOfType(hitObject))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pools[lookupType] = pool = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
private readonly Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>> samplePools = new Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>>();
|
private readonly Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>> samplePools = new Dictionary<ISampleInfo, DrawablePool<PoolableSkinnableSample>>();
|
||||||
|
|
||||||
public PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo)
|
public PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo) => prepareSamplePool(sampleInfo).Get();
|
||||||
{
|
|
||||||
if (!samplePools.TryGetValue(sampleInfo, out var existingPool))
|
|
||||||
AddInternal(samplePools[sampleInfo] = existingPool = new DrawableSamplePool(sampleInfo, 1));
|
|
||||||
|
|
||||||
return existingPool.Get();
|
private DrawablePool<PoolableSkinnableSample> prepareSamplePool(ISampleInfo sampleInfo)
|
||||||
|
{
|
||||||
|
if (samplePools.TryGetValue(sampleInfo, out var pool)) return pool;
|
||||||
|
|
||||||
|
AddInternal(samplePools[sampleInfo] = pool = new DrawableSamplePool(sampleInfo, 1));
|
||||||
|
|
||||||
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DrawableSamplePool : DrawablePool<PoolableSkinnableSample>
|
private class DrawableSamplePool : DrawablePool<PoolableSkinnableSample>
|
||||||
|
@ -13,14 +13,17 @@ using osu.Framework.Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using Realms;
|
using Realms;
|
||||||
@ -55,7 +58,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private const int exit_delay = 3000;
|
private const int exit_delay = 3000;
|
||||||
|
|
||||||
private Sample seeya;
|
private SkinnableSound skinnableSeeya;
|
||||||
|
private ISample seeya;
|
||||||
|
|
||||||
protected virtual string SeeyaSampleName => "Intro/seeya";
|
protected virtual string SeeyaSampleName => "Intro/seeya";
|
||||||
|
|
||||||
@ -90,13 +94,17 @@ namespace osu.Game.Screens.Menu
|
|||||||
private BeatmapManager beatmaps { get; set; }
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config, Framework.Game game, RealmAccess realm)
|
private void load(OsuConfigManager config, Framework.Game game, RealmAccess realm, IAPIProvider api)
|
||||||
{
|
{
|
||||||
// prevent user from changing beatmap while the intro is still running.
|
// prevent user from changing beatmap while the intro is still running.
|
||||||
beatmap = Beatmap.BeginLease(false);
|
beatmap = Beatmap.BeginLease(false);
|
||||||
|
|
||||||
MenuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
|
MenuVoice = config.GetBindable<bool>(OsuSetting.MenuVoice);
|
||||||
MenuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
MenuMusic = config.GetBindable<bool>(OsuSetting.MenuMusic);
|
||||||
|
|
||||||
|
if (api.LocalUser.Value.IsSupporter)
|
||||||
|
AddInternal(skinnableSeeya = new SkinnableSound(new SampleInfo(SeeyaSampleName)));
|
||||||
|
else
|
||||||
seeya = audio.Samples.Get(SeeyaSampleName);
|
seeya = audio.Samples.Get(SeeyaSampleName);
|
||||||
|
|
||||||
// if the user has requested not to play theme music, we should attempt to find a random beatmap from their collection.
|
// if the user has requested not to play theme music, we should attempt to find a random beatmap from their collection.
|
||||||
@ -201,6 +209,14 @@ namespace osu.Game.Screens.Menu
|
|||||||
// we also handle the exit transition.
|
// we also handle the exit transition.
|
||||||
if (MenuVoice.Value)
|
if (MenuVoice.Value)
|
||||||
{
|
{
|
||||||
|
if (skinnableSeeya != null)
|
||||||
|
{
|
||||||
|
// resuming a screen (i.e. calling OnResume) happens before the screen itself becomes alive,
|
||||||
|
// therefore skinnable samples may not be updated yet with the recently selected skin.
|
||||||
|
// schedule after children to ensure skinnable samples have processed skin changes before playing.
|
||||||
|
ScheduleAfterChildren(() => skinnableSeeya.Play());
|
||||||
|
}
|
||||||
|
else
|
||||||
seeya.Play();
|
seeya.Play();
|
||||||
|
|
||||||
// if playing the outro voice, we have more time to have fun with the background track.
|
// if playing the outro voice, we have more time to have fun with the background track.
|
||||||
|
@ -13,7 +13,10 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Screens.Backgrounds;
|
using osu.Game.Screens.Backgrounds;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Menu
|
namespace osu.Game.Screens.Menu
|
||||||
@ -23,8 +26,11 @@ namespace osu.Game.Screens.Menu
|
|||||||
protected override string BeatmapHash => "64e00d7022195959bfa3109d09c2e2276c8f12f486b91fcf6175583e973b48f2";
|
protected override string BeatmapHash => "64e00d7022195959bfa3109d09c2e2276c8f12f486b91fcf6175583e973b48f2";
|
||||||
protected override string BeatmapFile => "welcome.osz";
|
protected override string BeatmapFile => "welcome.osz";
|
||||||
private const double delay_step_two = 2142;
|
private const double delay_step_two = 2142;
|
||||||
private Sample welcome;
|
|
||||||
private Sample pianoReverb;
|
private SkinnableSound skinnableWelcome;
|
||||||
|
private ISample welcome;
|
||||||
|
|
||||||
|
private ISample pianoReverb;
|
||||||
protected override string SeeyaSampleName => "Intro/Welcome/seeya";
|
protected override string SeeyaSampleName => "Intro/Welcome/seeya";
|
||||||
|
|
||||||
protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false)
|
protected override BackgroundScreen CreateBackground() => background = new BackgroundScreenDefault(false)
|
||||||
@ -40,10 +46,15 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(AudioManager audio)
|
private void load(AudioManager audio, IAPIProvider api)
|
||||||
{
|
{
|
||||||
if (MenuVoice.Value)
|
if (MenuVoice.Value)
|
||||||
|
{
|
||||||
|
if (api.LocalUser.Value.IsSupporter)
|
||||||
|
AddInternal(skinnableWelcome = new SkinnableSound(new SampleInfo(@"Intro/Welcome/welcome")));
|
||||||
|
else
|
||||||
welcome = audio.Samples.Get(@"Intro/Welcome/welcome");
|
welcome = audio.Samples.Get(@"Intro/Welcome/welcome");
|
||||||
|
}
|
||||||
|
|
||||||
pianoReverb = audio.Samples.Get(@"Intro/Welcome/welcome_piano");
|
pianoReverb = audio.Samples.Get(@"Intro/Welcome/welcome_piano");
|
||||||
}
|
}
|
||||||
@ -65,6 +76,9 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
AddInternal(intro);
|
AddInternal(intro);
|
||||||
|
|
||||||
|
if (skinnableWelcome != null)
|
||||||
|
skinnableWelcome.Play();
|
||||||
|
else
|
||||||
welcome?.Play();
|
welcome?.Play();
|
||||||
|
|
||||||
var reverbChannel = pianoReverb?.Play();
|
var reverbChannel = pianoReverb?.Play();
|
||||||
@ -100,13 +114,13 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private class WelcomeIntroSequence : Container
|
private class WelcomeIntroSequence : Container
|
||||||
{
|
{
|
||||||
private Sprite welcomeText;
|
private Drawable welcomeText;
|
||||||
private Container scaleContainer;
|
private Container scaleContainer;
|
||||||
|
|
||||||
public LogoVisualisation LogoVisualisation { get; private set; }
|
public LogoVisualisation LogoVisualisation { get; private set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(TextureStore textures, IAPIProvider api)
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
@ -135,15 +149,17 @@ namespace osu.Game.Screens.Menu
|
|||||||
Size = new Vector2(480),
|
Size = new Vector2(480),
|
||||||
Colour = Color4.Black
|
Colour = Color4.Black
|
||||||
},
|
},
|
||||||
welcomeText = new Sprite
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Texture = textures.Get(@"Intro/Welcome/welcome_text")
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (api.LocalUser.Value.IsSupporter)
|
||||||
|
scaleContainer.Add(welcomeText = new SkinnableSprite(@"Intro/Welcome/welcome_text"));
|
||||||
|
else
|
||||||
|
scaleContainer.Add(welcomeText = new Sprite { Texture = textures.Get(@"Intro/Welcome/welcome_text") });
|
||||||
|
|
||||||
|
welcomeText.Anchor = Anchor.Centre;
|
||||||
|
welcomeText.Origin = Anchor.Centre;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -334,6 +334,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
|
|||||||
// ID must be unset as we use this as a marker for whether this is a client-side (not-yet-created) room or not.
|
// ID must be unset as we use this as a marker for whether this is a client-side (not-yet-created) room or not.
|
||||||
r.RoomID.Value = null;
|
r.RoomID.Value = null;
|
||||||
|
|
||||||
|
// Null out dates because end date is not supported client-side and the settings overlay will populate a duration.
|
||||||
|
r.EndDate.Value = null;
|
||||||
|
r.Duration.Value = null;
|
||||||
|
|
||||||
Open(r);
|
Open(r);
|
||||||
|
|
||||||
joiningRoomOperation?.Dispose();
|
joiningRoomOperation?.Dispose();
|
||||||
|
@ -13,23 +13,13 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
||||||
{
|
{
|
||||||
public class BarHitErrorMeter : HitErrorMeter
|
public class BarHitErrorMeter : HitErrorMeter
|
||||||
{
|
{
|
||||||
private const int arrow_move_duration = 400;
|
private const int judgement_line_width = 14;
|
||||||
|
private const int judgement_line_height = 4;
|
||||||
private const int judgement_line_width = 6;
|
|
||||||
|
|
||||||
private const int bar_height = 200;
|
|
||||||
|
|
||||||
private const int bar_width = 2;
|
|
||||||
|
|
||||||
private const int spacing = 2;
|
|
||||||
|
|
||||||
private const float chevron_size = 8;
|
|
||||||
|
|
||||||
private SpriteIcon arrow;
|
private SpriteIcon arrow;
|
||||||
private SpriteIcon iconEarly;
|
private SpriteIcon iconEarly;
|
||||||
@ -50,17 +40,94 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChild = new FillFlowContainer
|
const int centre_marker_size = 8;
|
||||||
|
const int bar_height = 200;
|
||||||
|
const int bar_width = 2;
|
||||||
|
const float chevron_size = 8;
|
||||||
|
const float icon_size = 14;
|
||||||
|
|
||||||
|
var hitWindows = HitWindows.GetAllAvailableWindows().ToArray();
|
||||||
|
|
||||||
|
InternalChild = new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Height = bar_height,
|
Height = bar_height,
|
||||||
Direction = FillDirection.Horizontal,
|
|
||||||
Spacing = new Vector2(spacing, 0),
|
|
||||||
Margin = new MarginPadding(2),
|
Margin = new MarginPadding(2),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
colourBars = new Container
|
||||||
|
{
|
||||||
|
Name = "colour axis",
|
||||||
|
X = chevron_size,
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Width = judgement_line_width,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
iconEarly = new SpriteIcon
|
||||||
|
{
|
||||||
|
Y = -10,
|
||||||
|
Size = new Vector2(icon_size),
|
||||||
|
Icon = FontAwesome.Solid.ShippingFast,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
iconLate = new SpriteIcon
|
||||||
|
{
|
||||||
|
Y = 10,
|
||||||
|
Size = new Vector2(icon_size),
|
||||||
|
Icon = FontAwesome.Solid.Bicycle,
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
},
|
||||||
|
colourBarsEarly = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Width = bar_width,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Height = 0.5f,
|
||||||
|
Scale = new Vector2(1, -1),
|
||||||
|
},
|
||||||
|
colourBarsLate = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Width = bar_width,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Height = 0.5f,
|
||||||
|
},
|
||||||
|
new Circle
|
||||||
|
{
|
||||||
|
Name = "middle marker behind",
|
||||||
|
Colour = GetColourForHitResult(hitWindows.Last().result),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(centre_marker_size),
|
||||||
|
},
|
||||||
|
judgementsContainer = new Container
|
||||||
|
{
|
||||||
|
Name = "judgements",
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = judgement_line_width,
|
||||||
|
},
|
||||||
|
new Circle
|
||||||
|
{
|
||||||
|
Name = "middle marker in front",
|
||||||
|
Colour = GetColourForHitResult(hitWindows.Last().result).Darken(0.3f),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(centre_marker_size),
|
||||||
|
Scale = new Vector2(0.5f),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
|
Name = "average chevron",
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Width = chevron_size,
|
Width = chevron_size,
|
||||||
@ -75,58 +142,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
Size = new Vector2(chevron_size),
|
Size = new Vector2(chevron_size),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colourBars = new Container
|
|
||||||
{
|
|
||||||
Width = bar_width,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
colourBarsEarly = new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Height = 0.5f,
|
|
||||||
Scale = new Vector2(1, -1),
|
|
||||||
},
|
|
||||||
colourBarsLate = new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Height = 0.5f,
|
|
||||||
},
|
|
||||||
iconEarly = new SpriteIcon
|
|
||||||
{
|
|
||||||
Y = -10,
|
|
||||||
Size = new Vector2(10),
|
|
||||||
Icon = FontAwesome.Solid.ShippingFast,
|
|
||||||
Anchor = Anchor.TopCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
},
|
|
||||||
iconLate = new SpriteIcon
|
|
||||||
{
|
|
||||||
Y = 10,
|
|
||||||
Size = new Vector2(10),
|
|
||||||
Icon = FontAwesome.Solid.Bicycle,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
judgementsContainer = new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
Width = judgement_line_width,
|
|
||||||
RelativeSizeAxes = Axes.Y,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
createColourBars();
|
createColourBars(hitWindows);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -149,10 +168,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
iconLate.Rotation = -Rotation;
|
iconLate.Rotation = -Rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createColourBars()
|
private void createColourBars((HitResult result, double length)[] windows)
|
||||||
{
|
{
|
||||||
var windows = HitWindows.GetAllAvailableWindows().ToArray();
|
|
||||||
|
|
||||||
// max to avoid div-by-zero.
|
// max to avoid div-by-zero.
|
||||||
maxHitWindow = Math.Max(1, windows.First().length);
|
maxHitWindow = Math.Max(1, windows.First().length);
|
||||||
|
|
||||||
@ -166,17 +183,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
colourBarsLate.Add(createColourBar(result, hitWindow, i == 0));
|
colourBarsLate.Add(createColourBar(result, hitWindow, i == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// a little nub to mark the centre point.
|
Drawable createColourBar(HitResult result, float height, bool requireGradient = false)
|
||||||
var centre = createColourBar(windows.Last().result, 0.01f);
|
|
||||||
centre.Anchor = centre.Origin = Anchor.CentreLeft;
|
|
||||||
centre.Width = 2.5f;
|
|
||||||
colourBars.Add(centre);
|
|
||||||
|
|
||||||
Drawable createColourBar(HitResult result, float height, bool first = false)
|
|
||||||
{
|
{
|
||||||
var colour = GetColourForHitResult(result);
|
var colour = GetColourForHitResult(result);
|
||||||
|
|
||||||
if (first)
|
if (requireGradient)
|
||||||
{
|
{
|
||||||
// the first bar needs gradient rendering.
|
// the first bar needs gradient rendering.
|
||||||
const float gradient_start = 0.8f;
|
const float gradient_start = 0.8f;
|
||||||
@ -220,6 +231,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
|
|
||||||
protected override void OnNewJudgement(JudgementResult judgement)
|
protected override void OnNewJudgement(JudgementResult judgement)
|
||||||
{
|
{
|
||||||
|
const int arrow_move_duration = 800;
|
||||||
|
|
||||||
if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0)
|
if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -243,46 +256,52 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
|
|||||||
judgementsContainer.Add(new JudgementLine
|
judgementsContainer.Add(new JudgementLine
|
||||||
{
|
{
|
||||||
Y = getRelativeJudgementPosition(judgement.TimeOffset),
|
Y = getRelativeJudgementPosition(judgement.TimeOffset),
|
||||||
Origin = Anchor.CentreLeft,
|
Colour = GetColourForHitResult(judgement.Type),
|
||||||
});
|
});
|
||||||
|
|
||||||
arrow.MoveToY(
|
arrow.MoveToY(
|
||||||
getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1)
|
getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1)
|
||||||
, arrow_move_duration, Easing.Out);
|
, arrow_move_duration, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getRelativeJudgementPosition(double value) => Math.Clamp((float)((value / maxHitWindow) + 1) / 2, 0, 1);
|
private float getRelativeJudgementPosition(double value) => Math.Clamp((float)((value / maxHitWindow) + 1) / 2, 0, 1);
|
||||||
|
|
||||||
internal class JudgementLine : CompositeDrawable
|
internal class JudgementLine : CompositeDrawable
|
||||||
{
|
{
|
||||||
private const int judgement_fade_duration = 5000;
|
|
||||||
|
|
||||||
public JudgementLine()
|
public JudgementLine()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
RelativePositionAxes = Axes.Y;
|
RelativePositionAxes = Axes.Y;
|
||||||
Height = 3;
|
Height = judgement_line_height;
|
||||||
|
|
||||||
InternalChild = new CircularContainer
|
Blending = BlendingParameters.Additive;
|
||||||
{
|
|
||||||
Masking = true,
|
Origin = Anchor.Centre;
|
||||||
RelativeSizeAxes = Axes.Both,
|
Anchor = Anchor.TopCentre;
|
||||||
Child = new Box
|
|
||||||
|
InternalChild = new Circle
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
|
const int judgement_fade_in_duration = 100;
|
||||||
|
const int judgement_fade_out_duration = 5000;
|
||||||
|
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Alpha = 0;
|
||||||
Width = 0;
|
Width = 0;
|
||||||
|
|
||||||
this.ResizeWidthTo(1, 200, Easing.OutElasticHalf);
|
this
|
||||||
this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration).Expire();
|
.FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint)
|
||||||
|
.ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint)
|
||||||
|
.Then()
|
||||||
|
.FadeOut(judgement_fade_out_duration)
|
||||||
|
.ResizeWidthTo(0, judgement_fade_out_duration, Easing.InQuint)
|
||||||
|
.Expire();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Skinning.Editor
|
|||||||
|
|
||||||
protected override bool StartHidden => true;
|
protected override bool StartHidden => true;
|
||||||
|
|
||||||
private readonly Drawable targetScreen;
|
private Drawable targetScreen;
|
||||||
|
|
||||||
private OsuTextFlowContainer headerText;
|
private OsuTextFlowContainer headerText;
|
||||||
|
|
||||||
@ -42,11 +42,13 @@ namespace osu.Game.Skinning.Editor
|
|||||||
|
|
||||||
private bool hasBegunMutating;
|
private bool hasBegunMutating;
|
||||||
|
|
||||||
|
private Container content;
|
||||||
|
|
||||||
public SkinEditor(Drawable targetScreen)
|
public SkinEditor(Drawable targetScreen)
|
||||||
{
|
{
|
||||||
this.targetScreen = targetScreen;
|
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
UpdateTargetScreen(targetScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -113,13 +115,9 @@ namespace osu.Game.Skinning.Editor
|
|||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
RequestPlacement = placeComponent
|
RequestPlacement = placeComponent
|
||||||
},
|
},
|
||||||
new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new SkinBlueprintContainer(targetScreen),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,6 +145,21 @@ namespace osu.Game.Skinning.Editor
|
|||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateTargetScreen(Drawable targetScreen)
|
||||||
|
{
|
||||||
|
this.targetScreen = targetScreen;
|
||||||
|
|
||||||
|
Scheduler.AddOnce(loadBlueprintContainer);
|
||||||
|
|
||||||
|
void loadBlueprintContainer()
|
||||||
|
{
|
||||||
|
content.Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new SkinBlueprintContainer(targetScreen),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void skinChanged()
|
private void skinChanged()
|
||||||
{
|
{
|
||||||
headerText.Clear();
|
headerText.Clear();
|
||||||
@ -171,7 +184,12 @@ namespace osu.Game.Skinning.Editor
|
|||||||
|
|
||||||
private void placeComponent(Type type)
|
private void placeComponent(Type type)
|
||||||
{
|
{
|
||||||
var targetContainer = getTarget(SkinnableTarget.MainHUDComponents);
|
var target = availableTargets.FirstOrDefault()?.Target;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var targetContainer = getTarget(target.Value);
|
||||||
|
|
||||||
if (targetContainer == null)
|
if (targetContainer == null)
|
||||||
return;
|
return;
|
||||||
|
@ -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.Diagnostics;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -8,6 +9,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
|
||||||
@ -114,15 +116,39 @@ namespace osu.Game.Skinning.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exit any existing skin editor due to the game state changing.
|
/// Set a new target screen which will be used to find skinnable components.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Reset()
|
public void SetTarget(Screen screen)
|
||||||
{
|
{
|
||||||
skinEditor?.Save();
|
if (skinEditor == null) return;
|
||||||
skinEditor?.Hide();
|
|
||||||
skinEditor?.Expire();
|
|
||||||
|
|
||||||
|
skinEditor.Save();
|
||||||
|
|
||||||
|
// AddOnce with parameter will ensure the newest target is loaded if there is any overlap.
|
||||||
|
Scheduler.AddOnce(setTarget, screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTarget(Screen target)
|
||||||
|
{
|
||||||
|
Debug.Assert(skinEditor != null);
|
||||||
|
|
||||||
|
if (!target.IsCurrentScreen())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!target.IsLoaded)
|
||||||
|
{
|
||||||
|
Scheduler.AddOnce(setTarget, target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skinEditor.State.Value == Visibility.Visible)
|
||||||
|
skinEditor.UpdateTargetScreen(target);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skinEditor.Hide();
|
||||||
|
skinEditor.Expire();
|
||||||
skinEditor = null;
|
skinEditor = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
@ -73,31 +72,7 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
protected override Vector2 DrawScale
|
protected override Vector2 DrawScale
|
||||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y) * VectorScale;
|
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y) * VectorScale;
|
||||||
|
|
||||||
public override Anchor Origin
|
public override Anchor Origin => StoryboardExtensions.AdjustOrigin(base.Origin, VectorScale, FlipH, FlipV);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var origin = base.Origin;
|
|
||||||
|
|
||||||
if (FlipH)
|
|
||||||
{
|
|
||||||
if (origin.HasFlagFast(Anchor.x0))
|
|
||||||
origin = Anchor.x2 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
|
||||||
else if (origin.HasFlagFast(Anchor.x2))
|
|
||||||
origin = Anchor.x0 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FlipV)
|
|
||||||
{
|
|
||||||
if (origin.HasFlagFast(Anchor.y0))
|
|
||||||
origin = Anchor.y2 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
|
||||||
else if (origin.HasFlagFast(Anchor.y2))
|
|
||||||
origin = Anchor.y0 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
|
||||||
}
|
|
||||||
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsPresent
|
public override bool IsPresent
|
||||||
=> !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent;
|
=> !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
@ -73,31 +72,7 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
protected override Vector2 DrawScale
|
protected override Vector2 DrawScale
|
||||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y) * VectorScale;
|
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y) * VectorScale;
|
||||||
|
|
||||||
public override Anchor Origin
|
public override Anchor Origin => StoryboardExtensions.AdjustOrigin(base.Origin, VectorScale, FlipH, FlipV);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var origin = base.Origin;
|
|
||||||
|
|
||||||
if (FlipH)
|
|
||||||
{
|
|
||||||
if (origin.HasFlagFast(Anchor.x0))
|
|
||||||
origin = Anchor.x2 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
|
||||||
else if (origin.HasFlagFast(Anchor.x2))
|
|
||||||
origin = Anchor.x0 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FlipV)
|
|
||||||
{
|
|
||||||
if (origin.HasFlagFast(Anchor.y0))
|
|
||||||
origin = Anchor.y2 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
|
||||||
else if (origin.HasFlagFast(Anchor.y2))
|
|
||||||
origin = Anchor.y0 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
|
||||||
}
|
|
||||||
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsPresent
|
public override bool IsPresent
|
||||||
=> !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent;
|
=> !float.IsNaN(DrawPosition.X) && !float.IsNaN(DrawPosition.Y) && base.IsPresent;
|
||||||
|
43
osu.Game/Storyboards/StoryboardExtensions.cs
Normal file
43
osu.Game/Storyboards/StoryboardExtensions.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// 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.Extensions.EnumExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Storyboards
|
||||||
|
{
|
||||||
|
public static class StoryboardExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Given an origin and a set of properties, adjust the origin to display the sprite/animation correctly.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="origin">The current origin.</param>
|
||||||
|
/// <param name="vectorScale">The vector scale.</param>
|
||||||
|
/// <param name="flipH">Whether the element is flipped horizontally.</param>
|
||||||
|
/// <param name="flipV">Whether the element is flipped vertically.</param>
|
||||||
|
/// <returns>The adjusted origin.</returns>
|
||||||
|
public static Anchor AdjustOrigin(Anchor origin, Vector2 vectorScale, bool flipH, bool flipV)
|
||||||
|
{
|
||||||
|
// Either flip horizontally or negative X scale, but not both.
|
||||||
|
if (flipH ^ (vectorScale.X < 0))
|
||||||
|
{
|
||||||
|
if (origin.HasFlagFast(Anchor.x0))
|
||||||
|
origin = Anchor.x2 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||||
|
else if (origin.HasFlagFast(Anchor.x2))
|
||||||
|
origin = Anchor.x0 | (origin & (Anchor.y0 | Anchor.y1 | Anchor.y2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either flip vertically or negative Y scale, but not both.
|
||||||
|
if (flipV ^ (vectorScale.Y < 0))
|
||||||
|
{
|
||||||
|
if (origin.HasFlagFast(Anchor.y0))
|
||||||
|
origin = Anchor.y2 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||||
|
else if (origin.HasFlagFast(Anchor.y2))
|
||||||
|
origin = Anchor.y0 | (origin & (Anchor.x0 | Anchor.x1 | Anchor.x2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Realm" Version="10.10.0" />
|
<PackageReference Include="Realm" Version="10.10.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.308.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.314.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.304.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.304.0" />
|
||||||
<PackageReference Include="Sentry" Version="3.14.1" />
|
<PackageReference Include="Sentry" Version="3.14.1" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||||
|
@ -61,7 +61,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="2022.308.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.314.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.304.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.304.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
||||||
@ -84,7 +84,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2022.308.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2022.314.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user