Skip to content

Commit

Permalink
Merge branch 'master' into health-animates-in-intro
Browse files Browse the repository at this point in the history
  • Loading branch information
peppy committed Oct 6, 2023
2 parents bd71403 + cc62100 commit 1a60e6d
Show file tree
Hide file tree
Showing 16 changed files with 491 additions and 194 deletions.
487 changes: 323 additions & 164 deletions .github/workflows/diffcalc.yml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public partial class LegacyBananaPiece : LegacyCatchHitObjectPiece
{
private static readonly Vector2 banana_max_size = new Vector2(128);
private static readonly Vector2 banana_max_size = new Vector2(160);

protected override void LoadComplete()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
public partial class LegacyDropletPiece : LegacyCatchHitObjectPiece
{
private static readonly Vector2 droplet_max_size = new Vector2(82, 103);
private static readonly Vector2 droplet_max_size = new Vector2(160);

public LegacyDropletPiece()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{
internal partial class LegacyFruitPiece : LegacyCatchHitObjectPiece
{
private static readonly Vector2 fruit_max_size = new Vector2(128);
private static readonly Vector2 fruit_max_size = new Vector2(160);

protected override void LoadComplete()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private void load()
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png.
InternalChildren = new[]
{
CircleSprite = new LegacyKiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName)?.WithMaximumSize(OsuHitObject.OBJECT_DIMENSIONS) })
CircleSprite = new LegacyKiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName)?.WithMaximumSize(OsuHitObject.OBJECT_DIMENSIONS * 2) })
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Expand All @@ -76,7 +76,7 @@ private void load()
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Child = OverlaySprite = new LegacyKiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d, maxSize: OsuHitObject.OBJECT_DIMENSIONS))
Child = OverlaySprite = new LegacyKiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d, maxSize: OsuHitObject.OBJECT_DIMENSIONS * 2))
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private void load(ISkinSource skinSource)

var skin = skinSource.FindProvider(s => s.GetTexture(lookupName) != null);

InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS) ?? Empty()).With(d =>
InternalChild = arrow = (skin?.GetAnimation(lookupName, true, true, maxSize: OsuHitObject.OBJECT_DIMENSIONS * 2) ?? Empty()).With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
Expand Down
5 changes: 2 additions & 3 deletions osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Skinning;
using osuTK.Graphics;
Expand Down Expand Up @@ -47,7 +46,7 @@ private void load()
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = skin.GetTexture("sliderb-nd")?.WithMaximumSize(OsuHitObject.OBJECT_DIMENSIONS),
Texture = skin.GetTexture("sliderb-nd")?.WithMaximumSize(OsuLegacySkinTransformer.MAX_FOLLOW_CIRCLE_AREA_SIZE),
Colour = new Color4(5, 5, 5, 255),
},
LegacyColourCompatibility.ApplyWithDoubledAlpha(animationContent.With(d =>
Expand All @@ -59,7 +58,7 @@ private void load()
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Texture = skin.GetTexture("sliderb-spec")?.WithMaximumSize(OsuHitObject.OBJECT_DIMENSIONS),
Texture = skin.GetTexture("sliderb-spec")?.WithMaximumSize(OsuLegacySkinTransformer.MAX_FOLLOW_CIRCLE_AREA_SIZE),
Blending = BlendingParameters.Additive,
},
};
Expand Down
19 changes: 15 additions & 4 deletions osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ public class OsuLegacySkinTransformer : LegacySkinTransformer
/// </summary>
public const float LEGACY_CIRCLE_RADIUS = OsuHitObject.OBJECT_RADIUS - 5;

/// <summary>
/// The maximum allowed size of sprites that reside in the follow circle area of a slider.
/// </summary>
/// <remarks>
/// The reason this is extracted out to a constant, rather than be inlined in the follow circle sprite retrieval,
/// is that some skins will use `sliderb` elements to emulate a slider follow circle with slightly different visual effects applied
/// (`sliderb` is always shown and doesn't pulsate; `sliderfollowcircle` isn't always shown and pulsates).
/// </remarks>
public static readonly Vector2 MAX_FOLLOW_CIRCLE_AREA_SIZE = OsuHitObject.OBJECT_DIMENSIONS * 3;

public OsuLegacySkinTransformer(ISkin skin)
: base(skin)
{
Expand All @@ -42,14 +52,14 @@ public OsuLegacySkinTransformer(ISkin skin)
return this.GetAnimation("sliderscorepoint", false, false);

case OsuSkinComponents.SliderFollowCircle:
var followCircleContent = this.GetAnimation("sliderfollowcircle", true, true, true, maxSize: new Vector2(308f));
var followCircleContent = this.GetAnimation("sliderfollowcircle", true, true, true, maxSize: MAX_FOLLOW_CIRCLE_AREA_SIZE);
if (followCircleContent != null)
return new LegacyFollowCircle(followCircleContent);

return null;

case OsuSkinComponents.SliderBall:
var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: "", maxSize: OsuHitObject.OBJECT_DIMENSIONS);
var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: "", maxSize: MAX_FOLLOW_CIRCLE_AREA_SIZE);

