mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 15:17:27 +08:00
Merge remote-tracking branch 'upstream/master' into fix-replay-import-statistics
This commit is contained in:
commit
8160162cde
68
README.md
68
README.md
@ -11,25 +11,71 @@ We are accepting bug reports (please report with as much detail as possible). Fe
|
||||
# Requirements
|
||||
|
||||
- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed.
|
||||
- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio Code](https://code.visualstudio.com/) (with the C# plugin installed) or [Jetbrains Rider](https://www.jetbrains.com/rider/) (commercial).
|
||||
- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2017+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- Note that there are **[additional requirements for Windows 7 and Windows 8.1](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore2x)** which you may need to manually install if your operating system is not up-to-date.
|
||||
|
||||
# Building and running
|
||||
# Running osu!
|
||||
|
||||
If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled (download and run the install executable for your platform).
|
||||
## Releases
|
||||
|
||||
Clone the repository including submodules
|
||||
If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled.
|
||||
|
||||
`git clone --recurse-submodules https://github.com/ppy/osu`
|
||||
- Windows (x64) users should download and run `install.exe`.
|
||||
- macOS users (10.12 "Sierra" and higher) should download and run `osu.app.zip`.
|
||||
- iOS users can join the [TestFlight beta program](https://t.co/xQJmHkfC18).
|
||||
|
||||
Build and run
|
||||
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
||||
|
||||
- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
|
||||
- From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance.
|
||||
- To run with code analysis, instead use `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
|
||||
## Downloading the source code
|
||||
|
||||
Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example
|
||||
Clone the repository **including submodules**:
|
||||
|
||||
If you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`). Visual Studio Code users must run `Restore` task from debug tab before attempt to build.
|
||||
```shell
|
||||
git clone --recurse-submodules https://github.com/ppy/osu
|
||||
cd osu
|
||||
```
|
||||
|
||||
> If you forgot the `--recurse-submodules` option, run this command inside the `osu` directory:
|
||||
>
|
||||
> `git submodule update --init --recursive`
|
||||
|
||||
To update the source code to the latest commit, run the following command inside the `osu` directory:
|
||||
|
||||
```shell
|
||||
git pull --recurse-submodules
|
||||
```
|
||||
|
||||
## 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 provided below.
|
||||
|
||||
> Visual Studio Code users must run the `Restore` task before any build attempt.
|
||||
|
||||
You can also build and run osu! from the command-line with a single command:
|
||||
|
||||
```shell
|
||||
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.
|
||||
|
||||
If the build fails, try to restore nuget packages with `dotnet restore`.
|
||||
|
||||
### A note for Linux users
|
||||
|
||||
On Linux, the environment variable `LD_LIBRARY_PATH` must point to the build directory, located at `osu.Desktop/bin/Debug/$NETCORE_VERSION`.
|
||||
|
||||
`$NETCORE_VERSION` is the version of .NET Core SDK. You can have it with `grep TargetFramework osu.Desktop/osu.Desktop.csproj | sed -r 's/.*>(.*)<\/.*/\1/'`.
|
||||
|
||||
For example, you can run osu! with the following command:
|
||||
|
||||
```shell
|
||||
LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop
|
||||
```
|
||||
|
||||
## Code analysis
|
||||
|
||||
Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
|
||||
|
||||
# Contributing
|
||||
|
||||
|
@ -97,7 +97,7 @@ namespace osu.Desktop
|
||||
|
||||
private void fileDrop(object sender, FileDropEventArgs e)
|
||||
{
|
||||
var filePaths = new[] { e.FileName };
|
||||
var filePaths = e.FileNames;
|
||||
|
||||
var firstExtension = Path.GetExtension(filePaths.First());
|
||||
|
||||
|
@ -28,8 +28,8 @@
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
<PackageReference Include="ppy.squirrel.windows" Version="1.9.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="lazer.ico" />
|
||||
|
@ -26,7 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
|
||||
|
||||
|
@ -19,7 +19,6 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
{
|
||||
var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
|
||||
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
if (i % 5 < 3)
|
||||
beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 });
|
||||
|
@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
{
|
||||
public class CatchDifficultyCalculator : DifficultyCalculator
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
|
||||
/// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : Color4.White);
|
||||
}
|
||||
|
||||
private const float preempt = 1000;
|
||||
|
@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
@ -180,7 +180,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
||||
|
||||
foreach (var obj in newPattern.HitObjects)
|
||||
yield return obj;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
if (!calculateStrainValues(difficultyHitObjects, timeRate))
|
||||
return new DifficultyAttributes(mods, 0);
|
||||
|
||||
|
||||
double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
|
||||
|
||||
return new ManiaDifficultyAttributes(mods, starRating)
|
||||
|
@ -3,14 +3,14 @@
|
||||
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModMirror : Mod, IApplicableToRulesetContainer<ManiaHitObject>
|
||||
public class ManiaModMirror : Mod, IApplicableToBeatmap<ManiaHitObject>
|
||||
{
|
||||
public override string Name => "Mirror";
|
||||
public override string Acronym => "MR";
|
||||
@ -18,11 +18,11 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||
public void ApplyToBeatmap(Beatmap<ManiaHitObject> beatmap)
|
||||
{
|
||||
var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
|
||||
var availableColumns = ((ManiaBeatmap)beatmap).TotalColumns;
|
||||
|
||||
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = availableColumns - 1 - h.Column);
|
||||
beatmap.HitObjects.OfType<ManiaHitObject>().ForEach(h => h.Column = availableColumns - 1 - h.Column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,15 @@
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Mods
|
||||
{
|
||||
public class ManiaModRandom : Mod, IApplicableToRulesetContainer<ManiaHitObject>
|
||||
public class ManiaModRandom : Mod, IApplicableToBeatmap<ManiaHitObject>
|
||||
{
|
||||
public override string Name => "Random";
|
||||
public override string Acronym => "RD";
|
||||
@ -21,12 +21,12 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public override string Description => @"Shuffle around the keys!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public void ApplyToRulesetContainer(RulesetContainer<ManiaHitObject> rulesetContainer)
|
||||
public void ApplyToBeatmap(Beatmap<ManiaHitObject> beatmap)
|
||||
{
|
||||
var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
|
||||
var availableColumns = ((ManiaBeatmap)beatmap).TotalColumns;
|
||||
var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList();
|
||||
|
||||
rulesetContainer.Objects.OfType<ManiaHitObject>().ForEach(h => h.Column = shuffledColumns[h.Column]);
|
||||
beatmap.HitObjects.OfType<ManiaHitObject>().ForEach(h => h.Column = shuffledColumns[h.Column]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Mania.Objects
|
||||
|
||||
private readonly int beatmapColumnCount;
|
||||
|
||||
|
||||
private readonly double endTime;
|
||||
private readonly double[] heldUntil;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
@ -57,6 +57,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
s.Process(h);
|
||||
}
|
||||
|
||||
// The peak strain will not be saved for the last section in the above loop
|
||||
foreach (Skill s in skills)
|
||||
s.SaveCurrentPeak();
|
||||
|
||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
|
||||
|
@ -105,13 +105,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
double approachRateFactor = 1.0f;
|
||||
if (Attributes.ApproachRate > 10.33f)
|
||||
approachRateFactor += 0.45f * (Attributes.ApproachRate - 10.33f);
|
||||
approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f);
|
||||
else if (Attributes.ApproachRate < 8.0f)
|
||||
{
|
||||
// HD is worth more with lower ar!
|
||||
if (mods.Any(h => h is OsuModHidden))
|
||||
approachRateFactor += 0.02f * (8.0f - Attributes.ApproachRate);
|
||||
else
|
||||
approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate);
|
||||
}
|
||||
|
||||
@ -119,7 +115,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
|
||||
if (mods.Any(h => h is OsuModHidden))
|
||||
aimValue *= 1.02 + (11.0f - Attributes.ApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11.
|
||||
aimValue *= 1.0f + 0.04f * (12.0f - Attributes.ApproachRate);
|
||||
|
||||
if (mods.Any(h => h is OsuModFlashlight))
|
||||
{
|
||||
@ -152,13 +148,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
if (beatmapMaxCombo > 0)
|
||||
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
|
||||
|
||||
double approachRateFactor = 1.0f;
|
||||
if (Attributes.ApproachRate > 10.33f)
|
||||
approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f);
|
||||
|
||||
speedValue *= approachRateFactor;
|
||||
|
||||
if (mods.Any(m => m is OsuModHidden))
|
||||
speedValue *= 1.18f;
|
||||
speedValue *= 1.0f + 0.04f * (12.0f - Attributes.ApproachRate);
|
||||
|
||||
// Scale the speed value with accuracy _slightly_
|
||||
speedValue *= 0.5f + accuracy / 2.0f;
|
||||
speedValue *= 0.02f + accuracy;
|
||||
// It is important to also consider accuracy difficulty when doing that
|
||||
speedValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
|
||||
speedValue *= 0.96f + Math.Pow(Attributes.OverallDifficulty, 2) / 1600;
|
||||
|
||||
return speedValue;
|
||||
}
|
||||
@ -186,7 +188,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
|
||||
|
||||
if (mods.Any(m => m is OsuModHidden))
|
||||
accuracyValue *= 1.02f;
|
||||
accuracyValue *= 1.08f;
|
||||
if (mods.Any(m => m is OsuModFlashlight))
|
||||
accuracyValue *= 1.02f;
|
||||
|
||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
if (HitObject is IHasComboInformation combo)
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
|
||||
AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : Color4.White);
|
||||
}
|
||||
|
||||
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
|
||||
|
@ -101,7 +101,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
float aimRotation = MathHelper.RadiansToDegrees((float)Math.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
|
||||
while (Math.Abs(aimRotation - Rotation) > 180)
|
||||
aimRotation += aimRotation < Rotation ? 360 : -360;
|
||||
|
@ -14,6 +14,7 @@ using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
@ -151,6 +152,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
base.SkinChanged(skin, allowFallback);
|
||||
|
||||
Body.AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : Body.AccentColour);
|
||||
Body.BorderColour = skin.GetValue<SkinConfiguration, Color4>(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : Body.BorderColour);
|
||||
Ball.AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : Ball.AccentColour);
|
||||
}
|
||||
|
||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||
{
|
||||
if (userTriggered || Time.Current < slider.EndTime)
|
||||
|
@ -39,10 +39,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
private int downCount;
|
||||
|
||||
private const float pressed_scale = 1.2f;
|
||||
private const float released_scale = 1f;
|
||||
|
||||
private float targetScale => downCount > 0 ? pressed_scale : released_scale;
|
||||
private void updateExpandedState()
|
||||
{
|
||||
if (downCount > 0)
|
||||
(ActiveCursor as OsuCursor)?.Expand();
|
||||
else
|
||||
(ActiveCursor as OsuCursor)?.Contract();
|
||||
}
|
||||
|
||||
public bool OnPressed(OsuAction action)
|
||||
{
|
||||
@ -51,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
case OsuAction.LeftButton:
|
||||
case OsuAction.RightButton:
|
||||
downCount++;
|
||||
ActiveCursor.ScaleTo(released_scale).ScaleTo(targetScale, 100, Easing.OutQuad);
|
||||
updateExpandedState();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -65,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
case OsuAction.LeftButton:
|
||||
case OsuAction.RightButton:
|
||||
if (--downCount == 0)
|
||||
ActiveCursor.ScaleTo(targetScale, 200, Easing.OutQuad);
|
||||
updateExpandedState();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -77,92 +80,106 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
protected override void PopIn()
|
||||
{
|
||||
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(targetScale, 400, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(targetScale * 0.8f, 450, Easing.OutQuint);
|
||||
ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
|
||||
}
|
||||
|
||||
public class OsuCursor : Container
|
||||
public class OsuCursor : SkinReloadableDrawable
|
||||
{
|
||||
private Drawable cursorContainer;
|
||||
private bool cursorExpand;
|
||||
|
||||
private Bindable<double> cursorScale;
|
||||
private Bindable<bool> autoCursorScale;
|
||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||
|
||||
private Container expandTarget;
|
||||
private Drawable scaleTarget;
|
||||
|
||||
public OsuCursor()
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
Size = new Vector2(42);
|
||||
}
|
||||
|
||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||
{
|
||||
cursorExpand = skin.GetValue<SkinConfiguration, bool>(s => s.CursorExpand ?? true);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config, IBindableBeatmap beatmap)
|
||||
{
|
||||
Child = cursorContainer = new SkinnableDrawable("cursor", _ => new CircularContainer
|
||||
InternalChild = expandTarget = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = Size.X / 6,
|
||||
BorderColour = Color4.White,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Pink.Opacity(0.5f),
|
||||
Radius = 5,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = Size.X / 3,
|
||||
BorderColour = Color4.White.Opacity(0.5f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.1f),
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.White,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}, restrictSize: false)
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = scaleTarget = new SkinnableDrawable("cursor", _ => new CircularContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = Size.X / 6,
|
||||
BorderColour = Color4.White,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Pink.Opacity(0.5f),
|
||||
Radius = 5,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
BorderThickness = Size.X / 3,
|
||||
BorderColour = Color4.White.Opacity(0.5f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
new CircularContainer
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Scale = new Vector2(0.1f),
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.White,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}, restrictSize: false)
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
};
|
||||
|
||||
this.beatmap.BindTo(beatmap);
|
||||
@ -187,8 +204,19 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
scale *= (float)(1 - 0.7 * (1 + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY);
|
||||
}
|
||||
|
||||
cursorContainer.Scale = new Vector2(scale);
|
||||
scaleTarget.Scale = new Vector2(scale);
|
||||
}
|
||||
|
||||
private const float pressed_scale = 1.2f;
|
||||
private const float released_scale = 1f;
|
||||
|
||||
public void Expand()
|
||||
{
|
||||
if (!cursorExpand) return;
|
||||
expandTarget.ScaleTo(released_scale).ScaleTo(pressed_scale, 100, Easing.OutQuad);
|
||||
}
|
||||
|
||||
public void Contract() => expandTarget.ScaleTo(released_scale, 100, Easing.OutQuad);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
@ -149,7 +149,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
||||
using (var stream = Resource.OpenResource(filename))
|
||||
using (var sr = new StreamReader(stream))
|
||||
{
|
||||
|
||||
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
|
||||
using (var ms = new MemoryStream())
|
||||
using (var sw = new StreamWriter(ms))
|
||||
|
@ -40,7 +40,6 @@ namespace osu.Game.Tests.Visual
|
||||
typeof(DrawableCarouselBeatmapSet),
|
||||
};
|
||||
|
||||
|
||||
private readonly Stack<BeatmapSetInfo> selectedSets = new Stack<BeatmapSetInfo>();
|
||||
private readonly HashSet<int> eagerSelectedIDs = new HashSet<int>();
|
||||
|
||||
|
@ -55,7 +55,6 @@ namespace osu.Game.Tests.Visual
|
||||
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
|
||||
AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo });
|
||||
|
||||
|
||||
scores = new[]
|
||||
{
|
||||
new APIScoreInfo
|
||||
|
@ -16,7 +16,6 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
public TestCaseBreadcrumbs()
|
||||
{
|
||||
|
||||
Add(breadcrumbs = new BreadcrumbControl<BreadcrumbTab>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
|
@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual
|
||||
linkColour = colours.Blue;
|
||||
|
||||
var chatManager = new ChannelManager();
|
||||
BindableCollection<Channel> availableChannels = (BindableCollection<Channel>)chatManager.AvailableChannels;
|
||||
BindableList<Channel> availableChannels = (BindableList<Channel>)chatManager.AvailableChannels;
|
||||
availableChannels.Add(new Channel { Name = "#english"});
|
||||
availableChannels.Add(new Channel { Name = "#japanese" });
|
||||
Dependencies.Cache(chatManager);
|
||||
|
@ -39,7 +39,6 @@ namespace osu.Game.Tests.Visual
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
AddStep("Add random", () =>
|
||||
{
|
||||
Key key = (Key)((int)Key.A + RNG.Next(26));
|
||||
|
@ -73,8 +73,8 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public event Action RoomsUpdated;
|
||||
|
||||
public readonly BindableCollection<Room> Rooms = new BindableCollection<Room>();
|
||||
IBindableCollection<Room> IRoomManager.Rooms => Rooms;
|
||||
public readonly BindableList<Room> Rooms = new BindableList<Room>();
|
||||
IBindableList<Room> IRoomManager.Rooms => Rooms;
|
||||
|
||||
public void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null) => Rooms.Add(room);
|
||||
|
||||
|
@ -17,12 +17,13 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
public TestCaseMatchLeaderboard()
|
||||
{
|
||||
Add(new MatchLeaderboard(new Room { RoomID = { Value = 3 } })
|
||||
Add(new MatchLeaderboard
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Size = new Vector2(550f, 450f),
|
||||
Scope = MatchLeaderboardScope.Overall,
|
||||
Room = new Room { RoomID = { Value = 3 } }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
public event Action RoomsUpdated;
|
||||
|
||||
public IBindableCollection<Room> Rooms { get; } = null;
|
||||
public IBindableList<Room> Rooms { get; } = null;
|
||||
|
||||
public void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null)
|
||||
{
|
||||
|
@ -57,11 +57,19 @@ namespace osu.Game.Tests.Visual
|
||||
|
||||
private class TestSongSelect : PlaySongSelect
|
||||
{
|
||||
public Action StartRequested;
|
||||
|
||||
public new Bindable<RulesetInfo> Ruleset => base.Ruleset;
|
||||
|
||||
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
|
||||
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
|
||||
public new BeatmapCarousel Carousel => base.Carousel;
|
||||
|
||||
protected override bool OnStart()
|
||||
{
|
||||
StartRequested?.Invoke();
|
||||
return base.OnStart();
|
||||
}
|
||||
}
|
||||
|
||||
private TestSongSelect songSelect;
|
||||
@ -182,6 +190,27 @@ namespace osu.Game.Tests.Visual
|
||||
void onRulesetChange(RulesetInfo ruleset) => rulesetChangeIndex = actionIndex--;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStartAfterUnMatchingFilterDoesNotStart()
|
||||
{
|
||||
addManyTestMaps();
|
||||
AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "has selection");
|
||||
|
||||
bool startRequested = false;
|
||||
|
||||
AddStep("set filter and finalize", () =>
|
||||
{
|
||||
songSelect.StartRequested = () => startRequested = true;
|
||||
|
||||
songSelect.Carousel.Filter(new FilterCriteria { SearchText = "somestringthatshouldn'tbematchable" });
|
||||
songSelect.FinaliseSelection();
|
||||
|
||||
songSelect.StartRequested = null;
|
||||
});
|
||||
|
||||
AddAssert("start not requested", () => !startRequested);
|
||||
}
|
||||
|
||||
private void importForRuleset(int id) => AddStep($"import test map for ruleset {id}", () => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())));
|
||||
|
||||
private static int importId;
|
||||
|
@ -57,5 +57,4 @@ namespace osu.Game.Tests.Visual
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ using osu.Game.Screens.Play;
|
||||
namespace osu.Game.Tests.Visual
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCaseSkipButton : OsuTestCase
|
||||
public class TestCaseSkipOverlay : OsuTestCase
|
||||
{
|
||||
protected override void LoadComplete()
|
||||
{
|
@ -5,7 +5,7 @@
|
||||
<PackageReference Include="DeepEqual" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.11.2" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
|
||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
@ -9,6 +10,7 @@ using Newtonsoft.Json;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Serialization;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@ -112,6 +114,11 @@ namespace osu.Game.Beatmaps
|
||||
[JsonProperty("difficulty_rating")]
|
||||
public double StarDifficulty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Currently only populated for beatmap deletion. Use <see cref="ScoreManager"/> to query scores.
|
||||
/// </summary>
|
||||
public List<ScoreInfo> Scores { get; set; }
|
||||
|
||||
public override string ToString() => $"{Metadata} [{Version}]";
|
||||
|
||||
public bool Equals(BeatmapInfo other)
|
||||
|
@ -64,7 +64,8 @@ namespace osu.Game.Beatmaps
|
||||
base.AddIncludesForDeletion(query)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
|
||||
.Include(s => s.Metadata);
|
||||
.Include(s => s.Metadata)
|
||||
.Include(s => s.Beatmaps).ThenInclude(b => b.Scores);
|
||||
|
||||
protected override IQueryable<BeatmapSetInfo> AddIncludesForConsumption(IQueryable<BeatmapSetInfo> query) =>
|
||||
base.AddIncludesForConsumption(query)
|
||||
|
@ -151,7 +151,7 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
public bool WaveformLoaded => waveform.IsResultAvailable;
|
||||
public Waveform Waveform => waveform.Value;
|
||||
protected virtual Waveform GetWaveform() => new Waveform();
|
||||
protected virtual Waveform GetWaveform() => new Waveform(null);
|
||||
private readonly RecyclableLazy<Waveform> waveform;
|
||||
|
||||
public bool StoryboardLoaded => storyboard.IsResultAvailable;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Configuration.Tracking;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -96,15 +97,27 @@ namespace osu.Game.Configuration
|
||||
Set(OsuSetting.ScreenshotCaptureMenuCursor, false);
|
||||
|
||||
Set(OsuSetting.SongSelectRightMouseScroll, false);
|
||||
|
||||
Set(OsuSetting.Scaling, ScalingMode.Off);
|
||||
|
||||
Set(OsuSetting.ScalingSizeX, 0.8f, 0.2f, 1f);
|
||||
Set(OsuSetting.ScalingSizeY, 0.8f, 0.2f, 1f);
|
||||
|
||||
Set(OsuSetting.ScalingPositionX, 0.5f, 0f, 1f);
|
||||
Set(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
|
||||
|
||||
Set(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f);
|
||||
}
|
||||
|
||||
public OsuConfigManager(Storage storage) : base(storage)
|
||||
public OsuConfigManager(Storage storage)
|
||||
: base(storage)
|
||||
{
|
||||
}
|
||||
|
||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||
{
|
||||
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled"))
|
||||
new TrackedSetting<bool>(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled")),
|
||||
new TrackedSetting<ScalingMode>(OsuSetting.Scaling, m => new SettingDescription(m, "scaling", m.GetDescription())),
|
||||
};
|
||||
}
|
||||
|
||||
@ -151,6 +164,12 @@ namespace osu.Game.Configuration
|
||||
BeatmapHitsounds,
|
||||
IncreaseFirstObjectVisibility,
|
||||
ScoreDisplayMode,
|
||||
ExternalLinkWarning
|
||||
ExternalLinkWarning,
|
||||
Scaling,
|
||||
ScalingPositionX,
|
||||
ScalingPositionY,
|
||||
ScalingSizeX,
|
||||
ScalingSizeY,
|
||||
UIScale
|
||||
}
|
||||
}
|
||||
|
16
osu.Game/Configuration/ScalingMode.cs
Normal file
16
osu.Game/Configuration/ScalingMode.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace osu.Game.Configuration
|
||||
{
|
||||
public enum ScalingMode
|
||||
{
|
||||
Off,
|
||||
Everything,
|
||||
[Description("Excluding overlays")]
|
||||
ExcludeOverlays,
|
||||
Gameplay,
|
||||
}
|
||||
}
|
@ -79,6 +79,7 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
AddInternal(new DrawableLinkCompiler(drawables.OfType<SpriteText>().ToList())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
|
||||
Action = action ?? (() =>
|
||||
{
|
||||
@ -122,5 +123,10 @@ namespace osu.Game.Graphics.Containers
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// We want the compilers to always be visible no matter where they are, so RelativeSizeAxes is used.
|
||||
// However due to https://github.com/ppy/osu-framework/issues/2073, it's possible for the compilers to be relative size in the flow's auto-size axes - an unsupported operation.
|
||||
// Since the compilers don't display any content and don't affect the layout, it's simplest to exclude them from the flow.
|
||||
public override IEnumerable<Drawable> FlowingChildren => base.FlowingChildren.Where(c => !(c is DrawableLinkCompiler));
|
||||
}
|
||||
}
|
||||
|
161
osu.Game/Graphics/Containers/ScalingContainer.cs
Normal file
161
osu.Game/Graphics/Containers/ScalingContainer.cs
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles user-defined scaling, allowing application at multiple levels defined by <see cref="ScalingMode"/>.
|
||||
/// </summary>
|
||||
public class ScalingContainer : Container
|
||||
{
|
||||
private Bindable<float> sizeX;
|
||||
private Bindable<float> sizeY;
|
||||
private Bindable<float> posX;
|
||||
private Bindable<float> posY;
|
||||
|
||||
private readonly ScalingMode? targetMode;
|
||||
|
||||
private Bindable<ScalingMode> scalingMode;
|
||||
|
||||
private readonly Container content;
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
private readonly Container sizableContainer;
|
||||
|
||||
private Drawable backgroundLayer;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new instance.
|
||||
/// </summary>
|
||||
/// <param name="targetMode">The mode which this container should be handling. Handles all modes if null.</param>
|
||||
public ScalingContainer(ScalingMode? targetMode = null)
|
||||
{
|
||||
this.targetMode = targetMode;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
InternalChild = sizableContainer = new AlwaysInputContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
CornerRadius = 10,
|
||||
Child = content = new ScalingDrawSizePreservingFillContainer(targetMode != ScalingMode.Gameplay)
|
||||
};
|
||||
}
|
||||
|
||||
private class ScalingDrawSizePreservingFillContainer : DrawSizePreservingFillContainer
|
||||
{
|
||||
private readonly bool applyUIScale;
|
||||
private Bindable<float> uiScale;
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
public ScalingDrawSizePreservingFillContainer(bool applyUIScale)
|
||||
{
|
||||
this.applyUIScale = applyUIScale;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager osuConfig)
|
||||
{
|
||||
if (applyUIScale)
|
||||
{
|
||||
uiScale = osuConfig.GetBindable<float>(OsuSetting.UIScale);
|
||||
uiScale.BindValueChanged(scaleChanged, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void scaleChanged(float value)
|
||||
{
|
||||
this.ScaleTo(new Vector2(value), 500, Easing.Out);
|
||||
this.ResizeTo(new Vector2(1 / value), 500, Easing.Out);
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
scalingMode = config.GetBindable<ScalingMode>(OsuSetting.Scaling);
|
||||
scalingMode.ValueChanged += _ => updateSize();
|
||||
|
||||
sizeX = config.GetBindable<float>(OsuSetting.ScalingSizeX);
|
||||
sizeX.ValueChanged += _ => updateSize();
|
||||
|
||||
sizeY = config.GetBindable<float>(OsuSetting.ScalingSizeY);
|
||||
sizeY.ValueChanged += _ => updateSize();
|
||||
|
||||
posX = config.GetBindable<float>(OsuSetting.ScalingPositionX);
|
||||
posX.ValueChanged += _ => updateSize();
|
||||
|
||||
posY = config.GetBindable<float>(OsuSetting.ScalingPositionY);
|
||||
posY.ValueChanged += _ => updateSize();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
updateSize();
|
||||
sizableContainer.FinishTransforms();
|
||||
}
|
||||
|
||||
private bool requiresBackgroundVisible => (scalingMode == ScalingMode.Everything || scalingMode == ScalingMode.ExcludeOverlays) && (sizeX.Value != 1 || sizeY.Value != 1);
|
||||
|
||||
private void updateSize()
|
||||
{
|
||||
if (targetMode == ScalingMode.Everything)
|
||||
{
|
||||
// the top level scaling container manages the background to be displayed while scaling.
|
||||
if (requiresBackgroundVisible)
|
||||
{
|
||||
if (backgroundLayer == null)
|
||||
LoadComponentAsync(backgroundLayer = new Background("Menu/menu-background-1")
|
||||
{
|
||||
Colour = OsuColour.Gray(0.1f),
|
||||
Alpha = 0,
|
||||
Depth = float.MaxValue
|
||||
}, d =>
|
||||
{
|
||||
AddInternal(d);
|
||||
d.FadeTo(requiresBackgroundVisible ? 1 : 0, 4000, Easing.OutQuint);
|
||||
});
|
||||
else
|
||||
backgroundLayer.FadeIn(500);
|
||||
}
|
||||
else
|
||||
backgroundLayer?.FadeOut(500);
|
||||
}
|
||||
|
||||
bool scaling = targetMode == null || scalingMode.Value == targetMode;
|
||||
|
||||
var targetSize = scaling ? new Vector2(sizeX, sizeY) : Vector2.One;
|
||||
var targetPosition = scaling ? new Vector2(posX, posY) * (Vector2.One - targetSize) : Vector2.Zero;
|
||||
bool requiresMasking = scaling && targetSize != Vector2.One;
|
||||
|
||||
if (requiresMasking)
|
||||
sizableContainer.Masking = true;
|
||||
|
||||
sizableContainer.MoveTo(targetPosition, 500, Easing.OutQuart);
|
||||
sizableContainer.ResizeTo(targetSize, 500, Easing.OutQuart).OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
|
||||
}
|
||||
|
||||
private class AlwaysInputContainer : Container
|
||||
{
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
public AlwaysInputContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ using osuTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
@ -33,38 +32,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private readonly Box leftBox;
|
||||
private readonly Box rightBox;
|
||||
|
||||
public virtual string TooltipText
|
||||
{
|
||||
get
|
||||
{
|
||||
var bindableDouble = CurrentNumber as BindableNumber<double>;
|
||||
var bindableFloat = CurrentNumber as BindableNumber<float>;
|
||||
var floatValue = bindableDouble?.Value ?? bindableFloat?.Value;
|
||||
var floatPrecision = bindableDouble?.Precision ?? bindableFloat?.Precision;
|
||||
|
||||
if (floatValue != null)
|
||||
{
|
||||
var floatMinValue = bindableDouble?.MinValue ?? bindableFloat.MinValue;
|
||||
var floatMaxValue = bindableDouble?.MaxValue ?? bindableFloat.MaxValue;
|
||||
|
||||
if (floatMaxValue == 1 && (floatMinValue == 0 || floatMinValue == -1))
|
||||
return floatValue.Value.ToString("P0");
|
||||
|
||||
var decimalPrecision = normalise((decimal)floatPrecision, max_decimal_digits);
|
||||
|
||||
// Find the number of significant digits (we could have less than 5 after normalize())
|
||||
var significantDigits = findPrecision(decimalPrecision);
|
||||
|
||||
return floatValue.Value.ToString($"N{significantDigits}");
|
||||
}
|
||||
|
||||
var bindableInt = CurrentNumber as BindableNumber<int>;
|
||||
if (bindableInt != null)
|
||||
return bindableInt.Value.ToString("N0");
|
||||
|
||||
return Current.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
public virtual string TooltipText { get; private set; }
|
||||
|
||||
private Color4 accentColour;
|
||||
public Color4 AccentColour
|
||||
@ -124,6 +92,12 @@ namespace osu.Game.Graphics.UserInterface
|
||||
AccentColour = colours.Pink;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
updateTooltipText(Current.Value);
|
||||
base.LoadComplete();
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
Nub.Glowing = true;
|
||||
@ -136,21 +110,34 @@ namespace osu.Game.Graphics.UserInterface
|
||||
base.OnHoverLost(e);
|
||||
}
|
||||
|
||||
protected override void OnUserChange()
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
base.OnUserChange();
|
||||
playSample();
|
||||
Nub.Current.Value = true;
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
private void playSample()
|
||||
protected override bool OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
Nub.Current.Value = false;
|
||||
return base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
protected override void OnUserChange(T value)
|
||||
{
|
||||
base.OnUserChange(value);
|
||||
playSample(value);
|
||||
updateTooltipText(value);
|
||||
}
|
||||
|
||||
private void playSample(T value)
|
||||
{
|
||||
if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
|
||||
return;
|
||||
|
||||
if (Current.Value.Equals(lastSampleValue))
|
||||
if (value.Equals(lastSampleValue))
|
||||
return;
|
||||
|
||||
lastSampleValue = Current.Value;
|
||||
lastSampleValue = value;
|
||||
|
||||
lastSampleTime = Clock.CurrentTime;
|
||||
sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
|
||||
@ -163,16 +150,28 @@ namespace osu.Game.Graphics.UserInterface
|
||||
sample.Play();
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
private void updateTooltipText(T value)
|
||||
{
|
||||
Nub.Current.Value = true;
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
if (CurrentNumber.IsInteger)
|
||||
TooltipText = ((int)Convert.ChangeType(value, typeof(int))).ToString("N0");
|
||||
else
|
||||
{
|
||||
double floatValue = (double)Convert.ChangeType(value, typeof(double));
|
||||
double floatMinValue = (double)Convert.ChangeType(CurrentNumber.MinValue, typeof(double));
|
||||
double floatMaxValue = (double)Convert.ChangeType(CurrentNumber.MaxValue, typeof(double));
|
||||
|
||||
protected override bool OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
Nub.Current.Value = false;
|
||||
return base.OnMouseUp(e);
|
||||
if (floatMaxValue == 1 && floatMinValue >= -1)
|
||||
TooltipText = floatValue.ToString("P0");
|
||||
else
|
||||
{
|
||||
var decimalPrecision = normalise((decimal)Convert.ChangeType(CurrentNumber.Precision, typeof(decimal)), max_decimal_digits);
|
||||
|
||||
// Find the number of significant digits (we could have less than 5 after normalize())
|
||||
var significantDigits = findPrecision(decimalPrecision);
|
||||
|
||||
TooltipText = floatValue.ToString($"N{significantDigits}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
|
@ -160,7 +160,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Text = (value as IHasDescription)?.Description ?? (value as Enum)?.GetDescription() ?? value.ToString(),
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
|
||||
},
|
||||
Bar = new Box
|
||||
{
|
||||
@ -173,6 +172,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
},
|
||||
new HoverClickSounds()
|
||||
};
|
||||
|
||||
Active.BindValueChanged(val => Text.Font = val ? @"Exo2.0-Bold" : @"Exo2.0", true);
|
||||
}
|
||||
|
||||
protected override void OnActivated() => fadeActive();
|
||||
|
@ -46,7 +46,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
box = new Box
|
||||
{
|
||||
@ -59,6 +58,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
},
|
||||
new HoverClickSounds()
|
||||
};
|
||||
|
||||
Active.BindValueChanged(val => Text.Font = val ? @"Exo2.0-Bold" : @"Exo2.0", true);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
|
@ -62,6 +62,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
fill.Width = value * UsableWidth;
|
||||
}
|
||||
|
||||
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||
protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.4-rtm-31024");
|
||||
.HasAnnotation("ProductVersion", "2.2.0-rtm-35687");
|
||||
|
||||
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
|
||||
{
|
||||
@ -215,6 +215,25 @@ namespace osu.Game.Migrations
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int>("ReferenceCount");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ReferenceCount");
|
||||
|
||||
b.ToTable("FileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
@ -239,25 +258,6 @@ namespace osu.Game.Migrations
|
||||
b.ToTable("KeyBinding");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("Hash");
|
||||
|
||||
b.Property<int>("ReferenceCount");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("Hash")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ReferenceCount");
|
||||
|
||||
b.ToTable("FileInfo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
|
||||
{
|
||||
b.Property<int?>("ID")
|
||||
@ -454,7 +454,7 @@ namespace osu.Game.Migrations
|
||||
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
|
||||
{
|
||||
b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
|
||||
.WithMany()
|
||||
.WithMany("Scores")
|
||||
.HasForeignKey("BeatmapInfoID")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
|
@ -101,6 +101,9 @@ namespace osu.Game.Online.API
|
||||
//todo: replace this with a ping request.
|
||||
log.Add(@"In a failing state, waiting a bit before we try again...");
|
||||
Thread.Sleep(5000);
|
||||
|
||||
if (!IsLoggedIn) goto case APIState.Connecting;
|
||||
|
||||
if (queue.Count == 0)
|
||||
{
|
||||
log.Add(@"Queueing a ping request");
|
||||
|
@ -41,7 +41,6 @@ namespace osu.Game.Online.Chat
|
||||
/// </summary>
|
||||
private readonly List<LocalEchoMessage> pendingMessages = new List<LocalEchoMessage>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An event that fires when new messages arrived.
|
||||
/// </summary>
|
||||
|
@ -29,8 +29,8 @@ namespace osu.Game.Online.Chat
|
||||
@"#lobby"
|
||||
};
|
||||
|
||||
private readonly BindableCollection<Channel> availableChannels = new BindableCollection<Channel>();
|
||||
private readonly BindableCollection<Channel> joinedChannels = new BindableCollection<Channel>();
|
||||
private readonly BindableList<Channel> availableChannels = new BindableList<Channel>();
|
||||
private readonly BindableList<Channel> joinedChannels = new BindableList<Channel>();
|
||||
|
||||
/// <summary>
|
||||
/// The currently opened channel
|
||||
@ -40,12 +40,12 @@ namespace osu.Game.Online.Chat
|
||||
/// <summary>
|
||||
/// The Channels the player has joined
|
||||
/// </summary>
|
||||
public IBindableCollection<Channel> JoinedChannels => joinedChannels;
|
||||
public IBindableList<Channel> JoinedChannels => joinedChannels;
|
||||
|
||||
/// <summary>
|
||||
/// The channels available for the player to join
|
||||
/// </summary>
|
||||
public IBindableCollection<Channel> AvailableChannels => availableChannels;
|
||||
public IBindableList<Channel> AvailableChannels => availableChannels;
|
||||
|
||||
private IAPIProvider api;
|
||||
|
||||
|
@ -37,10 +37,10 @@ namespace osu.Game.Online.Multiplayer
|
||||
public RulesetInfo Ruleset { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly BindableCollection<Mod> AllowedMods = new BindableCollection<Mod>();
|
||||
public readonly BindableList<Mod> AllowedMods = new BindableList<Mod>();
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly BindableCollection<Mod> RequiredMods = new BindableCollection<Mod>();
|
||||
public readonly BindableList<Mod> RequiredMods = new BindableList<Mod>();
|
||||
|
||||
[JsonProperty("beatmap")]
|
||||
private APIBeatmap apiBeatmap { get; set; }
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Online.Multiplayer
|
||||
public Bindable<User> Host { get; private set; } = new Bindable<User>();
|
||||
|
||||
[JsonProperty("playlist")]
|
||||
public BindableCollection<PlaylistItem> Playlist { get; set; } = new BindableCollection<PlaylistItem>();
|
||||
public BindableList<PlaylistItem> Playlist { get; set; } = new BindableList<PlaylistItem>();
|
||||
|
||||
[JsonProperty("channel_id")]
|
||||
public Bindable<int> ChannelId { get; private set; } = new Bindable<int>();
|
||||
|
@ -26,6 +26,7 @@ using osu.Framework.Platform;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Input;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
@ -187,6 +188,7 @@ namespace osu.Game
|
||||
}
|
||||
|
||||
private ExternalLinkOpener externalLinkOpener;
|
||||
|
||||
public void OpenUrlExternally(string url)
|
||||
{
|
||||
if (url.StartsWith("/"))
|
||||
@ -353,7 +355,14 @@ namespace osu.Game
|
||||
ActionRequested = action => volume.Adjust(action),
|
||||
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
|
||||
},
|
||||
mainContent = new Container { RelativeSizeAxes = Axes.Both },
|
||||
screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
mainContent = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
|
||||
idleTracker = new IdleTracker(6000)
|
||||
});
|
||||
@ -362,7 +371,7 @@ namespace osu.Game
|
||||
{
|
||||
screenStack.ModePushed += screenAdded;
|
||||
screenStack.Exited += screenRemoved;
|
||||
mainContent.Add(screenStack);
|
||||
screenContainer.Add(screenStack);
|
||||
});
|
||||
|
||||
loadComponentSingleFile(Toolbar = new Toolbar
|
||||
@ -497,7 +506,7 @@ namespace osu.Game
|
||||
if (notifications.State == Visibility.Visible)
|
||||
offset -= ToolbarButton.WIDTH / 2;
|
||||
|
||||
screenStack.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
|
||||
screenContainer.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
|
||||
}
|
||||
|
||||
settings.StateChanged += _ => updateScreenOffset();
|
||||
@ -555,7 +564,7 @@ namespace osu.Game
|
||||
focused.StateChanged += s =>
|
||||
{
|
||||
visibleOverlayCount += s == Visibility.Visible ? 1 : -1;
|
||||
screenStack.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
|
||||
screenContainer.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
|
||||
};
|
||||
}
|
||||
|
||||
@ -646,6 +655,7 @@ namespace osu.Game
|
||||
|
||||
private OsuScreen currentScreen;
|
||||
private FrameworkConfigManager frameworkConfig;
|
||||
private ScalingContainer screenContainer;
|
||||
|
||||
protected override bool OnExiting()
|
||||
{
|
||||
@ -685,7 +695,7 @@ namespace osu.Game
|
||||
ruleset.Disabled = applyBeatmapRulesetRestrictions;
|
||||
Beatmap.Disabled = applyBeatmapRulesetRestrictions;
|
||||
|
||||
mainContent.Padding = new MarginPadding { Top = ToolbarOffset };
|
||||
screenContainer.Padding = new MarginPadding { Top = ToolbarOffset };
|
||||
|
||||
MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Audio;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Input;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.IO;
|
||||
@ -189,7 +190,7 @@ namespace osu.Game
|
||||
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
|
||||
};
|
||||
|
||||
base.Content.Add(new DrawSizePreservingFillContainer { Child = MenuCursorContainer });
|
||||
base.Content.Add(new ScalingContainer(ScalingMode.Everything) { Child = MenuCursorContainer });
|
||||
|
||||
KeyBindingStore.Register(globalBinding);
|
||||
dependencies.Cache(globalBinding);
|
||||
@ -247,7 +248,8 @@ namespace osu.Game
|
||||
var extension = Path.GetExtension(paths.First())?.ToLowerInvariant();
|
||||
|
||||
foreach (var importer in fileImporters)
|
||||
if (importer.HandledExtensions.Contains(extension)) importer.Import(paths);
|
||||
if (importer.HandledExtensions.Contains(extension))
|
||||
importer.Import(paths);
|
||||
}
|
||||
|
||||
public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray();
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osuTK;
|
||||
@ -18,7 +19,7 @@ namespace osu.Game.Overlays.Chat.Selection
|
||||
public readonly FillFlowContainer<ChannelListItem> ChannelFlow;
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => ChannelFlow.Children;
|
||||
public IEnumerable<string> FilterTerms => new[] { Header };
|
||||
public IEnumerable<string> FilterTerms => Array.Empty<string>();
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
|
@ -77,7 +77,6 @@ namespace osu.Game.Overlays.Chat.Tabs
|
||||
CloseButton.FadeIn(TRANSITION_LENGTH, Easing.OutQuint);
|
||||
}
|
||||
|
||||
|
||||
protected override void FadeInactive()
|
||||
{
|
||||
base.FadeInactive();
|
||||
|
@ -18,7 +18,6 @@ namespace osu.Game.Overlays.KeyBinding
|
||||
Add(new InGameKeyBindingsSubsection(manager));
|
||||
}
|
||||
|
||||
|
||||
private class DefaultBindingsSubsection : KeyBindingsSubsection
|
||||
{
|
||||
protected override string Header => string.Empty;
|
||||
|
@ -176,7 +176,6 @@ namespace osu.Game.Overlays.Mods
|
||||
section.DeselectTypes(modTypes, immediate);
|
||||
}
|
||||
|
||||
|
||||
private SampleChannel sampleOn, sampleOff;
|
||||
|
||||
private void modButtonPressed(Mod selectedMod)
|
||||
|
@ -49,7 +49,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
|
||||
Api.Queue(request);
|
||||
}
|
||||
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
base.Dispose(isDisposing);
|
||||
|
@ -6,9 +6,14 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
@ -16,24 +21,33 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
{
|
||||
protected override string Header => "Layout";
|
||||
|
||||
private FillFlowContainer letterboxSettings;
|
||||
private FillFlowContainer<SettingsSlider<float>> scalingSettings;
|
||||
|
||||
private Bindable<bool> letterboxing;
|
||||
private Bindable<ScalingMode> scalingMode;
|
||||
private Bindable<Size> sizeFullscreen;
|
||||
|
||||
private OsuGameBase game;
|
||||
private SettingsDropdown<Size> resolutionDropdown;
|
||||
private SettingsEnumDropdown<WindowMode> windowModeDropdown;
|
||||
|
||||
private Bindable<float> scalingPositionX;
|
||||
private Bindable<float> scalingPositionY;
|
||||
private Bindable<float> scalingSizeX;
|
||||
private Bindable<float> scalingSizeY;
|
||||
|
||||
private const int transition_duration = 400;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(FrameworkConfigManager config, OsuGameBase game)
|
||||
private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game)
|
||||
{
|
||||
this.game = game;
|
||||
|
||||
letterboxing = config.GetBindable<bool>(FrameworkSetting.Letterboxing);
|
||||
scalingMode = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling);
|
||||
sizeFullscreen = config.GetBindable<Size>(FrameworkSetting.SizeFullscreen);
|
||||
scalingSizeX = osuConfig.GetBindable<float>(OsuSetting.ScalingSizeX);
|
||||
scalingSizeY = osuConfig.GetBindable<float>(OsuSetting.ScalingSizeY);
|
||||
scalingPositionX = osuConfig.GetBindable<float>(OsuSetting.ScalingPositionX);
|
||||
scalingPositionY = osuConfig.GetBindable<float>(OsuSetting.ScalingPositionY);
|
||||
|
||||
Container resolutionSettingsContainer;
|
||||
|
||||
@ -49,12 +63,19 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
},
|
||||
new SettingsCheckbox
|
||||
new SettingsSlider<float, UIScaleSlider>
|
||||
{
|
||||
LabelText = "Letterboxing",
|
||||
Bindable = letterboxing,
|
||||
LabelText = "UI Scaling",
|
||||
TransferValueOnCommit = true,
|
||||
Bindable = osuConfig.GetBindable<float>(OsuSetting.UIScale),
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
letterboxSettings = new FillFlowContainer
|
||||
new SettingsEnumDropdown<ScalingMode>
|
||||
{
|
||||
LabelText = "Screen Scaling",
|
||||
Bindable = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling),
|
||||
},
|
||||
scalingSettings = new FillFlowContainer<SettingsSlider<float>>
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
@ -62,25 +83,38 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
AutoSizeDuration = transition_duration,
|
||||
AutoSizeEasing = Easing.OutQuint,
|
||||
Masking = true,
|
||||
|
||||
Children = new Drawable[]
|
||||
Children = new []
|
||||
{
|
||||
new SettingsSlider<double>
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Horizontal position",
|
||||
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionX),
|
||||
Bindable = scalingPositionX,
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
new SettingsSlider<double>
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Vertical position",
|
||||
Bindable = config.GetBindable<double>(FrameworkSetting.LetterboxPositionY),
|
||||
Bindable = scalingPositionY,
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Horizontal scale",
|
||||
Bindable = scalingSizeX,
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
LabelText = "Vertical scale",
|
||||
Bindable = scalingSizeY,
|
||||
KeyboardStep = 0.01f
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
scalingSettings.ForEach(s => bindPreviewEvent(s.Bindable));
|
||||
|
||||
var resolutions = getResolutions();
|
||||
|
||||
if (resolutions.Count > 1)
|
||||
@ -105,16 +139,46 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
}, true);
|
||||
}
|
||||
|
||||
letterboxing.BindValueChanged(isVisible =>
|
||||
scalingMode.BindValueChanged(mode =>
|
||||
{
|
||||
letterboxSettings.ClearTransforms();
|
||||
letterboxSettings.AutoSizeAxes = isVisible ? Axes.Y : Axes.None;
|
||||
scalingSettings.ClearTransforms();
|
||||
scalingSettings.AutoSizeAxes = mode != ScalingMode.Off ? Axes.Y : Axes.None;
|
||||
|
||||
if (!isVisible)
|
||||
letterboxSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
|
||||
if (mode == ScalingMode.Off)
|
||||
scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
|
||||
|
||||
scalingSettings.ForEach(s => s.TransferValueOnCommit = mode == ScalingMode.Everything);
|
||||
}, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a delayed bindable which only updates when a condition is met.
|
||||
/// </summary>
|
||||
/// <param name="bindable">The config bindable.</param>
|
||||
/// <returns>A bindable which will propagate updates with a delay.</returns>
|
||||
private void bindPreviewEvent(Bindable<float> bindable)
|
||||
{
|
||||
bindable.ValueChanged += v =>
|
||||
{
|
||||
switch (scalingMode.Value)
|
||||
{
|
||||
case ScalingMode.Gameplay:
|
||||
showPreview();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Drawable preview;
|
||||
private void showPreview()
|
||||
{
|
||||
if (preview?.IsAlive != true)
|
||||
game.Add(preview = new ScalingPreview());
|
||||
|
||||
preview.FadeOutFromOne(1500);
|
||||
preview.Expire();
|
||||
}
|
||||
|
||||
private IReadOnlyList<Size> getResolutions()
|
||||
{
|
||||
var resolutions = new List<Size> { new Size(9999, 9999) };
|
||||
@ -132,6 +196,24 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
|
||||
return resolutions;
|
||||
}
|
||||
|
||||
private class ScalingPreview : ScalingContainer
|
||||
{
|
||||
public ScalingPreview()
|
||||
{
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class UIScaleSlider : OsuSliderBar<float>
|
||||
{
|
||||
public override string TooltipText => base.TooltipText + "x";
|
||||
}
|
||||
|
||||
private class ResolutionSettingsDropdown : SettingsDropdown<Size>
|
||||
{
|
||||
protected override OsuDropdown<Size> CreateDropdown() => new ResolutionDropdownControl { Items = Items };
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
@ -78,66 +77,15 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
|
||||
{
|
||||
public override Bindable<double> Bindable
|
||||
{
|
||||
get { return ((SensitivitySlider)Control).Sensitivity; }
|
||||
|
||||
set
|
||||
{
|
||||
BindableDouble doubleValue = (BindableDouble)value;
|
||||
|
||||
// create a second layer of bindable so we can only handle state changes when not being dragged.
|
||||
((SensitivitySlider)Control).Sensitivity = doubleValue;
|
||||
|
||||
// this bindable will still act as the "interactive" bindable displayed during a drag.
|
||||
base.Bindable = new BindableDouble(doubleValue.Value)
|
||||
{
|
||||
Default = doubleValue.Default,
|
||||
MinValue = doubleValue.MinValue,
|
||||
MaxValue = doubleValue.MaxValue
|
||||
};
|
||||
|
||||
// one-way binding to update the sliderbar with changes from external actions.
|
||||
doubleValue.DisabledChanged += disabled => base.Bindable.Disabled = disabled;
|
||||
doubleValue.ValueChanged += newValue => base.Bindable.Value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public SensitivitySetting()
|
||||
{
|
||||
KeyboardStep = 0.01f;
|
||||
TransferValueOnCommit = true;
|
||||
}
|
||||
}
|
||||
|
||||
private class SensitivitySlider : OsuSliderBar<double>
|
||||
{
|
||||
public Bindable<double> Sensitivity;
|
||||
|
||||
public SensitivitySlider()
|
||||
{
|
||||
Current.ValueChanged += newValue =>
|
||||
{
|
||||
if (!isDragging && Sensitivity != null)
|
||||
Sensitivity.Value = newValue;
|
||||
};
|
||||
}
|
||||
|
||||
private bool isDragging;
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
isDragging = true;
|
||||
return base.OnDragStart(e);
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(DragEndEvent e)
|
||||
{
|
||||
isDragging = false;
|
||||
Current.TriggerChange();
|
||||
|
||||
return base.OnDragEnd(e);
|
||||
}
|
||||
|
||||
public override string TooltipText => Current.Disabled ? "Enable raw input to adjust sensitivity" : Current.Value.ToString(@"0.##x");
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
@ -23,14 +22,16 @@ namespace osu.Game.Overlays.Settings
|
||||
RelativeSizeAxes = Axes.X
|
||||
};
|
||||
|
||||
public float KeyboardStep;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
public bool TransferValueOnCommit
|
||||
{
|
||||
var slider = Control as U;
|
||||
if (slider != null)
|
||||
slider.KeyboardStep = KeyboardStep;
|
||||
get => ((U)Control).TransferValueOnCommit;
|
||||
set => ((U)Control).TransferValueOnCommit = value;
|
||||
}
|
||||
|
||||
public float KeyboardStep
|
||||
{
|
||||
get => ((U)Control).KeyboardStep;
|
||||
set => ((U)Control).KeyboardStep = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,6 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
||||
// osu-stable treated the first span of the slider as a repeat, but no repeats are happening
|
||||
repeatCount = Math.Max(0, repeatCount - 1);
|
||||
|
||||
|
||||
if (split.Length > 7)
|
||||
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
|
||||
|
||||
|
27
osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
Normal file
27
osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Screens;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Backgrounds
|
||||
{
|
||||
public class BackgroundScreenBlack : BackgroundScreen
|
||||
{
|
||||
public BackgroundScreenBlack()
|
||||
{
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
Show();
|
||||
}
|
||||
}
|
||||
}
|
@ -2,10 +2,14 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Skinning;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Screens.Backgrounds
|
||||
{
|
||||
@ -16,11 +20,21 @@ namespace osu.Game.Screens.Backgrounds
|
||||
|
||||
private string backgroundName => $@"Menu/menu-background-{currentDisplay % background_count + 1}";
|
||||
|
||||
private Bindable<User> user;
|
||||
private Bindable<Skin> skin;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(IAPIProvider api, SkinManager skinManager)
|
||||
{
|
||||
user = api.LocalUser.GetBoundCopy();
|
||||
skin = skinManager.CurrentSkin.GetBoundCopy();
|
||||
|
||||
user.ValueChanged += _ => Next();
|
||||
skin.ValueChanged += _ => Next();
|
||||
|
||||
currentDisplay = RNG.Next(0, background_count);
|
||||
display(new Background(backgroundName));
|
||||
|
||||
Next();
|
||||
}
|
||||
|
||||
private void display(Background newBackground)
|
||||
@ -39,8 +53,33 @@ namespace osu.Game.Screens.Backgrounds
|
||||
nextTask?.Cancel();
|
||||
nextTask = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
LoadComponentAsync(new Background(backgroundName) { Depth = currentDisplay }, display);
|
||||
Background background;
|
||||
|
||||
if (user.Value?.IsSupporter ?? false)
|
||||
background = new SkinnedBackground(skin.Value, backgroundName);
|
||||
else
|
||||
background = new Background(backgroundName);
|
||||
|
||||
background.Depth = currentDisplay;
|
||||
|
||||
LoadComponentAsync(background, display);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
private class SkinnedBackground : Background
|
||||
{
|
||||
private readonly Skin skin;
|
||||
|
||||
public SkinnedBackground(Skin skin, string fallbackTextureName) : base(fallbackTextureName)
|
||||
{
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
namespace osu.Game.Screens.Backgrounds
|
||||
{
|
||||
public class BackgroundScreenEmpty : BackgroundScreen
|
||||
{
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@ namespace osu.Game.Screens.Edit.Components
|
||||
|
||||
public TimeInfoContainer()
|
||||
{
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
trackTimer = new OsuSpriteText
|
||||
|
@ -238,11 +238,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
case Key.Right:
|
||||
beatDivisor.Next();
|
||||
OnUserChange();
|
||||
OnUserChange(Current);
|
||||
return true;
|
||||
case Key.Left:
|
||||
beatDivisor.Previous();
|
||||
OnUserChange();
|
||||
OnUserChange(Current);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -279,7 +279,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
var xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
|
||||
|
||||
CurrentNumber.Value = availableDivisors.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First();
|
||||
OnUserChange();
|
||||
OnUserChange(Current);
|
||||
}
|
||||
|
||||
private float getMappedPosition(float divisor) => (float)Math.Pow((divisor - 1) / (availableDivisors.Last() - 1), 0.90f);
|
||||
|
@ -39,7 +39,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
public override bool CursorVisible => false;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty();
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack();
|
||||
|
||||
private Bindable<bool> menuVoice;
|
||||
private Bindable<bool> menuMusic;
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Graphics.ES30;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Batches;
|
||||
@ -150,7 +149,7 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
private class VisualiserSharedData
|
||||
{
|
||||
public readonly LinearBatch<TexturedVertex2D> VertexBatch = new LinearBatch<TexturedVertex2D>(100 * 4, 10, PrimitiveType.Quads);
|
||||
public readonly QuadBatch<TexturedVertex2D> VertexBatch = new QuadBatch<TexturedVertex2D>(100, 10);
|
||||
}
|
||||
|
||||
private class VisualisationDrawNode : DrawNode
|
||||
|
@ -58,6 +58,7 @@ namespace osu.Game.Screens.Menu
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = box_width * 2,
|
||||
Height = 1.5f,
|
||||
// align off-screen to make sure our edges don't become visible during parallax.
|
||||
X = -box_width,
|
||||
Alpha = 0,
|
||||
@ -70,6 +71,7 @@ namespace osu.Game.Screens.Menu
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = box_width * 2,
|
||||
Height = 1.5f,
|
||||
X = box_width,
|
||||
Alpha = 0,
|
||||
Blending = BlendingMode.Additive,
|
||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Screens.Multi
|
||||
/// <summary>
|
||||
/// All the active <see cref="Room"/>s.
|
||||
/// </summary>
|
||||
IBindableCollection<Room> Rooms { get; }
|
||||
IBindableList<Room> Rooms { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Room"/>.
|
||||
|
@ -93,10 +93,14 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
Host.BindValueChanged(v =>
|
||||
{
|
||||
hostText.Clear();
|
||||
hostText.AddText("hosted by ");
|
||||
hostText.AddLink(v.Username, null, LinkAction.OpenUserProfile, v.Id.ToString(), "Open profile", s => s.Font = "Exo2.0-BoldItalic");
|
||||
flagContainer.Clear();
|
||||
|
||||
flagContainer.Child = new DrawableFlag(v.Country) { RelativeSizeAxes = Axes.Both };
|
||||
if (v != null)
|
||||
{
|
||||
hostText.AddText("hosted by ");
|
||||
hostText.AddLink(v.Username, null, LinkAction.OpenUserProfile, v.Id.ToString(), "Open profile", s => s.Font = "Exo2.0-BoldItalic");
|
||||
flagContainer.Child = new DrawableFlag(v.Country) { RelativeSizeAxes = Axes.Both };
|
||||
}
|
||||
});
|
||||
|
||||
ParticipantCount.BindValueChanged(v => summary.Text = $"{v:#,0}{" participant".Pluralize(v == 1)}");
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Linq;
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
@ -13,8 +13,9 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.Multiplayer;
|
||||
using osu.Game.Screens.Multi.Components;
|
||||
using osu.Game.Users;
|
||||
@ -37,11 +38,10 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
private Box statusStrip;
|
||||
private UpdateableBeatmapBackgroundSprite background;
|
||||
private ParticipantCountDisplay participantCount;
|
||||
private FillFlowContainer topFlow, participantsFlow;
|
||||
private OsuSpriteText name, status;
|
||||
private BeatmapTypeInfo beatmapTypeInfo;
|
||||
private ScrollContainer participantsScroll;
|
||||
private ParticipantInfo participantInfo;
|
||||
private MatchParticipants participants;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmaps { get; set; }
|
||||
@ -58,141 +58,141 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"343138"),
|
||||
},
|
||||
topFlow = new FillFlowContainer
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Container
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Distributed),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 200,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
new FillFlowContainer
|
||||
{
|
||||
background = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both },
|
||||
new Box
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.5f), Color4.Black.Opacity(0)),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(20),
|
||||
Children = new Drawable[]
|
||||
new Container
|
||||
{
|
||||
participantCount = new ParticipantCountDisplay
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 200,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
background = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both },
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.5f), Color4.Black.Opacity(0)),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(20),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
participantCount = new ParticipantCountDisplay
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
},
|
||||
name = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
TextSize = 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
name = new OsuSpriteText
|
||||
},
|
||||
statusStrip = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 5,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
TextSize = 30,
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"28242d"),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
LayoutDuration = transition_duration,
|
||||
Padding = contentPadding,
|
||||
Spacing = new Vector2(0f, 5f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
status = new OsuSpriteText
|
||||
{
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
beatmapTypeInfo = new BeatmapTypeInfo(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = contentPadding,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
participantInfo = new ParticipantInfo(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
statusStrip = new Box
|
||||
new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 5,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
participants = new MatchParticipants
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"28242d"),
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
LayoutDuration = transition_duration,
|
||||
Padding = contentPadding,
|
||||
Spacing = new Vector2(0f, 5f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
status = new OsuSpriteText
|
||||
{
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
beatmapTypeInfo = new BeatmapTypeInfo(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = contentPadding,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
participantInfo = new ParticipantInfo(),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
participantsScroll = new OsuScrollContainer
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Padding = new MarginPadding { Top = contentPadding.Top, Left = 38, Right = 37 },
|
||||
Children = new[]
|
||||
{
|
||||
participantsFlow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
LayoutDuration = transition_duration,
|
||||
Spacing = new Vector2(5f),
|
||||
},
|
||||
},
|
||||
},
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
participantInfo.Host.BindTo(bindings.Host);
|
||||
participantInfo.ParticipantCount.BindTo(bindings.ParticipantCount);
|
||||
participantInfo.Participants.BindTo(bindings.Participants);
|
||||
|
||||
participantCount.Participants.BindTo(bindings.Participants);
|
||||
participantCount.ParticipantCount.BindTo(bindings.ParticipantCount);
|
||||
participantCount.MaxParticipants.BindTo(bindings.MaxParticipants);
|
||||
|
||||
beatmapTypeInfo.Beatmap.BindTo(bindings.CurrentBeatmap);
|
||||
beatmapTypeInfo.Ruleset.BindTo(bindings.CurrentRuleset);
|
||||
beatmapTypeInfo.Type.BindTo(bindings.Type);
|
||||
background.Beatmap.BindTo(bindings.CurrentBeatmap);
|
||||
|
||||
bindings.Status.BindValueChanged(displayStatus);
|
||||
bindings.Participants.BindValueChanged(p => participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)));
|
||||
bindings.Name.BindValueChanged(n => name.Text = n);
|
||||
|
||||
Room.BindValueChanged(updateRoom, true);
|
||||
}
|
||||
|
||||
private void updateRoom(Room room)
|
||||
{
|
||||
bindings.Room = room;
|
||||
participants.Room = room;
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
participantsFlow.FadeIn(transition_duration);
|
||||
participantCount.FadeIn(transition_duration);
|
||||
beatmapTypeInfo.FadeIn(transition_duration);
|
||||
name.FadeIn(transition_duration);
|
||||
@ -200,7 +200,6 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
participantsFlow.FadeOut(transition_duration);
|
||||
participantCount.FadeOut(transition_duration);
|
||||
beatmapTypeInfo.FadeOut(transition_duration);
|
||||
name.FadeOut(transition_duration);
|
||||
@ -210,13 +209,6 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
}
|
||||
}
|
||||
|
||||
protected override void UpdateAfterChildren()
|
||||
{
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
participantsScroll.Height = DrawHeight - topFlow.DrawHeight;
|
||||
}
|
||||
|
||||
private void displayStatus(RoomStatus s)
|
||||
{
|
||||
status.Text = s.Message;
|
||||
@ -226,39 +218,119 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
status.FadeColour(c, transition_duration);
|
||||
}
|
||||
|
||||
private class UserTile : Container, IHasTooltip
|
||||
{
|
||||
private readonly User user;
|
||||
|
||||
public string TooltipText => user.Username;
|
||||
|
||||
public UserTile(User user)
|
||||
{
|
||||
this.user = user;
|
||||
Size = new Vector2(70f);
|
||||
CornerRadius = 5f;
|
||||
Masking = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"27252d"),
|
||||
},
|
||||
new UpdateableAvatar
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
User = user,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class RoomStatusNoneSelected : RoomStatus
|
||||
{
|
||||
public override string Message => @"No Room Selected";
|
||||
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray8;
|
||||
}
|
||||
|
||||
private class MatchParticipants : CompositeDrawable
|
||||
{
|
||||
private Room room;
|
||||
private readonly FillFlowContainer fill;
|
||||
|
||||
public Room Room
|
||||
{
|
||||
get { return room; }
|
||||
set
|
||||
{
|
||||
if (room == value)
|
||||
return;
|
||||
|
||||
room = value;
|
||||
updateParticipants();
|
||||
}
|
||||
}
|
||||
|
||||
public MatchParticipants()
|
||||
{
|
||||
Padding = new MarginPadding { Horizontal = 10 };
|
||||
|
||||
InternalChild = new ScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = fill = new FillFlowContainer
|
||||
{
|
||||
Spacing = new Vector2(10),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Full,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private APIAccess api { get; set; }
|
||||
|
||||
private GetRoomScoresRequest request;
|
||||
|
||||
private void updateParticipants()
|
||||
{
|
||||
var roomId = room?.RoomID.Value ?? 0;
|
||||
|
||||
request?.Cancel();
|
||||
|
||||
// nice little progressive fade
|
||||
int time = 500;
|
||||
foreach (var c in fill.Children)
|
||||
{
|
||||
c.Delay(500 - time).FadeOut(time, Easing.Out);
|
||||
time = Math.Max(20, time - 20);
|
||||
c.Expire();
|
||||
}
|
||||
|
||||
if (roomId == 0) return;
|
||||
|
||||
request = new GetRoomScoresRequest(roomId);
|
||||
request.Success += scores =>
|
||||
{
|
||||
if (roomId != room.RoomID.Value)
|
||||
return;
|
||||
|
||||
fill.Clear();
|
||||
foreach (var s in scores)
|
||||
fill.Add(new UserTile(s.User));
|
||||
|
||||
fill.FadeInFromZero(1000, Easing.OutQuint);
|
||||
};
|
||||
|
||||
api.Queue(request);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
request?.Cancel();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private class UserTile : CompositeDrawable, IHasTooltip
|
||||
{
|
||||
private readonly User user;
|
||||
|
||||
public string TooltipText => user.Username;
|
||||
|
||||
public UserTile(User user)
|
||||
{
|
||||
this.user = user;
|
||||
Size = new Vector2(70f);
|
||||
CornerRadius = 5f;
|
||||
Masking = true;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"27252d"),
|
||||
},
|
||||
new UpdateableAvatar
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
User = user,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
|
||||
private readonly Bindable<Room> selectedRoom = new Bindable<Room>();
|
||||
public IBindable<Room> SelectedRoom => selectedRoom;
|
||||
|
||||
private readonly IBindableCollection<Room> rooms = new BindableCollection<Room>();
|
||||
private readonly IBindableList<Room> rooms = new BindableList<Room>();
|
||||
|
||||
private readonly FillFlowContainer<DrawableRoom> roomFlow;
|
||||
public IReadOnlyList<DrawableRoom> Rooms => roomFlow;
|
||||
|
@ -16,17 +16,18 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
{
|
||||
public Action<IEnumerable<APIRoomScoreInfo>> ScoresLoaded;
|
||||
|
||||
private readonly Room room;
|
||||
|
||||
public MatchLeaderboard(Room room)
|
||||
public Room Room
|
||||
{
|
||||
this.room = room;
|
||||
get => bindings.Room;
|
||||
set => bindings.Room = value;
|
||||
}
|
||||
|
||||
private readonly RoomBindings bindings = new RoomBindings();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
room.RoomID.BindValueChanged(id =>
|
||||
bindings.RoomID.BindValueChanged(id =>
|
||||
{
|
||||
if (id == null)
|
||||
return;
|
||||
@ -38,10 +39,10 @@ namespace osu.Game.Screens.Multi.Match.Components
|
||||
|
||||
protected override APIRequest FetchScores(Action<IEnumerable<APIRoomScoreInfo>> scoresCallback)
|
||||
{
|
||||
if (room.RoomID == null)
|
||||
if (bindings.RoomID.Value == null)
|
||||
return null;
|
||||
|
||||
var req = new GetRoomScoresRequest(room.RoomID.Value ?? 0);
|
||||
var req = new GetRoomScoresRequest(bindings.RoomID.Value ?? 0);
|
||||
|
||||
req.Success += r =>
|
||||
{
|
||||
|
@ -51,6 +51,8 @@ namespace osu.Game.Screens.Multi.Match
|
||||
|
||||
MatchChatDisplay chat;
|
||||
Components.Header header;
|
||||
Info info;
|
||||
GridContainer bottomRow;
|
||||
MatchSettingsOverlay settings;
|
||||
|
||||
Children = new Drawable[]
|
||||
@ -61,20 +63,21 @@ namespace osu.Game.Screens.Multi.Match
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[] { header = new Components.Header(room) { Depth = -1 } },
|
||||
new Drawable[] { new Info(room) { OnStart = onStart } },
|
||||
new Drawable[] { info = new Info(room) { OnStart = onStart } },
|
||||
new Drawable[]
|
||||
{
|
||||
new GridContainer
|
||||
bottomRow = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
leaderboard = new MatchLeaderboard(room)
|
||||
leaderboard = new MatchLeaderboard
|
||||
{
|
||||
Padding = new MarginPadding(10),
|
||||
RelativeSizeAxes = Axes.Both
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Room = room
|
||||
},
|
||||
new Container
|
||||
{
|
||||
@ -108,10 +111,19 @@ namespace osu.Game.Screens.Multi.Match
|
||||
header.OnRequestSelectBeatmap = () => Push(new MatchSongSelect { Selected = addPlaylistItem });
|
||||
header.Tabs.Current.ValueChanged += t =>
|
||||
{
|
||||
const float fade_duration = 500;
|
||||
if (t is SettingsMatchPage)
|
||||
{
|
||||
settings.Show();
|
||||
info.FadeOut(fade_duration, Easing.OutQuint);
|
||||
bottomRow.FadeOut(fade_duration, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.Hide();
|
||||
info.FadeIn(fade_duration, Easing.OutQuint);
|
||||
bottomRow.FadeIn(fade_duration, Easing.OutQuint);
|
||||
}
|
||||
};
|
||||
|
||||
chat.Exit += Exit;
|
||||
|
@ -103,8 +103,8 @@ namespace osu.Game.Screens.Multi.Ranking.Pages
|
||||
public class ResultsMatchLeaderboard : MatchLeaderboard
|
||||
{
|
||||
public ResultsMatchLeaderboard(Room room)
|
||||
: base(room)
|
||||
{
|
||||
Room = room;
|
||||
}
|
||||
|
||||
protected override bool FadeTop => true;
|
||||
|
@ -39,6 +39,7 @@ namespace osu.Game.Screens.Multi
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
RoomID.UnbindFrom(room.RoomID);
|
||||
Name.UnbindFrom(room.Name);
|
||||
Host.UnbindFrom(room.Host);
|
||||
Status.UnbindFrom(room.Status);
|
||||
@ -52,22 +53,20 @@ namespace osu.Game.Screens.Multi
|
||||
Duration.UnbindFrom(room.Duration);
|
||||
}
|
||||
|
||||
room = value;
|
||||
room = value ?? new Room();
|
||||
|
||||
if (room != null)
|
||||
{
|
||||
Name.BindTo(room.Name);
|
||||
Host.BindTo(room.Host);
|
||||
Status.BindTo(room.Status);
|
||||
Type.BindTo(room.Type);
|
||||
Playlist.BindTo(room.Playlist);
|
||||
Participants.BindTo(room.Participants);
|
||||
ParticipantCount.BindTo(room.ParticipantCount);
|
||||
MaxParticipants.BindTo(room.MaxParticipants);
|
||||
EndDate.BindTo(room.EndDate);
|
||||
Availability.BindTo(room.Availability);
|
||||
Duration.BindTo(room.Duration);
|
||||
}
|
||||
RoomID.BindTo(room.RoomID);
|
||||
Name.BindTo(room.Name);
|
||||
Host.BindTo(room.Host);
|
||||
Status.BindTo(room.Status);
|
||||
Type.BindTo(room.Type);
|
||||
Playlist.BindTo(room.Playlist);
|
||||
Participants.BindTo(room.Participants);
|
||||
ParticipantCount.BindTo(room.ParticipantCount);
|
||||
MaxParticipants.BindTo(room.MaxParticipants);
|
||||
EndDate.BindTo(room.EndDate);
|
||||
Availability.BindTo(room.Availability);
|
||||
Duration.BindTo(room.Duration);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,11 +81,12 @@ namespace osu.Game.Screens.Multi
|
||||
currentRuleset.Value = playlistItem?.Ruleset;
|
||||
}
|
||||
|
||||
public readonly Bindable<int?> RoomID = new Bindable<int?>();
|
||||
public readonly Bindable<string> Name = new Bindable<string>();
|
||||
public readonly Bindable<User> Host = new Bindable<User>();
|
||||
public readonly Bindable<RoomStatus> Status = new Bindable<RoomStatus>();
|
||||
public readonly Bindable<GameType> Type = new Bindable<GameType>();
|
||||
public readonly BindableCollection<PlaylistItem> Playlist = new BindableCollection<PlaylistItem>();
|
||||
public readonly BindableList<PlaylistItem> Playlist = new BindableList<PlaylistItem>();
|
||||
public readonly Bindable<IEnumerable<User>> Participants = new Bindable<IEnumerable<User>>();
|
||||
public readonly Bindable<int> ParticipantCount = new Bindable<int>();
|
||||
public readonly Bindable<int?> MaxParticipants = new Bindable<int?>();
|
||||
|
@ -21,8 +21,8 @@ namespace osu.Game.Screens.Multi
|
||||
{
|
||||
public event Action RoomsUpdated;
|
||||
|
||||
private readonly BindableCollection<Room> rooms = new BindableCollection<Room>();
|
||||
public IBindableCollection<Room> Rooms => rooms;
|
||||
private readonly BindableList<Room> rooms = new BindableList<Room>();
|
||||
public IBindableList<Room> Rooms => rooms;
|
||||
|
||||
private Room currentRoom;
|
||||
|
||||
|
@ -24,8 +24,6 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
private const int duration = 100;
|
||||
|
||||
private readonly Container content;
|
||||
|
||||
public readonly KeyCounterCollection KeyCounter;
|
||||
public readonly RollingCounter<int> ComboCounter;
|
||||
public readonly ScoreCounter ScoreCounter;
|
||||
@ -37,6 +35,7 @@ namespace osu.Game.Screens.Play
|
||||
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
|
||||
|
||||
private Bindable<bool> showHud;
|
||||
private readonly Container visibilityContainer;
|
||||
private readonly BindableBool replayLoaded = new BindableBool();
|
||||
|
||||
private static bool hasShownNotificationOnce;
|
||||
@ -45,34 +44,35 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Add(content = new Container
|
||||
Children = new Drawable[]
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
AlwaysPresent = true, // The hud may be hidden but certain elements may need to still be updated
|
||||
Children = new Drawable[]
|
||||
visibilityContainer = new Container {
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
AlwaysPresent = true, // The hud may be hidden but certain elements may need to still be updated
|
||||
Children = new Drawable[] {
|
||||
ComboCounter = CreateComboCounter(),
|
||||
ScoreCounter = CreateScoreCounter(),
|
||||
AccuracyCounter = CreateAccuracyCounter(),
|
||||
HealthDisplay = CreateHealthDisplay(),
|
||||
Progress = CreateProgress(),
|
||||
ModDisplay = CreateModsContainer(),
|
||||
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
|
||||
}
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
ComboCounter = CreateComboCounter(),
|
||||
ScoreCounter = CreateScoreCounter(),
|
||||
AccuracyCounter = CreateAccuracyCounter(),
|
||||
HealthDisplay = CreateHealthDisplay(),
|
||||
Progress = CreateProgress(),
|
||||
ModDisplay = CreateModsContainer(),
|
||||
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
|
||||
new FillFlowContainer
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock),
|
||||
HoldToQuit = CreateHoldForMenuButton(),
|
||||
}
|
||||
KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock),
|
||||
HoldToQuit = CreateHoldForMenuButton(),
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
BindProcessor(scoreProcessor);
|
||||
BindRulesetContainer(rulesetContainer);
|
||||
@ -91,7 +91,7 @@ namespace osu.Game.Screens.Play
|
||||
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
||||
{
|
||||
showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
|
||||
showHud.ValueChanged += hudVisibility => content.FadeTo(hudVisibility ? 1 : 0, duration);
|
||||
showHud.ValueChanged += hudVisibility => visibilityContainer.FadeTo(hudVisibility ? 1 : 0, duration);
|
||||
showHud.TriggerChange();
|
||||
|
||||
if (!showHud && !hasShownNotificationOnce)
|
||||
|
@ -20,6 +20,7 @@ using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Overlays;
|
||||
@ -179,10 +180,13 @@ namespace osu.Game.Screens.Play
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
},
|
||||
new LocalSkinOverrideContainer(working.Skin)
|
||||
new ScalingContainer(ScalingMode.Gameplay)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = RulesetContainer
|
||||
Child = new LocalSkinOverrideContainer(working.Skin)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = RulesetContainer
|
||||
}
|
||||
},
|
||||
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
|
||||
{
|
||||
@ -191,7 +195,10 @@ namespace osu.Game.Screens.Play
|
||||
ProcessCustomClock = false,
|
||||
Breaks = beatmap.Breaks
|
||||
},
|
||||
RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
|
||||
new ScalingContainer(ScalingMode.Gameplay)
|
||||
{
|
||||
Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
|
||||
},
|
||||
hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
|
||||
{
|
||||
Clock = Clock, // hud overlay doesn't want to use the audio clock directly
|
||||
|
@ -46,10 +46,10 @@ namespace osu.Game.Screens.Play
|
||||
State = Visibility.Visible;
|
||||
|
||||
RelativePositionAxes = Axes.Both;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Position = new Vector2(0.5f, 0.7f);
|
||||
Size = new Vector2(1, 0.14f);
|
||||
Size = new Vector2(1, 100);
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
}
|
||||
|
@ -112,6 +112,6 @@ namespace osu.Game.Screens.Play
|
||||
handleBase.X = xFill;
|
||||
}
|
||||
|
||||
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||
protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,6 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private readonly Container<DrawableCarouselItem> scrollableContent;
|
||||
|
||||
|
||||
public Bindable<bool> RightClickScrollingEnabled = new Bindable<bool>();
|
||||
|
||||
public Bindable<RandomSelectAlgorithm> RandomAlgorithm = new Bindable<RandomSelectAlgorithm>();
|
||||
|
@ -297,14 +297,14 @@ namespace osu.Game.Screens.Select
|
||||
/// <param name="performStartAction">Whether to trigger <see cref="OnStart"/>.</param>
|
||||
public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true)
|
||||
{
|
||||
// avoid attempting to continue before a selection has been obtained.
|
||||
// this could happen via a user interaction while the carousel is still in a loading state.
|
||||
if (Carousel.SelectedBeatmap == null) return;
|
||||
|
||||
// if we have a pending filter operation, we want to run it now.
|
||||
// it could change selection (ie. if the ruleset has been changed).
|
||||
Carousel.FlushPendingFilterOperations();
|
||||
|
||||
// avoid attempting to continue before a selection has been obtained.
|
||||
// this could happen via a user interaction while the carousel is still in a loading state.
|
||||
if (Carousel.SelectedBeatmap == null) return;
|
||||
|
||||
if (beatmap != null)
|
||||
Carousel.SelectBeatmap(beatmap);
|
||||
|
||||
|
@ -21,8 +21,6 @@ namespace osu.Game.Skinning
|
||||
|
||||
SampleChannel GetSample(string sampleName);
|
||||
|
||||
TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class;
|
||||
|
||||
TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct;
|
||||
TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ namespace osu.Game.Skinning
|
||||
case @"Author":
|
||||
skin.SkinInfo.Creator = pair.Value;
|
||||
break;
|
||||
case @"CursorExpand":
|
||||
skin.CursorExpand = pair.Value != "0";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -43,22 +43,14 @@ namespace osu.Game.Skinning
|
||||
return fallbackSource?.GetSample(sampleName);
|
||||
}
|
||||
|
||||
public TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration
|
||||
{
|
||||
TValue? val = null;
|
||||
TValue val;
|
||||
if ((source as Skin)?.Configuration is TConfiguration conf)
|
||||
val = query?.Invoke(conf);
|
||||
if (beatmapSkins && (val = query.Invoke(conf)) != null)
|
||||
return val;
|
||||
|
||||
return val ?? fallbackSource?.GetValue(query);
|
||||
}
|
||||
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class
|
||||
{
|
||||
TValue val = null;
|
||||
if ((source as Skin)?.Configuration is TConfiguration conf)
|
||||
val = query?.Invoke(conf);
|
||||
|
||||
return val ?? fallbackSource?.GetValue(query);
|
||||
return fallbackSource == null ? default : fallbackSource.GetValue(query);
|
||||
}
|
||||
|
||||
private readonly ISkinSource source;
|
||||
|
@ -22,11 +22,8 @@ namespace osu.Game.Skinning
|
||||
|
||||
public abstract Texture GetTexture(string componentName);
|
||||
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class
|
||||
=> Configuration is TConfiguration conf ? query?.Invoke(conf) : null;
|
||||
|
||||
public TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct
|
||||
=> Configuration is TConfiguration conf ? query?.Invoke(conf) : null;
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration
|
||||
=> Configuration is TConfiguration conf ? query.Invoke(conf) : default;
|
||||
|
||||
protected Skin(SkinInfo skin)
|
||||
{
|
||||
|
@ -16,5 +16,7 @@ namespace osu.Game.Skinning
|
||||
public Dictionary<string, Color4> CustomColours { get; set; } = new Dictionary<string, Color4>();
|
||||
|
||||
public string HitCircleFont { get; set; } = "default";
|
||||
|
||||
public bool? CursorExpand { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
@ -116,8 +116,6 @@ namespace osu.Game.Skinning
|
||||
|
||||
public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName);
|
||||
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration where TValue : class => CurrentSkin.Value.GetValue(query);
|
||||
|
||||
public TValue? GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue?> query) where TConfiguration : SkinConfiguration where TValue : struct => CurrentSkin.Value.GetValue(query);
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => CurrentSkin.Value.GetValue(query);
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,5 @@ namespace osu.Game.Users
|
||||
[JsonProperty(@"country")]
|
||||
public int? Country;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="Humanizer" Version="2.5.16" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2018.1226.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2019.117.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user