Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public partial class CatchModFlashlight : ModFlashlight<CatchHitObject>

public override BindableBool ComboBasedSize { get; } = new BindableBool(true);

public override float DefaultFlashlightSize => 325;
public override float DefaultFlashlightSize => 203.125f;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how to feel about this 1.6 thing being just directly baked into constants rather than 325 * 1.6f or similar

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100% has to be a constant, hopefully in the place its primarily used.

Copy link
Member Author

@frenzibyte frenzibyte Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these numbers bare any meaning before the constant is applied? If not, I see no reason to try extracting a constant for this. If anything, I would tweak DefaultFlashlightSize 3 pixels down to 200 and make this feel more natural to read instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.6 is the playfield and stable scale factor, if that's what you're asking. it's like, the meaning-of-life as far as stable is concerned.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to ask about the current numbers of the DefaultFlashlightSize (200 in osu! and 325 in catch before this PR), if they're not referenced anywhere else and they only represent themselves, I'm not sure it's necessary to split the constant away from them rather than just inline the computation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on #20566 it looks like the numbers are arbitrary constants anyway, so I guess I don't really care that much. that said 1.6 is used allllll over if you grep for it


protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield);

Expand Down
20 changes: 0 additions & 20 deletions osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,6 @@ public partial class TestSceneOsuModFlashlight : OsuModTestScene
[Test]
public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new OsuModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true });

[Test]
public void TestPlayfieldBasedSize()
{
OsuModFlashlight flashlight;
CreateModTest(new ModTestData
{
Mods = [flashlight = new OsuModFlashlight(), new OsuModBarrelRoll()],
PassCondition = () =>
{
var flashlightOverlay = Player.DrawableRuleset.Overlays
.ChildrenOfType<ModFlashlight<OsuHitObject>.Flashlight>()
.First();

// the combo check is here because the flashlight radius decreases for the first time at 100 combo
// and hardcoding it here eliminates the need to meddle in flashlight internals further by e.g. exposing `GetComboScaleFor()`
return flashlightOverlay.GetSize() < flashlight.DefaultFlashlightSize && Player.GameplayState.ScoreProcessor.Combo.Value < 100;
}
});
}