// todo: slider ball has a custom frame delay based on velocity
// Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
Expand Down Expand Up @@ -139,10 +149,11 @@ public OsuLegacySkinTransformer(ISkin skin)
if (!this.HasFont(LegacyFont.HitCircle))
return null;

return new LegacySpriteText(LegacyFont.HitCircle, OsuHitObject.OBJECT_DIMENSIONS)
const float hitcircle_text_scale = 0.8f;
return new LegacySpriteText(LegacyFont.HitCircle, OsuHitObject.OBJECT_DIMENSIONS * 2 / hitcircle_text_scale)
{
// stable applies a blanket 0.8x scale to hitcircle fonts
Scale = new Vector2(0.8f),
Scale = new Vector2(hitcircle_text_scale),
};

case OsuSkinComponents.SpinnerBody:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,48 @@ public void TestHitNoneSwell()
AddAssert("all tick offsets are 0", () => JudgementResults.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
}

[Test]
public void TestAtMostOneSwellTickJudgedPerFrame()
{
const double swell_time = 1000;

Swell swell = new Swell
{
StartTime = swell_time,
Duration = 1000,
RequiredHits = 10
};

List<ReplayFrame> frames = new List<ReplayFrame>
{
new TaikoReplayFrame(1000),
new TaikoReplayFrame(1250, TaikoAction.LeftCentre, TaikoAction.LeftRim),
new TaikoReplayFrame(1251),
new TaikoReplayFrame(1500, TaikoAction.LeftCentre, TaikoAction.LeftRim, TaikoAction.RightCentre, TaikoAction.RightRim),
new TaikoReplayFrame(1501),
new TaikoReplayFrame(2000),
};

PerformTest(frames, CreateBeatmap(swell));

AssertJudgementCount(11);

// this is a charitable interpretation of the inputs.
//
// for the frame at time 1250, we only count either one of the input actions - simple.
//
// for the frame at time 1500, we give the user the benefit of the doubt,
// and we ignore actions that wouldn't otherwise cause a hit due to not alternating,
// but we still count one (just one) of the actions that _would_ normally cause a hit.
// this is done as a courtesy to avoid stuff like key chattering after press blocking legitimate inputs.
for (int i = 0; i < 2; i++)
AssertResult<SwellTick>(i, HitResult.IgnoreHit);
for (int i = 2; i < swell.RequiredHits; i++)
AssertResult<SwellTick>(i, HitResult.IgnoreMiss);

AssertResult<Swell>(0, HitResult.IgnoreMiss);
}

/// <summary>
/// Ensure input is correctly sent to subsequent hits if a swell is fully completed.
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Screens.Play;
using osu.Game.Skinning;

namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Expand All @@ -38,6 +39,8 @@ public partial class DrawableSwell : DrawableTaikoHitObject<Swell>
private readonly CircularContainer targetRing;
private readonly CircularContainer expandingRing;

private double? lastPressHandleTime;

public override bool DisplayResult => false;

public DrawableSwell()
Expand Down Expand Up @@ -140,6 +143,7 @@ protected override void OnFree()
UnproxyContent();

lastWasCentre = null;
lastPressHandleTime = null;
}

protected override void AddNestedHitObject(DrawableHitObject hitObject)
Expand Down Expand Up @@ -266,6 +270,9 @@ protected override void Update()
ProxyContent();
else
UnproxyContent();

if ((Clock as IGameplayClock)?.IsRewinding == true)
lastPressHandleTime = null;
}

private bool? lastWasCentre;
Expand All @@ -285,7 +292,14 @@ public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
if (lastWasCentre == isCentre)
return false;

// If we've already successfully judged a tick this frame, do not judge more.
// Note that the ordering is important here - this is intentionally placed after the alternating check.
// That is done to prevent accidental double inputs blocking simultaneous but legitimate hits from registering.
if (lastPressHandleTime == Time.Current)
return true;

lastWasCentre = isCentre;
lastPressHandleTime = Time.Current;

UpdateResult(true);

