1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 10:33:30 +08:00

Merge branch 'master' into fix-storyboard-skin-textures-lookup

This commit is contained in:
Dean Herbert 2023-09-26 14:05:27 +09:00 committed by GitHub
commit 2ca1c684bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 520 additions and 112 deletions

View File

@ -12,40 +12,43 @@
A free-to-win rhythm game. Rhythm is just a *click* away!
The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Currently known by and released under the release codename "*lazer*". As in sharper than cutting-edge.
This is the future and final iteration of the [osu!](https://osu.ppy.sh) game client which marks the beginning of an open era! Currently known by and released under the release codename "*lazer*". As in sharper than cutting-edge.
## Status
This project is under constant development, but we aim to keep things in a stable state. Users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve to the point of eventually replacing the existing stable client as an update.
This project is under constant development, but we do our best to keep things in a stable state. Players are encouraged to install from a release alongside their stable *osu!* client. This project will continue to evolve until we eventually reach the point where most users prefer it over the previous "osu!stable" release.
**IMPORTANT:** Gameplay mechanics (and other features which you may have come to know and love) are in a constant state of flux. Game balance and final quality-of-life passes come at the end of development, preceded by experimentation and changes which may potentially **reduce playability or usability**. This is done in order to allow us to move forward as developers and designers more efficiently. If this offends you, please consider sticking to a [stable release](https://osu.ppy.sh/home/download) of osu!. We are not yet open to heated discussion over game mechanics and will not be using github as a forum for such discussions just yet.
We are accepting bug reports (please report with as much detail as possible and follow the existing issue templates). Feature requests are also welcome, but understand that our focus is on completing the game to feature parity before adding new features. A few resources are available as starting points to getting involved and understanding the project:
A few resources are available as starting points to getting involved and understanding the project:
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
- Track our current efforts [towards full "ranked play" support](https://github.com/orgs/ppy/projects/13?query=is%3Aopen+sort%3Aupdated-desc).
## Running osu!
If you are looking to install or test osu! without setting up a development environment, you can consume our [releases](https://github.com/ppy/osu/releases). You can also generally download a version for your current device from the [osu! site](https://osu.ppy.sh/home/download). Failing that, you may use the links below to download the latest version for your operating system of choice:
If you are just looking to give the game a whirl, you can grab the latest release for your platform:
**Latest release:**
### Latest release:
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 13.4+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) |
| ------------- | ------------- | ------------- | ------------- | ------------- |
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
You can also generally download a version for your current device from the [osu! site](https://osu.ppy.sh/home/download).
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
**For iOS/iPadOS users**: The iOS testflight link fills up very fast (Apple has a hard limit of 10,000 users). We reset it occasionally. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements. Our goal is to get the game on mobile app stores in early 2024.
## Developing a custom ruleset
osu! is designed to have extensible modular gameplay modes, called "rulesets". Building one of these allows a developer to harness the power of osu! for their own game style. To get started working on a ruleset, we have some templates available [here](https://github.com/ppy/osu/tree/master/Templates).
osu! is designed to allow user-created gameplay variations, called "rulesets". Building one of these allows a developer to harness the power of the osu! beatmap library, game engine, and general UX for a new style of gameplay. To get started working on a ruleset, we have some templates available [here](https://github.com/ppy/osu/tree/master/Templates).
You can see some examples of custom rulesets by visiting the [custom ruleset directory](https://github.com/ppy/osu/discussions/13096).
## Developing osu!
### Prerequisites
Please make sure you have the following prerequisites:
- A desktop platform with the [.NET 6.0 SDK](https://dotnet.microsoft.com/download) installed.
@ -69,9 +72,19 @@ git pull
### Building
Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this is provided [below](#contributing).
#### From an IDE
- Visual Studio / Rider users should load the project via one of the platform-specific `.slnf` files, rather than the main `.sln`. This will allow access to template run configurations.
You should load the solution via one of the platform-specific `.slnf` files, rather than the main `.sln`. This will reduce dependencies and hide platforms that you don't care about. Valid `.slnf` files are:
- `osu.Desktop.slnf` (most common)
- `osu.Android.slnf`
- `osu.iOS.slnf`
Run configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `osu! (Tests)` project/configuration. More information on this is provided [below](#contributing).
To build for mobile platforms, you will likely need to run `sudo dotnet workload restore` if you haven't done so previously. This will install Android/iOS tooling required to complete the build.
#### From CLI
You can also build and run *osu!* from the command-line with a single command:
@ -79,12 +92,10 @@ You can also build and run *osu!* from the command-line with a single command:
dotnet run --project osu.Desktop
```
If you are not interested in debugging *osu!*, you can add `-c Release` to gain performance. In this case, you must replace `Debug` with `Release` in any commands mentioned in this document.
When running locally to do any kind of performance testing, make sure to add `-c Release` to the build command, as the overhead of running with the default `Debug` configuration can be large (especially when testing with local framework modifications as below).
If the build fails, try to restore NuGet packages with `dotnet restore`.
_Due to a historical feature gap between .NET Core and Xamarin, running `dotnet` CLI from the root directory will not work for most commands. This can be resolved by specifying a target `.csproj` or the helper project at `build/Desktop.proj`. Configurations have been provided to work around this issue for all supported IDEs mentioned above._
### Testing with resource/framework modifications
Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be quickly achieved using included commands:

View File

@ -10,7 +10,7 @@
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.914.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.922.0" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.

View File

@ -25,6 +25,7 @@ using osuTK;
namespace osu.Game.Rulesets.Catch.Edit
{
// we're also a ScrollingHitObjectComposer candidate, but can't be everything can we?
public partial class CatchHitObjectComposer : DistancedHitObjectComposer<CatchHitObject>
{
private const float distance_snap_radius = 50;
@ -140,7 +141,7 @@ namespace osu.Game.Rulesets.Catch.Edit
return base.OnPressed(e);
}
protected override DrawableRuleset<CatchHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods = null) =>
protected override DrawableRuleset<CatchHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods) =>
new DrawableCatchEditorRuleset(ruleset, beatmap, mods)
{
TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, }

View File

@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Catch.UI
{
public partial class DrawableCatchRuleset : DrawableScrollingRuleset<CatchHitObject>
{
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant;
protected override bool UserScrollSpeedAdjustment => false;
public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods = null)
@ -30,6 +28,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
Direction.Value = ScrollingDirection.Down;
TimeRange.Value = GetTimeRange(beatmap.Difficulty.ApproachRate);
VisualisationMethod = ScrollVisualisationMethod.Constant;
}
[BackgroundDependencyLoader]

View File

@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods
PassCondition = () =>
{
var hitObject = Player.ChildrenOfType<DrawableManiaHitObject>().FirstOrDefault();
return hitObject?.Dependencies.Get<IScrollingInfo>().Algorithm is ConstantScrollAlgorithm;
return hitObject?.Dependencies.Get<IScrollingInfo>().Algorithm.Value is ConstantScrollAlgorithm;
}
});
}

View File

@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(5000);
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ConstantScrollAlgorithm();
IBindable<IScrollAlgorithm> IScrollingInfo.Algorithm { get; } = new Bindable<IScrollAlgorithm>(new ConstantScrollAlgorithm());
}
}
}

View File

@ -2,18 +2,22 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osuTK;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit
{
public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset
public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset, ISupportConstantAlgorithmToggle
{
public BindableBool ShowSpeedChanges { get; set; } = new BindableBool();
public new IScrollingInfo ScrollingInfo => base.ScrollingInfo;
public DrawableManiaEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod>? mods)
@ -21,6 +25,13 @@ namespace osu.Game.Rulesets.Mania.Edit
{
}
protected override void LoadComplete()
{
base.LoadComplete();
ShowSpeedChanges.BindValueChanged(showChanges => VisualisationMethod = showChanges.NewValue ? ScrollVisualisationMethod.Sequential : ScrollVisualisationMethod.Constant, true);
}
protected override Playfield CreatePlayfield() => new ManiaEditorPlayfield(Beatmap.Stages)
{
Anchor = Anchor.Centre,

View File

@ -21,7 +21,7 @@ using osuTK;
namespace osu.Game.Rulesets.Mania.Edit
{
public partial class ManiaHitObjectComposer : HitObjectComposer<ManiaHitObject>
public partial class ManiaHitObjectComposer : ScrollingHitObjectComposer<ManiaHitObject>
{
private DrawableManiaEditorRuleset drawableRuleset;
private ManiaBeatSnapGrid beatSnapGrid;
@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Mania.Edit
protected override Playfield PlayfieldAtScreenSpacePosition(Vector2 screenSpacePosition) =>
Playfield.GetColumnByPosition(screenSpacePosition);
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods)
{
drawableRuleset = new DrawableManiaEditorRuleset(ruleset, beatmap, mods);

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public void ApplyToDrawableRuleset(DrawableRuleset<ManiaHitObject> drawableRuleset)
{
var maniaRuleset = (DrawableManiaRuleset)drawableRuleset;
maniaRuleset.ScrollMethod = ScrollVisualisationMethod.Constant;
maniaRuleset.VisualisationMethod = ScrollVisualisationMethod.Constant;
}
}
}

View File

@ -3,7 +3,6 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@ -14,7 +13,6 @@ using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Configuration;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
using osu.Game.Rulesets.Mania.Beatmaps;
@ -52,22 +50,6 @@ namespace osu.Game.Rulesets.Mania.UI
protected new ManiaRulesetConfigManager Config => (ManiaRulesetConfigManager)base.Config;
public ScrollVisualisationMethod ScrollMethod
{
get => scrollMethod;
set
{
if (IsLoaded)
throw new InvalidOperationException($"Can't alter {nameof(ScrollMethod)} after ruleset is already loaded");
scrollMethod = value;
}
}
private ScrollVisualisationMethod scrollMethod = ScrollVisualisationMethod.Sequential;
protected override ScrollVisualisationMethod VisualisationMethod => scrollMethod;
private readonly Bindable<ManiaScrollingDirection> configDirection = new Bindable<ManiaScrollingDirection>();
private readonly BindableInt configScrollSpeed = new BindableInt();
private double smoothTimeRange;

View File

@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[TestCase("colinear-perfect-curve")]
[TestCase("slider-ticks")]
[TestCase("slider-ticks-edge-case")]
[TestCase("slider-paths-edge-case")]
[TestCase("repeat-slider")]
[TestCase("uneven-repeat-slider")]
[TestCase("old-stacking")]

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Edit
{
}
protected override DrawableRuleset<OsuHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
protected override DrawableRuleset<OsuHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods)
=> new DrawableOsuEditorRuleset(ruleset, beatmap, mods);
protected override IReadOnlyList<HitObjectCompositionTool> CompositionTools => new HitObjectCompositionTool[]

View File

@ -61,10 +61,12 @@ namespace osu.Game.Rulesets.Osu.Mods
public void ApplyToDrawableRuleset(DrawableRuleset<OsuHitObject> drawableRuleset)
{
OsuHitObject firstObject = drawableRuleset.Beatmap.HitObjects.First();
// Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
// Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
bubbleSize = (float)(drawableRuleset.Beatmap.HitObjects.OfType<HitCircle>().First().Radius * 1.90f);
bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType<HitCircle>().First().TimePreempt * 2;
bubbleSize = (float)firstObject.Radius * 1.90f;
bubbleFade = firstObject.TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
drawableRuleset.Playfield.DisplayJudgements.Value = false;

View File

@ -0,0 +1,94 @@
{
"Mappings": [
{
"StartTime": 46060.0,
"Objects": [
{
"StartTime": 46060.0,
"EndTime": 46060.0,
"X": 160.0,
"Y": 208.0,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
},
{
"StartTime": 46398.0,
"EndTime": 46398.0,
"X": 160.980164,
"Y": 317.779083,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
},
{
"StartTime": 46737.0,
"EndTime": 46737.0,
"X": 268.887268,
"Y": 320.0,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
},
{
"StartTime": 47040.0,
"EndTime": 47040.0,
"X": 378.995544,
"Y": 320.0,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
}
]
},
{
"StartTime": 123348.0,
"Objects": [
{
"StartTime": 123348.0,
"EndTime": 123348.0,
"X": 352.0,
"Y": 160.0,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
},
{
"StartTime": 123686.0,
"EndTime": 123686.0,
"X": 351.019836,
"Y": 50.2209129,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
},
{
"StartTime": 124025.0,
"EndTime": 124025.0,
"X": 243.112747,
"Y": 48.0,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
},
{
"StartTime": 124328.0,
"EndTime": 124328.0,
"X": 133.004471,
"Y": 48.0,
"StackOffset": {
"X": 0.0,
"Y": 0.0
}
}
]
}
]
}

View File

@ -0,0 +1,19 @@
osu file format v6
[General]
StackLeniency: 0.7
[Difficulty]
HPDrainRate:1
CircleSize:3
OverallDifficulty:1
SliderMultiplier:1.1
SliderTickRate:1
[TimingPoints]
-41,338.983050847458,4,1,0,70,1,0
93648,-100,4,1,0,70,0,0
[HitObjects]
160,208,46060,6,0,B|161:320|161:320|271:320|271:320,1,330,8|0
352,160,123348,6,0,B|351:48|351:48|241:48|241:48,1,330,8|0

View File

@ -0,0 +1,37 @@
// 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 System.Collections.Generic;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Taiko.Edit
{
public partial class DrawableTaikoEditorRuleset : DrawableTaikoRuleset, ISupportConstantAlgorithmToggle
{
public BindableBool ShowSpeedChanges { get; set; } = new BindableBool();
public DrawableTaikoEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods)
: base(ruleset, beatmap, mods)
{
}
protected override void LoadComplete()
{
base.LoadComplete();
ShowSpeedChanges.BindValueChanged(showChanges => VisualisationMethod = showChanges.NewValue ? ScrollVisualisationMethod.Overlapping : ScrollVisualisationMethod.Constant, true);
}
protected override double ComputeTimeRange()
{
// Adjust when we're using constant algorithm to not be sluggish.
double multiplier = ShowSpeedChanges.Value ? 1 : 4;
return base.ComputeTimeRange() / multiplier;
}
}
}

View File

@ -2,14 +2,17 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Compose.Components;
namespace osu.Game.Rulesets.Taiko.Edit
{
public partial class TaikoHitObjectComposer : HitObjectComposer<TaikoHitObject>
public partial class TaikoHitObjectComposer : ScrollingHitObjectComposer<TaikoHitObject>
{
protected override bool ApplyHorizontalCentering => false;
@ -25,6 +28,9 @@ namespace osu.Game.Rulesets.Taiko.Edit
new SwellCompositionTool()
};
protected override DrawableRuleset<TaikoHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods) =>
new DrawableTaikoEditorRuleset(ruleset, beatmap, mods);
protected override ComposeBlueprintContainer CreateBlueprintContainer()
=> new TaikoBlueprintContainer(this);
}

View File

@ -35,8 +35,6 @@ namespace osu.Game.Rulesets.Taiko.UI
public new TaikoInputManager KeyBindingInputManager => (TaikoInputManager)base.KeyBindingInputManager;
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
protected override bool UserScrollSpeedAdjustment => false;
private SkinnableDrawable scroller;
@ -45,6 +43,7 @@ namespace osu.Game.Rulesets.Taiko.UI
: base(ruleset, beatmap, mods)
{
Direction.Value = ScrollingDirection.Left;
VisualisationMethod = ScrollVisualisationMethod.Overlapping;
}
[BackgroundDependencyLoader]
@ -65,6 +64,11 @@ namespace osu.Game.Rulesets.Taiko.UI
{
base.Update();
TimeRange.Value = ComputeTimeRange();
}
protected virtual double ComputeTimeRange()
{
// Taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened.
const float scroll_rate = 10;
@ -73,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.UI
// We clamp the ratio to the maximum aspect ratio to keep scroll speed consistent on widths lower than the default.
float ratio = Math.Max(DrawSize.X / 768f, TaikoPlayfieldAdjustmentContainer.MAXIMUM_ASPECT);
TimeRange.Value = (Playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate;
return (Playfield.HitObjectContainer.DrawWidth / ratio) * scroll_rate;
}
protected override void UpdateAfterChildren()

View File

@ -621,6 +621,38 @@ namespace osu.Game.Tests.Beatmaps.Formats
}
}
[Test]
public void TestInvalidBankDefaultsToNormal()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("invalid-bank.osu"))
using (var stream = new LineBufferedReader(resStream))
{
var hitObjects = decoder.Decode(stream).HitObjects;
assertObjectHasBanks(hitObjects[0], HitSampleInfo.BANK_DRUM);
assertObjectHasBanks(hitObjects[1], HitSampleInfo.BANK_NORMAL);
assertObjectHasBanks(hitObjects[2], HitSampleInfo.BANK_SOFT);
assertObjectHasBanks(hitObjects[3], HitSampleInfo.BANK_DRUM);
assertObjectHasBanks(hitObjects[4], HitSampleInfo.BANK_NORMAL);
assertObjectHasBanks(hitObjects[5], HitSampleInfo.BANK_DRUM, HitSampleInfo.BANK_DRUM);
assertObjectHasBanks(hitObjects[6], HitSampleInfo.BANK_DRUM, HitSampleInfo.BANK_NORMAL);
assertObjectHasBanks(hitObjects[7], HitSampleInfo.BANK_DRUM, HitSampleInfo.BANK_SOFT);
assertObjectHasBanks(hitObjects[8], HitSampleInfo.BANK_DRUM, HitSampleInfo.BANK_DRUM);
assertObjectHasBanks(hitObjects[9], HitSampleInfo.BANK_DRUM, HitSampleInfo.BANK_NORMAL);
}
void assertObjectHasBanks(HitObject hitObject, string normalBank, string? additionsBank = null)
{
Assert.AreEqual(normalBank, hitObject.Samples[0].Bank);
if (additionsBank != null)
Assert.AreEqual(additionsBank, hitObject.Samples[1].Bank);
}
}
[Test]
public void TestFallbackDecoderForCorruptedHeader()
{

View File

@ -0,0 +1,19 @@
osu file format v14
[General]
SampleSet: Normal
[TimingPoints]
0,500,4,3,0,100,1,0
[HitObjects]
256,192,1000,5,0,0:0:0:0:
256,192,2000,1,0,1:0:0:0:
256,192,3000,1,0,2:0:0:0:
256,192,4000,1,0,3:0:0:0:
256,192,5000,1,0,42:0:0:0:
256,192,6000,5,4,0:0:0:0:
256,192,7000,1,4,0:1:0:0:
256,192,8000,1,4,0:2:0:0:
256,192,9000,1,4,0:3:0:0:
256,192,10000,1,4,0:42:0:0:

View File

@ -311,14 +311,13 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override bool RelativeScaleBeatLengths => RelativeScaleBeatLengthsOverride;
protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Overlapping;
public new Bindable<double> TimeRange => base.TimeRange;
public TestDrawableScrollingRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
: base(ruleset, beatmap, mods)
{
TimeRange.Value = time_range;
VisualisationMethod = ScrollVisualisationMethod.Overlapping;
}
public override DrawableHitObject<TestHitObject> CreateDrawableRepresentation(TestHitObject h)

View File

@ -3,14 +3,17 @@
#nullable disable
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Extensions.PolygonExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.Play.HUD;
using osuTK;
@ -139,6 +142,37 @@ namespace osu.Game.Tests.Visual.Gameplay
=> AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount);
}
[Test]
public void TestFriendScore()
{
APIUser friend = new APIUser { Username = "my friend", Id = 10000 };
createLeaderboard();
addLocalPlayer();
AddStep("Add friend to API", () =>
{
var api = (DummyAPIAccess)API;
api.Friends.Clear();
api.Friends.Add(friend);
});
int playerNumber = 1;
AddRepeatStep("add 3 other players", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 3);
AddUntilStep("no pink color scores",
() => leaderboard.ChildrenOfType<Box>().Select(b => ((Colour4)b.Colour).ToHex()),
() => Does.Not.Contain("#FF549A"));
AddRepeatStep("add 3 friend score", () => createRandomScore(friend), 3);
AddUntilStep("at least one friend score is pink",
() => leaderboard.GetAllScoresForUsername("my friend")
.SelectMany(score => score.ChildrenOfType<Box>())
.Select(b => ((Colour4)b.Colour).ToHex()),
() => Does.Contain("#FF549A"));
}
private void addLocalPlayer()
{
AddStep("add local player", () =>
@ -179,6 +213,9 @@ namespace osu.Game.Tests.Visual.Gameplay
return scoreItem != null && scoreItem.ScorePosition == expectedPosition;
}
public IEnumerable<GameplayLeaderboardScore> GetAllScoresForUsername(string username)
=> Flow.Where(i => i.User?.Username == username);
}
}
}

View File

@ -25,6 +25,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
@ -1087,6 +1088,25 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("0 matching shown", () => songSelect.ChildrenOfType<FilterControl>().Single().InformationalText == "0 matches");
}
[Test]
public void TestDeleteHotkey()
{
createSongSelect();
addRulesetImportStep(0);
AddAssert("3 matching shown", () => songSelect.ChildrenOfType<FilterControl>().Single().InformationalText == "3 matches");
AddStep("press shift-delete", () =>
{
InputManager.PressKey(Key.ShiftLeft);
InputManager.Key(Key.Delete);
InputManager.ReleaseKey(Key.ShiftLeft);
});
AddUntilStep("delete dialog shown", () => DialogOverlay.CurrentDialog, Is.InstanceOf<BeatmapDeleteDialog>);
AddStep("confirm deletion", () => DialogOverlay.CurrentDialog!.PerformAction<PopupDialogDangerousButton>());
AddAssert("0 matching shown", () => songSelect.ChildrenOfType<FilterControl>().Single().InformationalText == "0 matches");
}
private void waitForInitialSelection()
{
AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);

View File

@ -216,8 +216,6 @@ namespace osu.Game.Beatmaps
public double FramesPerSecond => finalClockSource.FramesPerSecond;
public FrameTimeInfo TimeInfo => finalClockSource.TimeInfo;
#endregion
protected override void Dispose(bool isDisposing)

View File

@ -64,6 +64,12 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.Username, string.Empty);
SetDefault(OsuSetting.Token, string.Empty);
#pragma warning disable CS0618 // Type or member is obsolete
// this default set MUST remain despite the setting being deprecated, because `SetDefault()` calls are implicitly used to declare the type returned for the lookup.
// if this is removed, the setting will be interpreted as a string, and `Migrate()` will fail due to cast failure.
// can be removed 20240618
SetDefault(OsuSetting.AutomaticallyDownloadWhenSpectating, false);
#pragma warning restore CS0618 // Type or member is obsolete
SetDefault(OsuSetting.AutomaticallyDownloadMissingBeatmaps, false);
SetDefault(OsuSetting.SavePassword, false).ValueChanged += enabled =>
@ -218,7 +224,7 @@ namespace osu.Game.Configuration
if (combined < 20230918)
{
#pragma warning disable CS0618 // Type or member is obsolete
SetValue(OsuSetting.AutomaticallyDownloadMissingBeatmaps, Get<OsuSetting>(OsuSetting.AutomaticallyDownloadWhenSpectating)); // can be removed 20240618
SetValue(OsuSetting.AutomaticallyDownloadMissingBeatmaps, Get<bool>(OsuSetting.AutomaticallyDownloadWhenSpectating)); // can be removed 20240618
#pragma warning restore CS0618 // Type or member is obsolete
}
}

View File

@ -99,9 +99,14 @@ namespace osu.Game.Online.API
return true;
}
}
catch (HttpRequestException)
{
// Network failure.
return false;
}
catch
{
//todo: potentially only kill the refresh token on certain exception types.
// Force a full re-reauthentication.
Token.Value = null;
return false;
}

View File

@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Edit
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
private void load()
{
RightToolbox.Add(new EditorToolboxGroup("snapping")
{

View File

@ -87,6 +87,8 @@ namespace osu.Game.Rulesets.Edit
private IBindable<bool> hasTiming;
private Bindable<bool> autoSeekOnPlacement;
protected DrawableRuleset<TObject> DrawableRuleset { get; private set; }
protected HitObjectComposer(Ruleset ruleset)
: base(ruleset)
{
@ -104,7 +106,8 @@ namespace osu.Game.Rulesets.Edit
try
{
drawableRulesetWrapper = new DrawableEditorRulesetWrapper<TObject>(CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap, new[] { Ruleset.GetAutoplayMod() }))
DrawableRuleset = CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap, new[] { Ruleset.GetAutoplayMod() });
drawableRulesetWrapper = new DrawableEditorRulesetWrapper<TObject>(DrawableRuleset)
{
Clock = EditorClock,
ProcessCustomClock = false
@ -304,7 +307,7 @@ namespace osu.Game.Rulesets.Edit
/// <param name="beatmap">The loaded beatmap.</param>
/// <param name="mods">The mods to be applied.</param>
/// <returns>An editor-relevant <see cref="DrawableRuleset{TObject}"/>.</returns>
protected virtual DrawableRuleset<TObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
protected virtual DrawableRuleset<TObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods)
=> (DrawableRuleset<TObject>)ruleset.CreateDrawableRulesetWith(beatmap, mods);
#region Tool selection logic

View File

@ -0,0 +1,51 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Screens.Edit.Components.TernaryButtons;
using osuTK;
namespace osu.Game.Rulesets.Edit
{
public abstract partial class ScrollingHitObjectComposer<TObject> : HitObjectComposer<TObject>
where TObject : HitObject
{
private readonly Bindable<TernaryState> showSpeedChanges = new Bindable<TernaryState>();
protected ScrollingHitObjectComposer(Ruleset ruleset)
: base(ruleset)
{
}
[BackgroundDependencyLoader]
private void load()
{
if (DrawableRuleset is ISupportConstantAlgorithmToggle toggleRuleset)
{
LeftToolbox.Add(new EditorToolboxGroup("playfield")
{
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 5),
Children = new[]
{
new DrawableTernaryButton(new TernaryButton(showSpeedChanges, "Show speed changes", () => new SpriteIcon { Icon = FontAwesome.Solid.TachometerAlt }))
}
},
});
showSpeedChanges.BindValueChanged(state => toggleRuleset.ShowSpeedChanges.Value = state.NewValue == TernaryState.True, true);
}
}
}
}

View File

@ -190,7 +190,12 @@ namespace osu.Game.Rulesets.Objects.Legacy
string[] split = str.Split(':');
var bank = (LegacySampleBank)Parsing.ParseInt(split[0]);
if (!Enum.IsDefined(bank))
bank = LegacySampleBank.Normal;
var addBank = (LegacySampleBank)Parsing.ParseInt(split[1]);
if (!Enum.IsDefined(addBank))
addBank = LegacySampleBank.Normal;
string stringBank = bank.ToString().ToLowerInvariant();
if (stringBank == @"none")

View File

@ -262,9 +262,16 @@ namespace osu.Game.Rulesets.Objects
var segmentVertices = vertices.AsSpan().Slice(start, i - start + 1);
var segmentType = ControlPoints[start].Type ?? PathType.Linear;
foreach (Vector2 t in calculateSubPath(segmentVertices, segmentType))
// No need to calculate path when there is only 1 vertex
if (segmentVertices.Length == 1)
calculatedPath.Add(segmentVertices[0]);
else if (segmentVertices.Length > 1)
{
if (calculatedPath.Count == 0 || calculatedPath.Last() != t)
List<Vector2> subPath = calculateSubPath(segmentVertices, segmentType);
// Skip the first vertex if it is the same as the last vertex from the previous segment
int skipFirst = calculatedPath.Count > 0 && subPath.Count > 0 && calculatedPath.Last() == subPath[0] ? 1 : 0;
foreach (Vector2 t in subPath.Skip(skipFirst))
calculatedPath.Add(t);
}
@ -328,8 +335,8 @@ namespace osu.Game.Rulesets.Objects
if (ExpectedDistance.Value is double expectedDistance && calculatedLength != expectedDistance)
{
// In osu-stable, if the last two control points of a slider are equal, extension is not performed.
if (ControlPoints.Count >= 2 && ControlPoints[^1].Position == ControlPoints[^2].Position && expectedDistance > calculatedLength)
// In osu-stable, if the last two path points of a slider are equal, extension is not performed.
if (calculatedPath.Count >= 2 && calculatedPath[^1] == calculatedPath[^2] && expectedDistance > calculatedLength)
{
cumulativeLength.Add(calculatedLength);
return;

View File

@ -264,8 +264,6 @@ namespace osu.Game.Rulesets.UI
public double FramesPerSecond => framedClock.FramesPerSecond;
public FrameTimeInfo TimeInfo => framedClock.TimeInfo;
public double StartTime => parentGameplayClock?.StartTime ?? 0;
private readonly AudioAdjustments gameplayAdjustments = new AudioAdjustments();

View File

@ -64,8 +64,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
MaxValue = time_span_max
};
protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential;
ScrollVisualisationMethod IDrawableScrollingRuleset.VisualisationMethod => VisualisationMethod;
/// <summary>
@ -99,20 +97,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
[BackgroundDependencyLoader]
private void load()
{
switch (VisualisationMethod)
{
case ScrollVisualisationMethod.Sequential:
scrollingInfo.Algorithm = new SequentialScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Overlapping:
scrollingInfo.Algorithm = new OverlappingScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Constant:
scrollingInfo.Algorithm = new ConstantScrollAlgorithm();
break;
}
updateScrollAlgorithm();
double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : double.MaxValue;
double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH;
@ -178,6 +163,36 @@ namespace osu.Game.Rulesets.UI.Scrolling
throw new ArgumentException($"{nameof(Playfield)} must be a {nameof(ScrollingPlayfield)} when using {nameof(DrawableScrollingRuleset<TObject>)}.");
}
private ScrollVisualisationMethod visualisationMethod = ScrollVisualisationMethod.Sequential;
public ScrollVisualisationMethod VisualisationMethod
{
get => visualisationMethod;
set
{
visualisationMethod = value;
updateScrollAlgorithm();
}
}
private void updateScrollAlgorithm()
{
switch (VisualisationMethod)
{
case ScrollVisualisationMethod.Sequential:
scrollingInfo.Algorithm.Value = new SequentialScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Overlapping:
scrollingInfo.Algorithm.Value = new OverlappingScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Constant:
scrollingInfo.Algorithm.Value = new ConstantScrollAlgorithm();
break;
}
}
/// <summary>
/// Adjusts the scroll speed of <see cref="HitObject"/>s.
/// </summary>
@ -217,7 +232,9 @@ namespace osu.Game.Rulesets.UI.Scrolling
public IBindable<double> TimeRange { get; } = new BindableDouble();
public IScrollAlgorithm Algorithm { get; set; }
public readonly Bindable<IScrollAlgorithm> Algorithm = new Bindable<IScrollAlgorithm>(new ConstantScrollAlgorithm());
IBindable<IScrollAlgorithm> IScrollingInfo.Algorithm => Algorithm;
}
}
}

View File

@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.UI.Scrolling
IBindable<ScrollingDirection> Direction { get; }
/// <summary>
///
/// The span of time that is visible by the length of the scrolling axes.
/// </summary>
IBindable<double> TimeRange { get; }
/// <summary>
/// The algorithm which controls <see cref="HitObject"/> positions and sizes.
/// </summary>
IScrollAlgorithm Algorithm { get; }
IBindable<IScrollAlgorithm> Algorithm { get; }
}
}

View File

@ -0,0 +1,15 @@
// 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.Bindables;
namespace osu.Game.Rulesets.UI.Scrolling
{
/// <summary>
/// Denotes a <see cref="IDrawableScrollingRuleset"/> which supports toggling constant algorithm for better display in the editor.
/// </summary>
public interface ISupportConstantAlgorithmToggle : IDrawableScrollingRuleset
{
public BindableBool ShowSpeedChanges { get; }
}
}

View File

@ -13,6 +13,7 @@ using osu.Framework.Layout;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
using osuTK;
namespace osu.Game.Rulesets.UI.Scrolling
@ -21,6 +22,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
{
private readonly IBindable<double> timeRange = new BindableDouble();
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private readonly IBindable<IScrollAlgorithm> algorithm = new Bindable<IScrollAlgorithm>();
/// <summary>
/// Whether the scrolling direction is horizontal or vertical.
@ -59,9 +61,11 @@ namespace osu.Game.Rulesets.UI.Scrolling
{
direction.BindTo(scrollingInfo.Direction);
timeRange.BindTo(scrollingInfo.TimeRange);
algorithm.BindTo(scrollingInfo.Algorithm);
direction.ValueChanged += _ => layoutCache.Invalidate();
timeRange.ValueChanged += _ => layoutCache.Invalidate();
algorithm.ValueChanged += _ => layoutCache.Invalidate();
}
/// <summary>
@ -73,7 +77,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
public double TimeAtPosition(float localPosition, double currentTime)
{
float scrollPosition = axisInverted ? -localPosition : localPosition;
return scrollingInfo.Algorithm.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength);
return algorithm.Value.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength);
}
/// <summary>
@ -95,7 +99,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary>
public float PositionAtTime(double time, double currentTime, double? originTime = null)
{
float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime);
float scrollPosition = algorithm.Value.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime);
return axisInverted ? -scrollPosition : scrollPosition;
}
@ -122,7 +126,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
/// </summary>
public float LengthAtTime(double startTime, double endTime)
{
return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength);
return algorithm.Value.GetLength(startTime, endTime, timeRange.Value, scrollLength);
}
private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight;
@ -169,7 +173,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
foreach (var entry in Entries)
setComputedLifetimeStart(entry);
scrollingInfo.Algorithm.Reset();
algorithm.Value.Reset();
layoutCache.Validate();
}
@ -224,7 +228,7 @@ namespace osu.Game.Rulesets.UI.Scrolling
break;
}
return scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength);
return algorithm.Value.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength);
}
private void setComputedLifetimeStart(HitObjectLifetimeEntry entry)

View File

@ -14,7 +14,7 @@ using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Components.TernaryButtons
{
internal partial class DrawableTernaryButton : OsuButton
public partial class DrawableTernaryButton : OsuButton
{
private Color4 defaultBackgroundColour;
private Color4 defaultIconColour;

View File

@ -231,8 +231,6 @@ namespace osu.Game.Screens.Edit
public double FramesPerSecond => underlyingClock.FramesPerSecond;
public FrameTimeInfo TimeInfo => underlyingClock.TimeInfo;
public void ChangeSource(IClock source)
{
track.Value = source as Track;

View File

@ -234,7 +234,5 @@ namespace osu.Game.Screens.Play
public double ElapsedFrameTime => GameplayClock.ElapsedFrameTime;
public double FramesPerSecond => GameplayClock.FramesPerSecond;
public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo;
}
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
@ -11,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using osu.Game.Users.Drawables;
@ -107,6 +109,8 @@ namespace osu.Game.Screens.Play.HUD
private IBindable<ScoringMode> scoreDisplayMode = null!;
private bool isFriend;
/// <summary>
/// Creates a new <see cref="GameplayLeaderboardScore"/>.
/// </summary>
@ -124,7 +128,7 @@ namespace osu.Game.Screens.Play.HUD
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, OsuConfigManager osuConfigManager)
private void load(OsuColour colours, OsuConfigManager osuConfigManager, IAPIProvider api)
{
Container avatarContainer;
@ -311,6 +315,8 @@ namespace osu.Game.Screens.Play.HUD
}, true);
HasQuit.BindValueChanged(_ => updateState());
isFriend = User != null && api.Friends.Any(u => User.OnlineID == u.Id);
}
protected override void LoadComplete()
@ -389,6 +395,11 @@ namespace osu.Game.Screens.Play.HUD
panelColour = BackgroundColour ?? Color4Extensions.FromHex("ffd966");
textColour = TextColour ?? Color4Extensions.FromHex("2e576b");
}
else if (isFriend)
{
panelColour = BackgroundColour ?? Color4Extensions.FromHex("ff549a");
textColour = TextColour ?? Color4.White;
}
else
{
panelColour = BackgroundColour ?? Color4Extensions.FromHex("3399cc");

View File

@ -254,6 +254,9 @@ namespace osu.Game.Screens.Select
public OsuSpriteText FilterText { get; private set; }
// clipboard is disabled because one of the "cut" platform key bindings (shift-delete) conflicts with the beatmap deletion action.
protected override bool AllowClipboardExport => false;
public FilterControlTextBox()
{
Height += filter_text_size;

View File

@ -142,14 +142,32 @@ namespace osu.Game.Storyboards.Drawables
public void Dispose() =>
realmFileStore.Dispose();
public byte[] Get(string name) =>
realmFileStore.Get(storyboard.GetStoragePathFromStoryboardPath(name));
public byte[] Get(string name)
{
string? storagePath = storyboard.GetStoragePathFromStoryboardPath(name);
public Task<byte[]> GetAsync(string name, CancellationToken cancellationToken = new CancellationToken()) =>
realmFileStore.GetAsync(storyboard.GetStoragePathFromStoryboardPath(name), cancellationToken);
return string.IsNullOrEmpty(storagePath)
? null!
: realmFileStore.Get(storagePath);
}
public Stream GetStream(string name) =>
realmFileStore.GetStream(storyboard.GetStoragePathFromStoryboardPath(name));
public Task<byte[]> GetAsync(string name, CancellationToken cancellationToken = new CancellationToken())
{
string? storagePath = storyboard.GetStoragePathFromStoryboardPath(name);
return string.IsNullOrEmpty(storagePath)
? Task.FromResult<byte[]>(null!)
: realmFileStore.GetAsync(storagePath, cancellationToken);
}
public Stream? GetStream(string name)
{
string? storagePath = storyboard.GetStoragePathFromStoryboardPath(name);
return string.IsNullOrEmpty(storagePath)
? null
: realmFileStore.GetStream(storagePath);
}
public IEnumerable<string> GetAvailableResources() =>
realmFileStore.GetAvailableResources();

View File

@ -29,12 +29,7 @@ namespace osu.Game.Storyboards.Drawables
[BackgroundDependencyLoader(true)]
private void load(IBindable<WorkingBeatmap> beatmap, TextureStore textureStore)
{
string? path = beatmap.Value.BeatmapSetInfo?.GetPathForFile(Video.Path);
if (path == null)
return;
var stream = textureStore.GetStream(path);
var stream = textureStore.GetStream(Video.Path);
if (stream == null)
return;

View File

@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual
IBindable<double> IScrollingInfo.TimeRange => TimeRange;
public readonly TestScrollAlgorithm Algorithm = new TestScrollAlgorithm();
IScrollAlgorithm IScrollingInfo.Algorithm => Algorithm;
IBindable<IScrollAlgorithm> IScrollingInfo.Algorithm => new Bindable<IScrollAlgorithm>(Algorithm);
}
public class TestScrollAlgorithm : IScrollAlgorithm

View File

@ -36,7 +36,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="11.5.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.914.0" />
<PackageReference Include="ppy.osu.Framework" Version="2023.922.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.914.0" />
<PackageReference Include="Sentry" Version="3.39.1" />
<PackageReference Include="SharpCompress" Version="0.33.0" />

View File

@ -23,6 +23,6 @@
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.914.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.922.0" />
</ItemGroup>
</Project>

View File

@ -34,9 +34,9 @@
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>We don&apos;t really use the camera.</string>
<string>We don't really use the camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>We don&apos;t really use the microphone.</string>
<string>We don't really use the microphone.</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeRight</string>
@ -130,5 +130,7 @@
<string>Editor</string>
</dict>
</array>
<key>LSApplicationCategoryType</key>
<string>public.app-category.music-games</string>
</dict>
</plist>