[Test]
public void TestSliderDimsOnlyAfterStartTime()
{
Expand Down
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public partial class OsuModFlashlight : ModFlashlight<OsuHitObject>, IApplicable

public override BindableBool ComboBasedSize { get; } = new BindableBool(true);

public override float DefaultFlashlightSize => 200;
public override float DefaultFlashlightSize => 125;

private OsuFlashlight flashlight = null!;

Expand Down
31 changes: 31 additions & 0 deletions osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.UI;
using osuTK;
Expand All @@ -12,6 +15,34 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods
{
public partial class TestSceneTaikoModFlashlight : TaikoModTestScene
{
[Test]
public void TestAspectRatios([Values] bool withClassicMod)
{
if (withClassicMod)
CreateModTest(new ModTestData { Mods = new Mod[] { new TaikoModFlashlight(), new TaikoModClassic() }, PassCondition = () => true });
else
CreateModTest(new ModTestData { Mod = new TaikoModFlashlight(), PassCondition = () => true });

AddStep("clear dim", () => LocalConfig.SetValue(OsuSetting.DimLevel, 0.0));

AddStep("reset", () => Stack.FillMode = FillMode.Stretch);
AddStep("set to 16:9", () =>
{
Stack.FillAspectRatio = 16 / 9f;
Stack.FillMode = FillMode.Fit;
});
AddStep("set to 4:3", () =>
{
Stack.FillAspectRatio = 4 / 3f;
Stack.FillMode = FillMode.Fit;
});
AddSliderStep("aspect ratio", 0.01f, 5f, 1f, v =>
{
Stack.FillAspectRatio = v;
Stack.FillMode = FillMode.Fit;
});
}

[TestCase(1f)]
[TestCase(0.5f)]
[TestCase(1.25f)]
Expand Down
19 changes: 3 additions & 16 deletions osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,15 @@ public TaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPla
{
this.taikoPlayfield = taikoPlayfield;

FlashlightSize = adjustSizeForPlayfieldAspectRatio(GetSize());
FlashlightSize = new Vector2(0, GetSize());
FlashlightSmoothness = 1.4f;

AddLayout(flashlightProperties);
}

/// <summary>
/// Returns the aspect ratio-adjusted size of the flashlight.
/// This ensures that the size of the flashlight remains independent of taiko-specific aspect ratio adjustments.
/// </summary>
/// <param name="size">
/// The size of the flashlight.
/// The value provided here should always come from <see cref="ModFlashlight{T}.Flashlight.GetSize"/>.
/// </param>
private Vector2 adjustSizeForPlayfieldAspectRatio(float size)
{
return new Vector2(0, size * taikoPlayfield.Parent!.Scale.Y);
}

protected override void UpdateFlashlightSize(float size)
{
this.TransformTo(nameof(FlashlightSize), adjustSizeForPlayfieldAspectRatio(size), FLASHLIGHT_FADE_DURATION);
this.TransformTo(nameof(FlashlightSize), new Vector2(0, size), FLASHLIGHT_FADE_DURATION);
}

protected override string FragmentShader => "CircularFlashlight";
Expand All @@ -82,7 +69,7 @@ protected override void Update()
FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre);

ClearTransforms(targetMember: nameof(FlashlightSize));
FlashlightSize = adjustSizeForPlayfieldAspectRatio(GetSize());
FlashlightSize = new Vector2(0, GetSize());

flashlightProperties.Validate();
}
Expand Down
58 changes: 44 additions & 14 deletions osu.Game/Rulesets/Mods/ModFlashlight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
Expand All @@ -14,8 +13,8 @@
using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Shaders.Types;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Layout;
using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.OpenGL.Vertices;
Expand Down Expand Up @@ -85,7 +84,11 @@ public virtual void ApplyToDrawableRuleset(DrawableRuleset<T> drawableRuleset)
flashlight.Colour = Color4.Black;

flashlight.Combo.BindTo(Combo);
flashlight.GetPlayfieldScale = () => drawableRuleset.PlayfieldAdjustmentContainer.Scale;

var playfieldDrawInfoTracker = new PlayfieldDrawInfoTracker();

drawableRuleset.PlayfieldAdjustmentContainer.Add(playfieldDrawInfoTracker);
flashlight.PlayfieldDrawInfoTracker = playfieldDrawInfoTracker;

drawableRuleset.Overlays.Add(new Container
{
Expand All @@ -111,7 +114,9 @@ public abstract partial class Flashlight : Drawable

public override bool RemoveCompletedTransforms => false;

internal Func<Vector2>? GetPlayfieldScale;
internal PlayfieldDrawInfoTracker PlayfieldDrawInfoTracker { get; set; } = null!;

private DrawInfo playfieldDrawInfo => PlayfieldDrawInfoTracker.DrawInfo;

private readonly float defaultFlashlightSize;
private readonly float sizeMultiplier;
Expand Down Expand Up @@ -146,6 +151,8 @@ protected override void LoadComplete()
isBreakTime.BindTo(player.IsBreakTime);
isBreakTime.BindValueChanged(_ => UpdateFlashlightSize(GetSize()), true);
}

PlayfieldDrawInfoTracker.OnDrawInfoInvalidate += () => Invalidate(Invalidation.DrawNode);
}

protected abstract void UpdateFlashlightSize(float size);
Expand All @@ -156,15 +163,6 @@ public float GetSize()
{
float size = defaultFlashlightSize * sizeMultiplier;

if (GetPlayfieldScale != null)
{
Vector2 playfieldScale = GetPlayfieldScale();

Debug.Assert(Precision.AlmostEquals(Math.Abs(playfieldScale.X), Math.Abs(playfieldScale.Y)),
@"Playfield has non-proportional scaling. Flashlight implementations should be revisited with regard to balance.");
size *= Math.Abs(playfieldScale.X);
}

if (isBreakTime.Value)
size *= 2.5f;
else if (comboBasedSize)
Expand Down Expand Up @@ -265,7 +263,11 @@ public override void ApplyState()
shader = Source.shader;
screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad;
flashlightPosition = Vector2Extensions.Transform(Source.FlashlightPosition, DrawInfo.Matrix);
flashlightSize = Source.FlashlightSize * DrawInfo.Matrix.ExtractScale().Xy;

// scale the flashlight based on the playfield to match gameplay components scale.
Vector2 drawInfoScale = Source.playfieldDrawInfo.Matrix.ExtractScale().Xy;
flashlightSize = Source.FlashlightSize * drawInfoScale;

flashlightDim = Source.FlashlightDim;
flashlightSmoothness = Source.flashlightSmoothness;
}
Expand Down Expand Up @@ -321,5 +323,33 @@ private record struct FlashlightParameters
}
}
}

/// <summary>
/// The purpose of this component is to track any changes to <c>Playfield.Parent.DrawInfo</c>
/// (by being added to the content of <see cref="PlayfieldAdjustmentContainer"/>).
/// All in order for the flashlight to invalidate its draw node and read any changes in the playfield's scaling.
/// </summary>
internal partial class PlayfieldDrawInfoTracker : Component
{
private readonly LayoutValue drawInfoLayout = new LayoutValue(Invalidation.DrawInfo);

public Action? OnDrawInfoInvalidate;

public PlayfieldDrawInfoTracker()
{
AddLayout(drawInfoLayout);
}

protected override void Update()
{
base.Update();

if (!drawInfoLayout.IsValid)
{
OnDrawInfoInvalidate?.Invoke();
drawInfoLayout.Validate();
}
}
}
}
}
Loading