Expand Down
5 changes: 3 additions & 2 deletions osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
public partial class LegacyCirclePiece : CompositeDrawable, IHasAccentColour
{
private static readonly Vector2 circle_piece_size = new Vector2(128);
private static readonly Vector2 max_circle_sprite_size = new Vector2(160);

private Drawable backgroundLayer = null!;
private Drawable? foregroundLayer;
Expand Down Expand Up @@ -54,9 +55,9 @@ private void load(ISkinSource skin, DrawableHitObject drawableHitObject, IBeatSy

string prefix = ((drawableHitObject.HitObject as TaikoStrongableHitObject)?.IsStrong ?? false) ? big_hit : normal_hit;

return skin.GetAnimation($"{prefix}{lookup}", true, false, maxSize: circle_piece_size) ??
return skin.GetAnimation($"{prefix}{lookup}", true, false, maxSize: max_circle_sprite_size) ??
// fallback to regular size if "big" version doesn't exist.
skin.GetAnimation($"{normal_hit}{lookup}", true, false, maxSize: circle_piece_size);
skin.GetAnimation($"{normal_hit}{lookup}", true, false, maxSize: max_circle_sprite_size);
}

// backgroundLayer is guaranteed to exist due to the pre-check in TaikoLegacySkinTransformer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.IO;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
Expand Down Expand Up @@ -173,7 +174,7 @@ public void TestReplayExport()
string? filePath = null;

// Files starting with _ are temporary, created by CreateFileSafely call.
AddUntilStep("wait for export file", () => filePath = LocalStorage.GetFiles("exports").SingleOrDefault(f => !f.StartsWith("_", StringComparison.Ordinal)), () => Is.Not.Null);
AddUntilStep("wait for export file", () => filePath = LocalStorage.GetFiles("exports").SingleOrDefault(f => !Path.GetFileName(f).StartsWith("_", StringComparison.Ordinal)), () => Is.Not.Null);
AddAssert("filesize is non-zero", () =>
{
using (var stream = LocalStorage.GetStream(filePath))
Expand Down
73 changes: 65 additions & 8 deletions osu.Game.Tests/Visual/Gameplay/TestScenePlayerMaxDimensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Game.IO;
using osu.Game.Rulesets;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

namespace osu.Game.Tests.Visual.Gameplay
{
Expand All @@ -23,6 +29,9 @@ namespace osu.Game.Tests.Visual.Gameplay
/// </remarks>
public partial class TestScenePlayerMaxDimensions : TestSceneAllRulesetPlayers
{
// scale textures to 4 times their size.
private const int scale_factor = 4;

protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
Expand Down Expand Up @@ -63,18 +72,66 @@ public event Action? SourceChanged
remove { }
}

public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT)
public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => this;
public IEnumerable<ISkin> AllSources => new[] { this };

protected override IResourceStore<TextureUpload> CreateTextureLoaderStore(IStorageResourceProvider resources, IResourceStore<byte[]> storage)
=> new UpscaledTextureLoaderStore(base.CreateTextureLoaderStore(resources, storage));

private class UpscaledTextureLoaderStore : IResourceStore<TextureUpload>
{
var texture = base.GetTexture(componentName, wrapModeS, wrapModeT);
private readonly IResourceStore<TextureUpload>? textureStore;

if (texture != null)
texture.ScaleAdjust /= 8f;
public UpscaledTextureLoaderStore(IResourceStore<TextureUpload>? textureStore)
{
this.textureStore = textureStore;
}

return texture;
}
public void Dispose()
{
textureStore?.Dispose();
}

public ISkin FindProvider(Func<ISkin, bool> lookupFunction) => this;
public IEnumerable<ISkin> AllSources => new[] { this };
public TextureUpload Get(string name)
{
var textureUpload = textureStore?.Get(name);

// NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp.
if (textureUpload == null)
return null!;

return upscale(textureUpload);
}

public async Task<TextureUpload> GetAsync(string name, CancellationToken cancellationToken = new CancellationToken())
{
// NRT not enabled on framework side classes (IResourceStore / TextureLoaderStore), welp.
if (textureStore == null)
return null!;

var textureUpload = await textureStore.GetAsync(name, cancellationToken).ConfigureAwait(false);

if (textureUpload == null)
return null!;

return await Task.Run(() => upscale(textureUpload), cancellationToken).ConfigureAwait(false);
}

private TextureUpload upscale(TextureUpload textureUpload)
{
var image = Image.LoadPixelData(textureUpload.Data.ToArray(), textureUpload.Width, textureUpload.Height);

// The original texture upload will no longer be returned or used.
textureUpload.Dispose();

image.Mutate(i => i.Resize(new Size(textureUpload.Width, textureUpload.Height) * scale_factor));
return new TextureUpload(image);
}

public Stream? GetStream(string name) => textureStore?.GetStream(name);

public IEnumerable<string> GetAvailableResources() => textureStore?.GetAvailableResources() ?? Array.Empty<string>();
}
}
}
}
11 changes: 9 additions & 2 deletions osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ protected override void LoadComplete()
controlPointGroups.BindTo(editorBeatmap.ControlPointInfo.Groups);
controlPointGroups.BindCollectionChanged((_, _) => updateTimingGroup());

beatLength.BindValueChanged(_ => regenerateDisplay(true), true);
beatLength.BindValueChanged(_ => Scheduler.AddOnce(regenerateDisplay, true), true);

displayLocked.BindValueChanged(locked =>
{
Expand Down Expand Up @@ -186,11 +186,18 @@ private void showFromTime(double time, bool animated)
return;

displayedTime = time;
regenerateDisplay(animated);
Scheduler.AddOnce(regenerateDisplay, animated);
}

private void regenerateDisplay(bool animated)
{
// Before a track is loaded, it won't have a valid length, which will break things.
if (!beatmap.Value.Track.IsLoaded)
{
Scheduler.AddOnce(regenerateDisplay, animated);
return;
}

double index = (displayedTime - selectedGroupStartTime) / timingPoint.BeatLength;

// Chosen as a pretty usable number across all BPMs.
Expand Down
Loading

0 comments on commit 1a60e6d

Please sign in to comment.