Merge branch 'master' into correct-reverse-arrow-depth
163
.github/workflows/test-diffcalc.yml
vendored
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
# Listens for new PR comments containing !pp check [id], and runs a diffcalc comparison against master.
|
||||||
|
# Usage:
|
||||||
|
# !pp check 0 | Runs only the osu! ruleset.
|
||||||
|
# !pp check 0 2 | Runs only the osu! and catch rulesets.
|
||||||
|
#
|
||||||
|
|
||||||
|
name: Diffcalc Consistency Checks
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [ created ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
DB_USER: root
|
||||||
|
DB_HOST: 127.0.0.1
|
||||||
|
CONCURRENCY: 4
|
||||||
|
ALLOW_DOWNLOAD: 1
|
||||||
|
SAVE_DOWNLOADED: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
diffcalc:
|
||||||
|
name: Diffcalc
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
if: |
|
||||||
|
github.event.issue.pull_request &&
|
||||||
|
contains(github.event.comment.body, '!pp check') &&
|
||||||
|
(github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER')
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
ruleset:
|
||||||
|
- { name: osu, id: 0 }
|
||||||
|
- { name: taiko, id: 1 }
|
||||||
|
- { name: catch, id: 2 }
|
||||||
|
- { name: mania, id: 3 }
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
env:
|
||||||
|
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Verify ruleset
|
||||||
|
if: contains(github.event.comment.body, matrix.ruleset.id) == false
|
||||||
|
run: |
|
||||||
|
echo "${{ github.event.comment.body }} doesn't contain ${{ matrix.ruleset.id }}"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
- name: Verify MySQL connection from host
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y mysql-client
|
||||||
|
mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "SHOW DATABASES"
|
||||||
|
|
||||||
|
- name: Create directory structure
|
||||||
|
run: |
|
||||||
|
mkdir -p $GITHUB_WORKSPACE/master/
|
||||||
|
mkdir -p $GITHUB_WORKSPACE/pr/
|
||||||
|
|
||||||
|
# Checkout osu
|
||||||
|
- name: Checkout osu (master)
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ppy/osu
|
||||||
|
path: 'master/osu'
|
||||||
|
- name: Checkout osu (pr)
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: 'pr/osu'
|
||||||
|
|
||||||
|
# Checkout osu-difficulty-calculator
|
||||||
|
- name: Checkout osu-difficulty-calculator (master)
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ppy/osu-difficulty-calculator
|
||||||
|
path: 'master/osu-difficulty-calculator'
|
||||||
|
- name: Checkout osu-difficulty-calculator (pr)
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ppy/osu-difficulty-calculator
|
||||||
|
path: 'pr/osu-difficulty-calculator'
|
||||||
|
|
||||||
|
- name: Install .NET 5.0.x
|
||||||
|
uses: actions/setup-dotnet@v1
|
||||||
|
with:
|
||||||
|
dotnet-version: "5.0.x"
|
||||||
|
|
||||||
|
# Sanity checks to make sure diffcalc is not run when incompatible.
|
||||||
|
- name: Build diffcalc (master)
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/master/osu-difficulty-calculator
|
||||||
|
./UseLocalOsu.sh
|
||||||
|
dotnet build
|
||||||
|
- name: Build diffcalc (pr)
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/pr/osu-difficulty-calculator
|
||||||
|
./UseLocalOsu.sh
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
# Initial data imports
|
||||||
|
- name: Download + import data
|
||||||
|
run: |
|
||||||
|
PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_top | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g')
|
||||||
|
BEATMAPS_DATA_NAME=$(curl https://data.ppy.sh/ | grep osu_files | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g')
|
||||||
|
|
||||||
|
# Set env variable for further steps.
|
||||||
|
echo "BEATMAPS_PATH=$GITHUB_WORKSPACE/$BEATMAPS_DATA_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
cd $GITHUB_WORKSPACE
|
||||||
|
|
||||||
|
wget https://data.ppy.sh/$PERFORMANCE_DATA_NAME.tar.bz2
|
||||||
|
wget https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2
|
||||||
|
tar -xf $PERFORMANCE_DATA_NAME.tar.bz2
|
||||||
|
tar -xf $BEATMAPS_DATA_NAME.tar.bz2
|
||||||
|
|
||||||
|
cd $GITHUB_WORKSPACE/$PERFORMANCE_DATA_NAME
|
||||||
|
|
||||||
|
mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_master"
|
||||||
|
mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_pr"
|
||||||
|
|
||||||
|
cat *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_master
|
||||||
|
cat *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_pr
|
||||||
|
|
||||||
|
# Run diffcalc
|
||||||
|
- name: Run diffcalc (master)
|
||||||
|
env:
|
||||||
|
DB_NAME: osu_master
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/master/osu-difficulty-calculator/osu.Server.DifficultyCalculator
|
||||||
|
dotnet run -c:Release -- all -m ${{ matrix.ruleset.id }} -ac -c ${{ env.CONCURRENCY }}
|
||||||
|
- name: Run diffcalc (pr)
|
||||||
|
env:
|
||||||
|
DB_NAME: osu_pr
|
||||||
|
run: |
|
||||||
|
cd $GITHUB_WORKSPACE/pr/osu-difficulty-calculator/osu.Server.DifficultyCalculator
|
||||||
|
dotnet run -c:Release -- all -m ${{ matrix.ruleset.id }} -ac -c ${{ env.CONCURRENCY }}
|
||||||
|
|
||||||
|
# Print diffs
|
||||||
|
- name: Print diffs
|
||||||
|
run: |
|
||||||
|
mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "
|
||||||
|
SELECT
|
||||||
|
m.beatmap_id,
|
||||||
|
m.mods,
|
||||||
|
m.diff_unified as 'sr_master',
|
||||||
|
p.diff_unified as 'sr_pr',
|
||||||
|
(p.diff_unified - m.diff_unified) as 'diff'
|
||||||
|
FROM osu_master.osu_beatmap_difficulty m
|
||||||
|
JOIN osu_pr.osu_beatmap_difficulty p
|
||||||
|
ON m.beatmap_id = p.beatmap_id
|
||||||
|
AND m.mode = p.mode
|
||||||
|
AND m.mods = p.mods
|
||||||
|
WHERE abs(m.diff_unified - p.diff_unified) > 0.1
|
||||||
|
ORDER BY abs(m.diff_unified - p.diff_unified)
|
||||||
|
DESC
|
||||||
|
LIMIT 10000;"
|
||||||
|
|
||||||
|
# Todo: Run ppcalc
|
@ -1,8 +1,8 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Benchmarks" type="DotNetProject" factoryName=".NET Project">
|
<configuration default="false" name="Benchmarks" type="DotNetProject" factoryName=".NET Project">
|
||||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/net5.0/osu.Game.Benchmarks.dll" />
|
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Debug/net5.0/osu.Game.Benchmarks.dll" />
|
||||||
<option name="PROGRAM_PARAMETERS" value="--filter *" />
|
<option name="PROGRAM_PARAMETERS" value="" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/net5.0" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Debug/net5.0" />
|
||||||
<option name="PASS_PARENT_ENVS" value="1" />
|
<option name="PASS_PARENT_ENVS" value="1" />
|
||||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||||
<option name="USE_MONO" value="0" />
|
<option name="USE_MONO" value="0" />
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||||
<option name="PROJECT_TFM" value="net5.0" />
|
<option name="PROJECT_TFM" value="net5.0" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Build" enabled="true" />
|
<option name="Build" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ContentModelUserStore">
|
<component name="UserContentModel">
|
||||||
<attachedFolders />
|
<attachedFolders />
|
||||||
<explicitIncludes />
|
<explicitIncludes />
|
||||||
<explicitExcludes />
|
<explicitExcludes />
|
||||||
|
@ -31,12 +31,11 @@ If you are looking to install or test osu! without setting up a development envi
|
|||||||
|
|
||||||
**Latest build:**
|
**Latest build:**
|
||||||
|
|
||||||
| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||||
| ------------- | ------------- | ------------- | ------------- | ------------- |
|
| ------------- | ------------- | ------------- | ------------- | ------------- |
|
||||||
|
|
||||||
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
|
- The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets.
|
||||||
|
|
||||||
- When running on Windows 7 or 8.1, *[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/windows?tabs=net50&pivots=os-windows#dependencies)** may be required to correctly run .NET 5 applications if your operating system is not up-to-date with the latest service packs.
|
|
||||||
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
||||||
|
|
||||||
## Developing a custom ruleset
|
## Developing a custom ruleset
|
||||||
|
@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load(GameHost host, OsuGameBase gameBase)
|
||||||
{
|
{
|
||||||
OsuGame game = new OsuGame();
|
|
||||||
game.SetHost(host);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
game
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddGame(new OsuGame());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load(GameHost host, OsuGameBase gameBase)
|
||||||
{
|
{
|
||||||
OsuGame game = new OsuGame();
|
|
||||||
game.SetHost(host);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
game
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddGame(new OsuGame());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load(GameHost host, OsuGameBase gameBase)
|
||||||
{
|
{
|
||||||
OsuGame game = new OsuGame();
|
|
||||||
game.SetHost(host);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
game
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddGame(new OsuGame());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host, OsuGameBase gameBase)
|
private void load(GameHost host, OsuGameBase gameBase)
|
||||||
{
|
{
|
||||||
OsuGame game = new OsuGame();
|
|
||||||
game.SetHost(host);
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.Pippidon.Tests
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
game
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddGame(new OsuGame());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -61,9 +62,9 @@ namespace osu.Game.Rulesets.Pippidon.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(PippidonAction action)
|
public bool OnPressed(KeyBindingPressEvent<PippidonAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case PippidonAction.MoveUp:
|
case PippidonAction.MoveUp:
|
||||||
changeLane(-1);
|
changeLane(-1);
|
||||||
@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.Pippidon.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(PippidonAction action)
|
public void OnReleased(KeyBindingReleaseEvent<PippidonAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,11 +51,11 @@
|
|||||||
<Reference Include="Java.Interop" />
|
<Reference Include="Java.Interop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.827.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.918.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.830.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.916.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||||
<PackageReference Include="Realm" Version="10.3.0" />
|
<PackageReference Include="Realm" Version="10.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -14,9 +14,9 @@ namespace osu.Game.Benchmarks
|
|||||||
[Params(1, 10, 100)]
|
[Params(1, 10, 100)]
|
||||||
public int Times { get; set; }
|
public int Times { get; set; }
|
||||||
|
|
||||||
[GlobalSetup]
|
public override void SetUp()
|
||||||
public void GlobalSetup()
|
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
mod = new OsuModDoubleTime();
|
mod = new OsuModDoubleTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
62
osu.Game.Benchmarks/BenchmarkRuleset.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Engines;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
|
||||||
|
namespace osu.Game.Benchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkRuleset : BenchmarkTest
|
||||||
|
{
|
||||||
|
private OsuRuleset ruleset;
|
||||||
|
private APIMod apiModDoubleTime;
|
||||||
|
private APIMod apiModDifficultyAdjust;
|
||||||
|
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
ruleset = new OsuRuleset();
|
||||||
|
apiModDoubleTime = new APIMod { Acronym = "DT" };
|
||||||
|
apiModDifficultyAdjust = new APIMod { Acronym = "DA" };
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkToModDoubleTime()
|
||||||
|
{
|
||||||
|
apiModDoubleTime.ToMod(ruleset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkToModDifficultyAdjust()
|
||||||
|
{
|
||||||
|
apiModDifficultyAdjust.ToMod(ruleset);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetAllMods()
|
||||||
|
{
|
||||||
|
ruleset.CreateAllMods().Consume(new Consumer());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetAllModsForReference()
|
||||||
|
{
|
||||||
|
ruleset.AllMods.Consume(new Consumer());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetForAcronym()
|
||||||
|
{
|
||||||
|
ruleset.CreateModFromAcronym("DT");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void BenchmarkGetForType()
|
||||||
|
{
|
||||||
|
ruleset.CreateMod<ModDoubleTime>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using BenchmarkDotNet.Configs;
|
||||||
using BenchmarkDotNet.Running;
|
using BenchmarkDotNet.Running;
|
||||||
|
|
||||||
namespace osu.Game.Benchmarks
|
namespace osu.Game.Benchmarks
|
||||||
@ -11,7 +12,7 @@ namespace osu.Game.Benchmarks
|
|||||||
{
|
{
|
||||||
BenchmarkSwitcher
|
BenchmarkSwitcher
|
||||||
.FromAssembly(typeof(Program).Assembly)
|
.FromAssembly(typeof(Program).Assembly)
|
||||||
.Run(args);
|
.Run(args, DefaultConfig.Instance.WithOption(ConfigOptions.DisableOptimizationsValidator, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.0" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
|
||||||
<PackageReference Include="nunit" Version="3.13.2" />
|
<PackageReference Include="nunit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -44,9 +44,9 @@ namespace osu.Game.Rulesets.Catch.Mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
// disable keyboard controls
|
// disable keyboard controls
|
||||||
public bool OnPressed(CatchAction action) => true;
|
public bool OnPressed(KeyBindingPressEvent<CatchAction> e) => true;
|
||||||
|
|
||||||
public void OnReleased(CatchAction action)
|
public void OnReleased(KeyBindingReleaseEvent<CatchAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Catch.Judgements;
|
using osu.Game.Rulesets.Catch.Judgements;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
@ -144,9 +145,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Catcher.VisualDirection = Direction.Left;
|
Catcher.VisualDirection = Direction.Left;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(CatchAction action)
|
public bool OnPressed(KeyBindingPressEvent<CatchAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case CatchAction.MoveLeft:
|
case CatchAction.MoveLeft:
|
||||||
currentDirection--;
|
currentDirection--;
|
||||||
@ -164,9 +165,9 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(CatchAction action)
|
public void OnReleased(KeyBindingReleaseEvent<CatchAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case CatchAction.MoveLeft:
|
case CatchAction.MoveLeft:
|
||||||
currentDirection++;
|
currentDirection++;
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 3.9 KiB |
@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
c.Add(CreateHitObject().With(h =>
|
c.Add(CreateHitObject().With(h =>
|
||||||
{
|
{
|
||||||
h.HitObject.StartTime = START_TIME;
|
h.HitObject.StartTime = Time.Current + 5000;
|
||||||
h.AccentColour.Value = Color4.Orange;
|
h.AccentColour.Value = Color4.Orange;
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
{
|
{
|
||||||
c.Add(CreateHitObject().With(h =>
|
c.Add(CreateHitObject().With(h =>
|
||||||
{
|
{
|
||||||
h.HitObject.StartTime = START_TIME;
|
h.HitObject.StartTime = Time.Current + 5000;
|
||||||
h.AccentColour.Value = Color4.Orange;
|
h.AccentColour.Value = Color4.Orange;
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
|
@ -19,8 +19,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ManiaSkinnableTestScene : SkinnableTestScene
|
public abstract class ManiaSkinnableTestScene : SkinnableTestScene
|
||||||
{
|
{
|
||||||
protected const double START_TIME = 1000000000;
|
|
||||||
|
|
||||||
[Cached(Type = typeof(IScrollingInfo))]
|
[Cached(Type = typeof(IScrollingInfo))]
|
||||||
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
|
private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo();
|
||||||
|
|
||||||
@ -55,27 +53,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning
|
|||||||
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
public readonly Bindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
IBindable<ScrollingDirection> IScrollingInfo.Direction => Direction;
|
||||||
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(1000);
|
IBindable<double> IScrollingInfo.TimeRange { get; } = new Bindable<double>(5000);
|
||||||
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ZeroScrollAlgorithm();
|
IScrollAlgorithm IScrollingInfo.Algorithm { get; } = new ConstantScrollAlgorithm();
|
||||||
}
|
|
||||||
|
|
||||||
private class ZeroScrollAlgorithm : IScrollAlgorithm
|
|
||||||
{
|
|
||||||
public double GetDisplayStartTime(double originTime, float offset, double timeRange, float scrollLength)
|
|
||||||
=> double.MinValue;
|
|
||||||
|
|
||||||
public float GetLength(double startTime, double endTime, double timeRange, float scrollLength)
|
|
||||||
=> scrollLength;
|
|
||||||
|
|
||||||
public float PositionAt(double time, double currentTime, double timeRange, float scrollLength)
|
|
||||||
=> (float)((time - START_TIME) / timeRange) * scrollLength;
|
|
||||||
|
|
||||||
public double TimeAt(float position, double currentTime, double timeRange, float scrollLength)
|
|
||||||
=> 0;
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
@ -58,7 +59,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
AddStep("Hold key", () =>
|
AddStep("Hold key", () =>
|
||||||
{
|
{
|
||||||
clock.CurrentTime = 0;
|
clock.CurrentTime = 0;
|
||||||
note.OnPressed(ManiaAction.Key1);
|
note.OnPressed(new KeyBindingPressEvent<ManiaAction>(GetContainingInputManager().CurrentState, ManiaAction.Key1));
|
||||||
});
|
});
|
||||||
AddStep("progress time", () => clock.CurrentTime = 500);
|
AddStep("progress time", () => clock.CurrentTime = 500);
|
||||||
AddAssert("head is visible", () => note.Head.Alpha == 1);
|
AddAssert("head is visible", () => note.Head.Alpha == 1);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -13,6 +14,10 @@ using osu.Game.Rulesets.Mania.Objects;
|
|||||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Tests
|
namespace osu.Game.Rulesets.Mania.Tests
|
||||||
{
|
{
|
||||||
@ -22,14 +27,65 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private RulesetConfigCache configCache { get; set; }
|
private RulesetConfigCache configCache { get; set; }
|
||||||
|
|
||||||
private readonly Bindable<bool> configTimingBasedNoteColouring = new Bindable<bool>();
|
private Bindable<bool> configTimingBasedNoteColouring;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
private ManualClock clock;
|
||||||
|
private DrawableManiaRuleset drawableRuleset;
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("setup hierarchy", () => Child = new Container
|
||||||
|
{
|
||||||
|
Clock = new FramedClock(clock = new ManualClock()),
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
drawableRuleset = (DrawableManiaRuleset)Ruleset.Value.CreateInstance().CreateDrawableRulesetWith(createTestBeatmap())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
AddStep("retrieve config bindable", () =>
|
||||||
|
{
|
||||||
|
var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
||||||
|
configTimingBasedNoteColouring = config.GetBindable<bool>(ManiaRulesetSetting.TimingBasedNoteColouring);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSimple()
|
||||||
|
{
|
||||||
|
AddStep("enable", () => configTimingBasedNoteColouring.Value = true);
|
||||||
|
AddStep("disable", () => configTimingBasedNoteColouring.Value = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestToggleOffScreen()
|
||||||
|
{
|
||||||
|
AddStep("enable", () => configTimingBasedNoteColouring.Value = true);
|
||||||
|
|
||||||
|
seekTo(10000);
|
||||||
|
AddStep("disable", () => configTimingBasedNoteColouring.Value = false);
|
||||||
|
seekTo(0);
|
||||||
|
AddAssert("all notes not coloured", () => this.ChildrenOfType<DrawableNote>().All(note => note.Colour == Colour4.White));
|
||||||
|
|
||||||
|
seekTo(10000);
|
||||||
|
AddStep("enable again", () => configTimingBasedNoteColouring.Value = true);
|
||||||
|
seekTo(0);
|
||||||
|
AddAssert("some notes coloured", () => this.ChildrenOfType<DrawableNote>().Any(note => note.Colour != Colour4.White));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void seekTo(double time)
|
||||||
|
{
|
||||||
|
AddStep($"seek to {time}", () => clock.CurrentTime = time);
|
||||||
|
AddUntilStep("wait for seek", () => Precision.AlmostEquals(drawableRuleset.FrameStableClock.CurrentTime, time, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ManiaBeatmap createTestBeatmap()
|
||||||
{
|
{
|
||||||
const double beat_length = 500;
|
const double beat_length = 500;
|
||||||
|
|
||||||
var ruleset = new ManiaRuleset();
|
|
||||||
|
|
||||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 })
|
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 })
|
||||||
{
|
{
|
||||||
HitObjects =
|
HitObjects =
|
||||||
@ -45,7 +101,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
new Note { StartTime = beat_length }
|
new Note { StartTime = beat_length }
|
||||||
},
|
},
|
||||||
ControlPointInfo = new ControlPointInfo(),
|
ControlPointInfo = new ControlPointInfo(),
|
||||||
BeatmapInfo = { Ruleset = ruleset.RulesetInfo },
|
BeatmapInfo = { Ruleset = Ruleset.Value },
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var note in beatmap.HitObjects)
|
foreach (var note in beatmap.HitObjects)
|
||||||
@ -57,24 +113,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
{
|
{
|
||||||
BeatLength = beat_length
|
BeatLength = beat_length
|
||||||
});
|
});
|
||||||
|
return beatmap;
|
||||||
Child = new Container
|
|
||||||
{
|
|
||||||
Clock = new FramedClock(new ManualClock()),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
ruleset.CreateDrawableRulesetWith(beatmap)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance());
|
|
||||||
config.BindWith(ManiaRulesetSetting.TimingBasedNoteColouring, configTimingBasedNoteColouring);
|
|
||||||
|
|
||||||
AddStep("Enable", () => configTimingBasedNoteColouring.Value = true);
|
|
||||||
AddStep("Disable", () => configTimingBasedNoteColouring.Value = false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
46
osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Edit.Setup
|
||||||
|
{
|
||||||
|
public class ManiaSetupSection : RulesetSetupSection
|
||||||
|
{
|
||||||
|
private LabelledSwitchButton specialStyle;
|
||||||
|
|
||||||
|
public ManiaSetupSection()
|
||||||
|
: base(new ManiaRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
specialStyle = new LabelledSwitchButton
|
||||||
|
{
|
||||||
|
Label = "Use special (N+1) style",
|
||||||
|
Description = "Changes one column to act as a classic \"scratch\" or \"special\" column, which can be moved around by the user's skin (to the left/right/centre). Generally used in 5k (4+1) or 8key (7+1) configurations.",
|
||||||
|
Current = { Value = Beatmap.BeatmapInfo.SpecialStyle }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
specialStyle.Current.BindValueChanged(_ => updateBeatmap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBeatmap()
|
||||||
|
{
|
||||||
|
Beatmap.BeatmapInfo.SpecialStyle = specialStyle.Current.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,11 +27,13 @@ using osu.Game.Rulesets.Mania.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
using osu.Game.Rulesets.Mania.Difficulty;
|
using osu.Game.Rulesets.Mania.Difficulty;
|
||||||
using osu.Game.Rulesets.Mania.Edit;
|
using osu.Game.Rulesets.Mania.Edit;
|
||||||
|
using osu.Game.Rulesets.Mania.Edit.Setup;
|
||||||
using osu.Game.Rulesets.Mania.Scoring;
|
using osu.Game.Rulesets.Mania.Scoring;
|
||||||
using osu.Game.Rulesets.Mania.Skinning.Legacy;
|
using osu.Game.Rulesets.Mania.Skinning.Legacy;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania
|
namespace osu.Game.Rulesets.Mania
|
||||||
@ -390,6 +392,8 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
{
|
{
|
||||||
return new ManiaFilterCriteria();
|
return new ManiaFilterCriteria();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override RulesetSetupSection CreateEditorSetupSection() => new ManiaSetupSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PlayfieldType
|
public enum PlayfieldType
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Mania.Skinning.Default;
|
using osu.Game.Rulesets.Mania.Skinning.Default;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -253,12 +254,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
HoldBrokenTime = Time.Current;
|
HoldBrokenTime = Time.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (AllJudged)
|
if (AllJudged)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (action != Action.Value)
|
if (e.Action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
||||||
@ -288,12 +289,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
isHitting.Value = true;
|
isHitting.Value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (AllJudged)
|
if (AllJudged)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (action != Action.Value)
|
if (e.Action != Action.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
// do not run any of this logic when rewinding, as it inverts order of presses/releases.
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
@ -43,9 +44,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
// it will be hidden along with its parenting hold note when required.
|
// it will be hidden along with its parenting hold note when required.
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note
|
public override bool OnPressed(KeyBindingPressEvent<ManiaAction> e) => false; // Handled by the hold note
|
||||||
|
|
||||||
public override void OnReleased(ManiaAction action)
|
public override void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
@ -68,9 +69,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note
|
public override bool OnPressed(KeyBindingPressEvent<ManiaAction> e) => false; // Handled by the hold note
|
||||||
|
|
||||||
public override void OnReleased(ManiaAction action)
|
public override void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Mania.Configuration;
|
using osu.Game.Rulesets.Mania.Configuration;
|
||||||
@ -66,6 +67,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
StartTimeBindable.BindValueChanged(_ => updateSnapColour(), true);
|
StartTimeBindable.BindValueChanged(_ => updateSnapColour(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
base.OnApply();
|
||||||
|
updateSnapColour();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
protected override void OnDirectionChanged(ValueChangedEvent<ScrollingDirection> e)
|
||||||
{
|
{
|
||||||
base.OnDirectionChanged(e);
|
base.OnDirectionChanged(e);
|
||||||
@ -91,9 +98,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = result);
|
ApplyResult(r => r.Type = result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool OnPressed(ManiaAction action)
|
public virtual bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action != Action.Value)
|
if (e.Action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (CheckHittable?.Invoke(this, Time.Current) == false)
|
if (CheckHittable?.Invoke(this, Time.Current) == false)
|
||||||
@ -102,7 +109,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
return UpdateResult(true);
|
return UpdateResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnReleased(ManiaAction action)
|
public virtual void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -76,9 +77,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == Column.Action.Value)
|
if (e.Action == Column.Action.Value)
|
||||||
{
|
{
|
||||||
light.FadeIn();
|
light.FadeIn();
|
||||||
light.ScaleTo(Vector2.One);
|
light.ScaleTo(Vector2.One);
|
||||||
@ -87,12 +88,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
// Todo: Should be 400 * 100 / CurrentBPM
|
// Todo: Should be 400 * 100 / CurrentBPM
|
||||||
const double animation_length = 250;
|
const double animation_length = 250;
|
||||||
|
|
||||||
if (action == Column.Action.Value)
|
if (e.Action == Column.Action.Value)
|
||||||
{
|
{
|
||||||
light.FadeTo(0, animation_length);
|
light.FadeTo(0, animation_length);
|
||||||
light.ScaleTo(new Vector2(1, 0), animation_length);
|
light.ScaleTo(new Vector2(1, 0), animation_length);
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
public class LegacyHoldNoteHeadPiece : LegacyNotePiece
|
||||||
{
|
{
|
||||||
protected override Texture GetTexture(ISkinSource skin)
|
protected override Drawable GetAnimation(ISkinSource skin)
|
||||||
{
|
{
|
||||||
// TODO: Should fallback to the head from default legacy skin instead of note.
|
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||||
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -18,12 +18,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
: new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Up, ScrollingDirection.Up));
|
: new ValueChangedEvent<ScrollingDirection>(ScrollingDirection.Up, ScrollingDirection.Up));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Texture GetTexture(ISkinSource skin)
|
protected override Drawable GetAnimation(ISkinSource skin)
|
||||||
{
|
{
|
||||||
// TODO: Should fallback to the head from default legacy skin instead of note.
|
// TODO: Should fallback to the head from default legacy skin instead of note.
|
||||||
return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage)
|
return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage)
|
||||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage)
|
||||||
?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Mania.UI;
|
using osu.Game.Rulesets.Mania.UI;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -86,9 +87,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == column.Action.Value)
|
if (e.Action == column.Action.Value)
|
||||||
{
|
{
|
||||||
upSprite.FadeTo(0);
|
upSprite.FadeTo(0);
|
||||||
downSprite.FadeTo(1);
|
downSprite.FadeTo(1);
|
||||||
@ -97,9 +98,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == column.Action.Value)
|
if (e.Action == column.Action.Value)
|
||||||
{
|
{
|
||||||
upSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(1);
|
upSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(1);
|
||||||
downSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(0);
|
downSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(0);
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
@ -19,7 +21,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||||
|
|
||||||
private Container directionContainer;
|
private Container directionContainer;
|
||||||
private Sprite noteSprite;
|
|
||||||
|
[CanBeNull]
|
||||||
|
private Drawable noteAnimation;
|
||||||
|
|
||||||
private float? minimumColumnWidth;
|
private float? minimumColumnWidth;
|
||||||
|
|
||||||
@ -39,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Child = noteSprite = new Sprite { Texture = GetTexture(skin) }
|
Child = noteAnimation = GetAnimation(skin) ?? Empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
direction.BindTo(scrollingInfo.Direction);
|
direction.BindTo(scrollingInfo.Direction);
|
||||||
@ -50,12 +54,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (noteSprite.Texture != null)
|
Texture texture = null;
|
||||||
|
|
||||||
|
if (noteAnimation is Sprite sprite)
|
||||||
|
texture = sprite.Texture;
|
||||||
|
else if (noteAnimation is TextureAnimation textureAnimation && textureAnimation.FrameCount > 0)
|
||||||
|
texture = textureAnimation.CurrentFrame;
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
{
|
{
|
||||||
// The height is scaled to the minimum column width, if provided.
|
// The height is scaled to the minimum column width, if provided.
|
||||||
float minimumWidth = minimumColumnWidth ?? DrawWidth;
|
float minimumWidth = minimumColumnWidth ?? DrawWidth;
|
||||||
|
noteAnimation.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), texture.DisplayWidth);
|
||||||
noteSprite.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), noteSprite.Texture.DisplayWidth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,9 +83,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Texture GetTexture(ISkinSource skin) => GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
[CanBeNull]
|
||||||
|
protected virtual Drawable GetAnimation(ISkinSource skin) => GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage);
|
||||||
|
|
||||||
protected Texture GetTextureFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup)
|
[CanBeNull]
|
||||||
|
protected Drawable GetAnimationFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup)
|
||||||
{
|
{
|
||||||
string suffix = string.Empty;
|
string suffix = string.Empty;
|
||||||
|
|
||||||
@ -93,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
|||||||
string noteImage = GetColumnSkinConfig<string>(skin, lookup)?.Value
|
string noteImage = GetColumnSkinConfig<string>(skin, lookup)?.Value
|
||||||
?? $"mania-note{FallbackColumnIndex}{suffix}";
|
?? $"mania-note{FallbackColumnIndex}{suffix}";
|
||||||
|
|
||||||
return skin.GetTexture(noteImage, WrapMode.ClampToEdge, WrapMode.ClampToEdge);
|
return skin.GetAnimation(noteImage, WrapMode.ClampToEdge, WrapMode.ClampToEdge, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics.Pooling;
|
using osu.Framework.Graphics.Pooling;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mania.UI.Components;
|
using osu.Game.Rulesets.Mania.UI.Components;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
@ -122,16 +123,16 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result)));
|
HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action != Action.Value)
|
if (e.Action != Action.Value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sampleTriggerSource.Play();
|
sampleTriggerSource.Play();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics.Colour;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -91,16 +92,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
direction.Value == ScrollingDirection.Up ? dimPoint : brightPoint);
|
direction.Value == ScrollingDirection.Up ? dimPoint : brightPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == this.action.Value)
|
if (e.Action == action.Value)
|
||||||
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == this.action.Value)
|
if (e.Action == action.Value)
|
||||||
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics.Colour;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -74,16 +75,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == column.Action.Value)
|
if (e.Action == column.Action.Value)
|
||||||
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == column.Action.Value)
|
if (e.Action == column.Action.Value)
|
||||||
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -101,16 +102,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(ManiaAction action)
|
public bool OnPressed(KeyBindingPressEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == column.Action.Value)
|
if (e.Action == column.Action.Value)
|
||||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(ManiaAction action)
|
public void OnReleased(KeyBindingReleaseEvent<ManiaAction> e)
|
||||||
{
|
{
|
||||||
if (action == column.Action.Value)
|
if (e.Action == column.Action.Value)
|
||||||
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,12 +37,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public override void PlayAnimation()
|
public override void PlayAnimation()
|
||||||
{
|
{
|
||||||
base.PlayAnimation();
|
|
||||||
|
|
||||||
switch (Result)
|
switch (Result)
|
||||||
{
|
{
|
||||||
case HitResult.None:
|
case HitResult.None:
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
|
base.PlayAnimation();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -52,6 +51,8 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
this.Delay(50)
|
this.Delay(50)
|
||||||
.ScaleTo(0.75f, 250)
|
.ScaleTo(0.75f, 250)
|
||||||
.FadeOut(200);
|
.FadeOut(200);
|
||||||
|
|
||||||
|
// osu!mania uses a custom fade length, so the base call is intentionally omitted.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||||
|
|
||||||
[TestCase(6.7568168283591499d, "diffcalc-test")]
|
[TestCase(6.6634445062299665d, "diffcalc-test")]
|
||||||
[TestCase(1.0348244046058293d, "zero-length-sliders")]
|
[TestCase(1.0414203870195022d, "zero-length-sliders")]
|
||||||
public void Test(double expected, string name)
|
public void Test(double expected, string name)
|
||||||
=> base.Test(expected, name);
|
=> base.Test(expected, name);
|
||||||
|
|
||||||
[TestCase(8.4783236764532557d, "diffcalc-test")]
|
[TestCase(8.3858089051603368d, "diffcalc-test")]
|
||||||
[TestCase(1.2708532136987165d, "zero-length-sliders")]
|
[TestCase(1.2723279173428435d, "zero-length-sliders")]
|
||||||
public void TestClockRateAdjusted(double expected, string name)
|
public void TestClockRateAdjusted(double expected, string name)
|
||||||
=> Test(expected, name, new OsuModDoubleTime());
|
=> Test(expected, name, new OsuModDoubleTime());
|
||||||
|
|
||||||
|
174
osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Skinning.Legacy;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests
|
||||||
|
{
|
||||||
|
public class TestSceneCursorParticles : TestSceneOsuPlayer
|
||||||
|
{
|
||||||
|
protected override bool Autoplay => autoplay;
|
||||||
|
protected override bool HasCustomSteps => true;
|
||||||
|
|
||||||
|
private bool autoplay;
|
||||||
|
private IBeatmap currentBeatmap;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private SkinManager skinManager { get; set; }
|
||||||
|
|
||||||
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => currentBeatmap ?? base.CreateBeatmap(ruleset);
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLegacyBreakParticles()
|
||||||
|
{
|
||||||
|
LegacyCursorParticles cursorParticles = null;
|
||||||
|
|
||||||
|
createLegacyTest(false, () => new Beatmap
|
||||||
|
{
|
||||||
|
Breaks =
|
||||||
|
{
|
||||||
|
new BreakPeriod(8500, 10000),
|
||||||
|
},
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 8000,
|
||||||
|
Position = OsuPlayfield.BASE_SIZE / 2,
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 11000,
|
||||||
|
Position = OsuPlayfield.BASE_SIZE / 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("fetch cursor particles", () =>
|
||||||
|
{
|
||||||
|
cursorParticles = this.ChildrenOfType<LegacyCursorParticles>().SingleOrDefault();
|
||||||
|
return cursorParticles != null;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("move mouse to centre", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre));
|
||||||
|
|
||||||
|
AddAssert("particles are being spawned", () => cursorParticles.Active);
|
||||||
|
|
||||||
|
AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left));
|
||||||
|
AddWaitStep("wait a bit", 5);
|
||||||
|
AddStep("press right mouse button", () => InputManager.PressButton(MouseButton.Right));
|
||||||
|
AddWaitStep("wait a bit", 5);
|
||||||
|
AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
|
AddWaitStep("wait a bit", 5);
|
||||||
|
AddStep("release right mouse button", () => InputManager.ReleaseButton(MouseButton.Right));
|
||||||
|
|
||||||
|
AddUntilStep("wait for beatmap start", () => !Player.IsBreakTime.Value);
|
||||||
|
AddAssert("particle spawning stopped", () => !cursorParticles.Active);
|
||||||
|
|
||||||
|
AddUntilStep("wait for break", () => Player.IsBreakTime.Value);
|
||||||
|
AddAssert("particles are being spawned", () => cursorParticles.Active);
|
||||||
|
|
||||||
|
AddUntilStep("wait for break end", () => !Player.IsBreakTime.Value);
|
||||||
|
AddAssert("particle spawning stopped", () => !cursorParticles.Active);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestLegacyKiaiParticles()
|
||||||
|
{
|
||||||
|
LegacyCursorParticles cursorParticles = null;
|
||||||
|
DrawableSpinner spinner = null;
|
||||||
|
DrawableSlider slider = null;
|
||||||
|
|
||||||
|
createLegacyTest(true, () =>
|
||||||
|
{
|
||||||
|
var controlPointInfo = new ControlPointInfo();
|
||||||
|
controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true });
|
||||||
|
|
||||||
|
return new Beatmap
|
||||||
|
{
|
||||||
|
ControlPointInfo = controlPointInfo,
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new Spinner
|
||||||
|
{
|
||||||
|
StartTime = 0,
|
||||||
|
Duration = 1000,
|
||||||
|
Position = OsuPlayfield.BASE_SIZE / 2,
|
||||||
|
},
|
||||||
|
new Slider
|
||||||
|
{
|
||||||
|
StartTime = 2500,
|
||||||
|
RepeatCount = 0,
|
||||||
|
Position = OsuPlayfield.BASE_SIZE / 2,
|
||||||
|
Path = new SliderPath(new[]
|
||||||
|
{
|
||||||
|
new PathControlPoint(Vector2.Zero),
|
||||||
|
new PathControlPoint(new Vector2(100, 0)),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
new HitCircle
|
||||||
|
{
|
||||||
|
StartTime = 4500,
|
||||||
|
Position = OsuPlayfield.BASE_SIZE / 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
AddUntilStep("fetch cursor particles", () =>
|
||||||
|
{
|
||||||
|
cursorParticles = this.ChildrenOfType<LegacyCursorParticles>().SingleOrDefault();
|
||||||
|
return cursorParticles != null;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for spinner tracking", () =>
|
||||||
|
{
|
||||||
|
spinner = this.ChildrenOfType<DrawableSpinner>().SingleOrDefault();
|
||||||
|
return spinner?.RotationTracker.Tracking == true;
|
||||||
|
});
|
||||||
|
AddAssert("particles are being spawned", () => cursorParticles.Active);
|
||||||
|
|
||||||
|
AddUntilStep("spinner tracking stopped", () => !spinner.RotationTracker.Tracking);
|
||||||
|
AddAssert("particle spawning stopped", () => !cursorParticles.Active);
|
||||||
|
|
||||||
|
AddUntilStep("wait for slider tracking", () =>
|
||||||
|
{
|
||||||
|
slider = this.ChildrenOfType<DrawableSlider>().SingleOrDefault();
|
||||||
|
return slider?.Tracking.Value == true;
|
||||||
|
});
|
||||||
|
AddAssert("particles are being spawned", () => cursorParticles.Active);
|
||||||
|
|
||||||
|
AddUntilStep("slider tracking stopped", () => !slider.Tracking.Value);
|
||||||
|
AddAssert("particle spawning stopped", () => !cursorParticles.Active);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createLegacyTest(bool autoplay, Func<IBeatmap> beatmap) => CreateTest(() =>
|
||||||
|
{
|
||||||
|
AddStep("set beatmap", () =>
|
||||||
|
{
|
||||||
|
this.autoplay = autoplay;
|
||||||
|
currentBeatmap = beatmap();
|
||||||
|
});
|
||||||
|
AddStep("setup default legacy skin", () =>
|
||||||
|
{
|
||||||
|
skinManager.CurrentSkinInfo.Value = skinManager.DefaultLegacySkin.SkinInfo;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.OpenGL.Textures;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Testing.Input;
|
using osu.Framework.Testing.Input;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -143,9 +144,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
pressed = value;
|
pressed = value;
|
||||||
if (value)
|
if (value)
|
||||||
OnPressed(OsuAction.LeftButton);
|
OnPressed(new KeyBindingPressEvent<OsuAction>(GetContainingInputManager().CurrentState, OsuAction.LeftButton));
|
||||||
else
|
else
|
||||||
OnReleased(OsuAction.LeftButton);
|
OnReleased(new KeyBindingReleaseEvent<OsuAction>(GetContainingInputManager().CurrentState, OsuAction.LeftButton));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
@ -97,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
private void scheduleHit() => AddStep("schedule action", () =>
|
private void scheduleHit() => AddStep("schedule action", () =>
|
||||||
{
|
{
|
||||||
var delay = hitCircle.StartTime - hitCircle.HitWindows.WindowFor(HitResult.Great) - Time.Current;
|
var delay = hitCircle.StartTime - hitCircle.HitWindows.WindowFor(HitResult.Great) - Time.Current;
|
||||||
Scheduler.AddDelayed(() => hitAreaReceptor.OnPressed(OsuAction.LeftButton), delay);
|
Scheduler.AddDelayed(() => hitAreaReceptor.OnPressed(new KeyBindingPressEvent<OsuAction>(GetContainingInputManager().CurrentState, OsuAction.LeftButton)), delay);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ using osu.Game.Configuration;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Storyboards;
|
using osu.Game.Storyboards;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
@ -86,9 +87,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
if (firstObject == null)
|
if (firstObject == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var skinnable = firstObject.ApproachCircle.Child as SkinnableDrawable;
|
var skinnable = firstObject.ApproachCircle;
|
||||||
|
|
||||||
if (skin == null && skinnable?.Drawable is Sprite)
|
if (skin == null && skinnable?.Drawable is DefaultApproachCircle)
|
||||||
// check for default skin provider
|
// check for default skin provider
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
|
@ -34,7 +34,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
|
|
||||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||||
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||||
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
|
|
||||||
|
double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000;
|
||||||
|
double baseSpeedPerformance = Math.Pow(5 * Math.Max(1, speedRating / 0.0675) - 4, 3) / 100000;
|
||||||
|
double basePerformance = Math.Pow(Math.Pow(baseAimPerformance, 1.1) + Math.Pow(baseSpeedPerformance, 1.1), 1 / 1.1);
|
||||||
|
double starRating = basePerformance > 0.00001 ? Math.Cbrt(1.12) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0;
|
||||||
|
|
||||||
HitWindows hitWindows = new OsuHitWindows();
|
HitWindows hitWindows = new OsuHitWindows();
|
||||||
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
|
||||||
|
@ -127,9 +127,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(PlatformAction action)
|
public bool OnPressed(KeyBindingPressEvent<PlatformAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case PlatformAction.Delete:
|
case PlatformAction.Delete:
|
||||||
return DeleteSelected();
|
return DeleteSelected();
|
||||||
@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(PlatformAction action)
|
public void OnReleased(KeyBindingReleaseEvent<PlatformAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
52
osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Edit.Setup
|
||||||
|
{
|
||||||
|
public class OsuSetupSection : RulesetSetupSection
|
||||||
|
{
|
||||||
|
private LabelledSliderBar<float> stackLeniency;
|
||||||
|
|
||||||
|
public OsuSetupSection()
|
||||||
|
: base(new OsuRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
stackLeniency = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = "Stack Leniency",
|
||||||
|
Description = "In play mode, osu! automatically stacks notes which occur at the same location. Increasing this value means it is more likely to snap notes of further time-distance.",
|
||||||
|
Current = new BindableFloat(Beatmap.BeatmapInfo.StackLeniency)
|
||||||
|
{
|
||||||
|
Default = 0.7f,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 1,
|
||||||
|
Precision = 0.1f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
stackLeniency.Current.BindValueChanged(_ => updateBeatmap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBeatmap()
|
||||||
|
{
|
||||||
|
Beatmap.BeatmapInfo.StackLeniency = stackLeniency.Current.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Judgements;
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
@ -25,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
public OsuAction? HitAction => HitArea.HitAction;
|
public OsuAction? HitAction => HitArea.HitAction;
|
||||||
protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle;
|
protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle;
|
||||||
|
|
||||||
public ApproachCircle ApproachCircle { get; private set; }
|
public SkinnableDrawable ApproachCircle { get; private set; }
|
||||||
public HitReceptor HitArea { get; private set; }
|
public HitReceptor HitArea { get; private set; }
|
||||||
public SkinnableDrawable CirclePiece { get; private set; }
|
public SkinnableDrawable CirclePiece { get; private set; }
|
||||||
|
|
||||||
@ -74,8 +75,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
ApproachCircle = new ApproachCircle
|
ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle())
|
||||||
{
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
Scale = new Vector2(4),
|
Scale = new Vector2(4),
|
||||||
}
|
}
|
||||||
@ -88,7 +92,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition);
|
||||||
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue));
|
||||||
AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -228,15 +231,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
CornerExponent = 2;
|
CornerExponent = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(OsuAction action)
|
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case OsuAction.LeftButton:
|
case OsuAction.LeftButton:
|
||||||
case OsuAction.RightButton:
|
case OsuAction.RightButton:
|
||||||
if (IsHovered && (Hit?.Invoke() ?? false))
|
if (IsHovered && (Hit?.Invoke() ?? false))
|
||||||
{
|
{
|
||||||
HitAction = action;
|
HitAction = e.Action;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +249,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(OsuAction action)
|
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProxyableSkinnableDrawable : SkinnableDrawable
|
||||||
|
{
|
||||||
|
public override bool RemoveWhenNotAlive => false;
|
||||||
|
|
||||||
|
public ProxyableSkinnableDrawable(ISkinComponent component, Func<ISkinComponent, Drawable> defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling)
|
||||||
|
: base(component, defaultImplementation, confineMode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,10 +74,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
public override void PlayAnimation()
|
public override void PlayAnimation()
|
||||||
{
|
{
|
||||||
base.PlayAnimation();
|
|
||||||
|
|
||||||
if (Result != HitResult.Miss)
|
if (Result != HitResult.Miss)
|
||||||
JudgementText.ScaleTo(new Vector2(0.8f, 1)).Then().ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint);
|
{
|
||||||
|
JudgementText
|
||||||
|
.ScaleTo(new Vector2(0.8f, 1))
|
||||||
|
.ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.PlayAnimation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,11 @@ using osu.Game.Skinning;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions.EnumExtensions;
|
using osu.Framework.Extensions.EnumExtensions;
|
||||||
|
using osu.Game.Rulesets.Osu.Edit.Setup;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Legacy;
|
using osu.Game.Rulesets.Osu.Skinning.Legacy;
|
||||||
using osu.Game.Rulesets.Osu.Statistics;
|
using osu.Game.Rulesets.Osu.Statistics;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
using osu.Game.Screens.Ranking.Statistics;
|
using osu.Game.Screens.Ranking.Statistics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu
|
namespace osu.Game.Rulesets.Osu
|
||||||
@ -305,5 +307,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override RulesetSetupSection CreateEditorSetupSection() => new OsuSetupSection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
FollowPoint,
|
FollowPoint,
|
||||||
Cursor,
|
Cursor,
|
||||||
CursorTrail,
|
CursorTrail,
|
||||||
|
CursorParticles,
|
||||||
SliderScorePoint,
|
SliderScorePoint,
|
||||||
ReverseArrow,
|
ReverseArrow,
|
||||||
HitCircleText,
|
HitCircleText,
|
||||||
@ -18,5 +19,6 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
SliderBall,
|
SliderBall,
|
||||||
SliderBody,
|
SliderBody,
|
||||||
SpinnerBody,
|
SpinnerBody,
|
||||||
|
ApproachCircle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Containers;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Game.Skinning;
|
|
||||||
using osuTK;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|
||||||
{
|
|
||||||
public class ApproachCircle : Container
|
|
||||||
{
|
|
||||||
public override bool RemoveWhenNotAlive => false;
|
|
||||||
|
|
||||||
public ApproachCircle()
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre;
|
|
||||||
Origin = Anchor.Centre;
|
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(TextureStore textures)
|
|
||||||
{
|
|
||||||
Child = new SkinnableApproachCircle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SkinnableApproachCircle : SkinnableSprite
|
|
||||||
{
|
|
||||||
public SkinnableApproachCircle()
|
|
||||||
: base("Gameplay/osu/approachcircle")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Drawable CreateDefault(ISkinComponent component)
|
|
||||||
{
|
|
||||||
var drawable = base.CreateDefault(component);
|
|
||||||
|
|
||||||
// account for the sprite being used for the default approach circle being taken from stable,
|
|
||||||
// when hitcircles have 5px padding on each size. this should be removed if we update the sprite.
|
|
||||||
drawable.Scale = new Vector2(128 / 118f);
|
|
||||||
|
|
||||||
return drawable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||||
|
{
|
||||||
|
public class DefaultApproachCircle : SkinnableSprite
|
||||||
|
{
|
||||||
|
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private DrawableHitObject drawableObject { get; set; }
|
||||||
|
|
||||||
|
public DefaultApproachCircle()
|
||||||
|
: base("Gameplay/osu/approachcircle")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
accentColour.BindTo(drawableObject.AccentColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
accentColour.BindValueChanged(colour => Colour = colour.NewValue, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateDefault(ISkinComponent component)
|
||||||
|
{
|
||||||
|
var drawable = base.CreateDefault(component);
|
||||||
|
|
||||||
|
// Although this is a non-legacy component, osu-resources currently stores approach circle as a legacy-like texture.
|
||||||
|
// See LegacyApproachCircle for documentation as to why this is required.
|
||||||
|
drawable.Scale = new Vector2(128 / 118f);
|
||||||
|
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
pathVersion.BindValueChanged(_ => Refresh());
|
pathVersion.BindValueChanged(_ => Refresh());
|
||||||
|
|
||||||
accentColour = drawableObject.AccentColour.GetBoundCopy();
|
accentColour = drawableObject.AccentColour.GetBoundCopy();
|
||||||
accentColour.BindValueChanged(accent => updateAccentColour(skin, accent.NewValue), true);
|
accentColour.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true);
|
||||||
|
|
||||||
config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn);
|
config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn);
|
||||||
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, configSnakingOut);
|
config?.BindWith(OsuRulesetSetting.SnakingOutSliders, configSnakingOut);
|
||||||
@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAccentColour(ISkinSource skin, Color4 defaultAccentColour)
|
protected virtual Color4 GetBodyAccentColour(ISkinSource skin, Color4 hitObjectAccentColour) =>
|
||||||
=> AccentColour = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? defaultAccentColour;
|
skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.SliderTrackOverride)?.Value ?? hitObjectAccentColour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A <see cref="SliderBody"/> which changes its curve depending on the snaking progress.
|
/// A <see cref="SliderBody"/> which changes its curve depending on the snaking progress.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SnakingSliderBody : SliderBody, ISliderProgress
|
public abstract class SnakingSliderBody : SliderBody, ISliderProgress
|
||||||
{
|
{
|
||||||
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
|
public readonly List<Vector2> CurrentCurve = new List<Vector2>();
|
||||||
|
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||||
|
{
|
||||||
|
public class LegacyApproachCircle : SkinnableSprite
|
||||||
|
{
|
||||||
|
private readonly IBindable<Color4> accentColour = new Bindable<Color4>();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private DrawableHitObject drawableObject { get; set; }
|
||||||
|
|
||||||
|
public LegacyApproachCircle()
|
||||||
|
: base("Gameplay/osu/approachcircle")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
accentColour.BindTo(drawableObject.AccentColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
accentColour.BindValueChanged(colour => Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateDefault(ISkinComponent component)
|
||||||
|
{
|
||||||
|
var drawable = base.CreateDefault(component);
|
||||||
|
|
||||||
|
// account for the sprite being used for the default approach circle being taken from stable,
|
||||||
|
// when hitcircles have 5px padding on each size. this should be removed if we update the sprite.
|
||||||
|
drawable.Scale = new Vector2(128 / 118f);
|
||||||
|
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
256
osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||||
|
{
|
||||||
|
public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler<OsuAction>
|
||||||
|
{
|
||||||
|
public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true;
|
||||||
|
|
||||||
|
private LegacyCursorParticleSpewer breakSpewer;
|
||||||
|
private LegacyCursorParticleSpewer kiaiSpewer;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private Player player { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private OsuPlayfield playfield { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private GameplayBeatmap gameplayBeatmap { get; set; }
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private GameplayClock gameplayClock { get; set; }
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(ISkinSource skin, OsuColour colours)
|
||||||
|
{
|
||||||
|
var texture = skin.GetTexture("star2");
|
||||||
|
var starBreakAdditive = skin.GetConfig<OsuSkinColour, Color4>(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255);
|
||||||
|
|
||||||
|
if (texture != null)
|
||||||
|
{
|
||||||
|
// stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation.
|
||||||
|
texture.ScaleAdjust *= 1.6f;
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalChildren = new[]
|
||||||
|
{
|
||||||
|
breakSpewer = new LegacyCursorParticleSpewer(texture, 20)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Colour = starBreakAdditive,
|
||||||
|
Direction = SpewDirection.None,
|
||||||
|
},
|
||||||
|
kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60)
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Colour = starBreakAdditive,
|
||||||
|
Direction = SpewDirection.None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (player != null)
|
||||||
|
((IBindable<bool>)breakSpewer.Active).BindTo(player.IsBreakTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
if (playfield == null || gameplayBeatmap == null) return;
|
||||||
|
|
||||||
|
DrawableHitObject kiaiHitObject = null;
|
||||||
|
|
||||||
|
// Check whether currently in a kiai section first. This is only done as an optimisation to avoid enumerating AliveObjects when not necessary.
|
||||||
|
if (gameplayBeatmap.ControlPointInfo.EffectPointAt(gameplayBeatmap.Time.Current).KiaiMode)
|
||||||
|
kiaiHitObject = playfield.HitObjectContainer.AliveObjects.FirstOrDefault(isTracking);
|
||||||
|
|
||||||
|
kiaiSpewer.Active.Value = kiaiHitObject != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isTracking(DrawableHitObject h)
|
||||||
|
{
|
||||||
|
if (!h.HitObject.Kiai)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (h)
|
||||||
|
{
|
||||||
|
case DrawableSlider slider:
|
||||||
|
return slider.Tracking.Value;
|
||||||
|
|
||||||
|
case DrawableSpinner spinner:
|
||||||
|
return spinner.RotationTracker.Tracking;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
|
||||||
|
{
|
||||||
|
handleInput(e.Action, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
|
||||||
|
{
|
||||||
|
handleInput(e.Action, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool leftPressed;
|
||||||
|
private bool rightPressed;
|
||||||
|
|
||||||
|
private void handleInput(OsuAction action, bool pressed)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case OsuAction.LeftButton:
|
||||||
|
leftPressed = pressed;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OsuAction.RightButton:
|
||||||
|
rightPressed = pressed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftPressed && rightPressed)
|
||||||
|
breakSpewer.Direction = SpewDirection.Omni;
|
||||||
|
else if (leftPressed)
|
||||||
|
breakSpewer.Direction = SpewDirection.Left;
|
||||||
|
else if (rightPressed)
|
||||||
|
breakSpewer.Direction = SpewDirection.Right;
|
||||||
|
else
|
||||||
|
breakSpewer.Direction = SpewDirection.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition
|
||||||
|
{
|
||||||
|
private const int particle_duration_min = 300;
|
||||||
|
private const int particle_duration_max = 1000;
|
||||||
|
|
||||||
|
public SpewDirection Direction { get; set; }
|
||||||
|
|
||||||
|
protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue;
|
||||||
|
protected override float ParticleGravity => 240;
|
||||||
|
|
||||||
|
public LegacyCursorParticleSpewer(Texture texture, int perSecond)
|
||||||
|
: base(texture, perSecond, particle_duration_max)
|
||||||
|
{
|
||||||
|
Active.BindValueChanged(_ => resetVelocityCalculation());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2? cursorScreenPosition;
|
||||||
|
private Vector2 cursorVelocity;
|
||||||
|
|
||||||
|
private const double max_velocity_frame_length = 15;
|
||||||
|
private double velocityFrameLength;
|
||||||
|
private Vector2 totalPosDifference;
|
||||||
|
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
|
{
|
||||||
|
if (cursorScreenPosition == null)
|
||||||
|
{
|
||||||
|
cursorScreenPosition = e.ScreenSpaceMousePosition;
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate cursor velocity.
|
||||||
|
totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value;
|
||||||
|
cursorScreenPosition = e.ScreenSpaceMousePosition;
|
||||||
|
|
||||||
|
velocityFrameLength += Math.Abs(Clock.ElapsedFrameTime);
|
||||||
|
|
||||||
|
if (velocityFrameLength > max_velocity_frame_length)
|
||||||
|
{
|
||||||
|
cursorVelocity = totalPosDifference / (float)velocityFrameLength;
|
||||||
|
|
||||||
|
totalPosDifference = Vector2.Zero;
|
||||||
|
velocityFrameLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetVelocityCalculation()
|
||||||
|
{
|
||||||
|
cursorScreenPosition = null;
|
||||||
|
totalPosDifference = Vector2.Zero;
|
||||||
|
velocityFrameLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override FallingParticle CreateParticle() =>
|
||||||
|
new FallingParticle
|
||||||
|
{
|
||||||
|
StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero),
|
||||||
|
Duration = RNG.NextSingle(particle_duration_min, particle_duration_max),
|
||||||
|
StartAngle = (float)(RNG.NextDouble() * 4 - 2),
|
||||||
|
EndAngle = RNG.NextSingle(-2f, 2f),
|
||||||
|
EndScale = RNG.NextSingle(2f),
|
||||||
|
Velocity = getVelocity(),
|
||||||
|
};
|
||||||
|
|
||||||
|
private Vector2 getVelocity()
|
||||||
|
{
|
||||||
|
Vector2 velocity = Vector2.Zero;
|
||||||
|
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SpewDirection.Left:
|
||||||
|
velocity = new Vector2(
|
||||||
|
RNG.NextSingle(-460f, 0),
|
||||||
|
RNG.NextSingle(-40f, 40f)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpewDirection.Right:
|
||||||
|
velocity = new Vector2(
|
||||||
|
RNG.NextSingle(0, 460f),
|
||||||
|
RNG.NextSingle(-40f, 40f)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpewDirection.Omni:
|
||||||
|
velocity = new Vector2(
|
||||||
|
RNG.NextSingle(-460f, 460f),
|
||||||
|
RNG.NextSingle(-160f, 160f)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
velocity += cursorVelocity * 40;
|
||||||
|
|
||||||
|
return velocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum SpewDirection
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Omni,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -14,6 +15,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
{
|
{
|
||||||
protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath();
|
protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath();
|
||||||
|
|
||||||
|
protected override Color4 GetBodyAccentColour(ISkinSource skin, Color4 hitObjectAccentColour)
|
||||||
|
{
|
||||||
|
// legacy skins use a constant value for slider track alpha, regardless of the source colour.
|
||||||
|
return base.GetBodyAccentColour(skin, hitObjectAccentColour).Opacity(0.7f);
|
||||||
|
}
|
||||||
|
|
||||||
private class LegacyDrawableSliderPath : DrawableSliderPath
|
private class LegacyDrawableSliderPath : DrawableSliderPath
|
||||||
{
|
{
|
||||||
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS);
|
||||||
@ -22,8 +29,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
// Roughly matches osu!stable's slider border portions.
|
// Roughly matches osu!stable's slider border portions.
|
||||||
=> base.CalculatedBorderPortion * 0.77f;
|
=> base.CalculatedBorderPortion * 0.77f;
|
||||||
|
|
||||||
public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, 0.7f);
|
|
||||||
|
|
||||||
protected override Color4 ColourAt(float position)
|
protected override Color4 ColourAt(float position)
|
||||||
{
|
{
|
||||||
float realBorderPortion = shadow_portion + CalculatedBorderPortion;
|
float realBorderPortion = shadow_portion + CalculatedBorderPortion;
|
||||||
|
@ -95,6 +95,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
case OsuSkinComponents.CursorParticles:
|
||||||
|
if (GetTexture("star2") != null)
|
||||||
|
return new LegacyCursorParticles();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
case OsuSkinComponents.HitCircleText:
|
case OsuSkinComponents.HitCircleText:
|
||||||
if (!this.HasFont(LegacyFont.HitCircle))
|
if (!this.HasFont(LegacyFont.HitCircle))
|
||||||
return null;
|
return null;
|
||||||
@ -114,6 +120,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
return new LegacyOldStyleSpinner();
|
return new LegacyOldStyleSpinner();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
case OsuSkinComponents.ApproachCircle:
|
||||||
|
return new LegacyApproachCircle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,5 +9,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
SliderBorder,
|
SliderBorder,
|
||||||
SliderBall,
|
SliderBall,
|
||||||
SpinnerBackground,
|
SpinnerBackground,
|
||||||
|
StarBreakAdditive,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Osu.Configuration;
|
using osu.Game.Rulesets.Osu.Configuration;
|
||||||
@ -42,7 +43,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
InternalChild = fadeContainer = new Container
|
InternalChild = fadeContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling)
|
Children = new[]
|
||||||
|
{
|
||||||
|
cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling),
|
||||||
|
new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorParticles), confineMode: ConfineMode.NoScaling),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,9 +120,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
(ActiveCursor as OsuCursor)?.Contract();
|
(ActiveCursor as OsuCursor)?.Contract();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(OsuAction action)
|
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case OsuAction.LeftButton:
|
case OsuAction.LeftButton:
|
||||||
case OsuAction.RightButton:
|
case OsuAction.RightButton:
|
||||||
@ -129,9 +134,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(OsuAction action)
|
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case OsuAction.LeftButton:
|
case OsuAction.LeftButton:
|
||||||
case OsuAction.RightButton:
|
case OsuAction.RightButton:
|
||||||
|
@ -24,6 +24,7 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.UI
|
namespace osu.Game.Rulesets.Osu.UI
|
||||||
{
|
{
|
||||||
|
[Cached]
|
||||||
public class OsuPlayfield : Playfield
|
public class OsuPlayfield : Playfield
|
||||||
{
|
{
|
||||||
private readonly PlayfieldBorder playfieldBorder;
|
private readonly PlayfieldBorder playfieldBorder;
|
||||||
|
@ -89,9 +89,9 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
base.OnHoverLost(e);
|
base.OnHoverLost(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(OsuAction action)
|
public bool OnPressed(KeyBindingPressEvent<OsuAction> e)
|
||||||
{
|
{
|
||||||
switch (action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case OsuAction.LeftButton:
|
case OsuAction.LeftButton:
|
||||||
case OsuAction.RightButton:
|
case OsuAction.RightButton:
|
||||||
@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.UI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(OsuAction action)
|
public void OnReleased(KeyBindingReleaseEvent<OsuAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -37,6 +38,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
Result.Type = Type;
|
Result.Type = Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
@ -30,6 +31,6 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
nestedStrongHit.Result.Type = hitBoth ? Type : HitResult.Miss;
|
nestedStrongHit.Result.Type = hitBoth ? Type : HitResult.Miss;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Import Project="..\osu.TestProject.props" />
|
<Import Project="..\osu.TestProject.props" />
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
|
||||||
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||||
|
@ -36,24 +36,27 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
|
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
|
||||||
{
|
{
|
||||||
this.taikoPlayfield = taikoPlayfield;
|
this.taikoPlayfield = taikoPlayfield;
|
||||||
FlashlightSize = new Vector2(0, getSizeFor(0));
|
FlashlightSize = getSizeFor(0);
|
||||||
|
|
||||||
AddLayout(flashlightProperties);
|
AddLayout(flashlightProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getSizeFor(int combo)
|
private Vector2 getSizeFor(int combo)
|
||||||
{
|
{
|
||||||
|
float size = default_flashlight_size;
|
||||||
|
|
||||||
if (combo > 200)
|
if (combo > 200)
|
||||||
return default_flashlight_size * 0.8f;
|
size *= 0.8f;
|
||||||
else if (combo > 100)
|
else if (combo > 100)
|
||||||
return default_flashlight_size * 0.9f;
|
size *= 0.9f;
|
||||||
else
|
|
||||||
return default_flashlight_size;
|
// Preserve flashlight size through the playfield's aspect adjustment.
|
||||||
|
return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnComboChange(ValueChangedEvent<int> e)
|
protected override void OnComboChange(ValueChangedEvent<int> e)
|
||||||
{
|
{
|
||||||
this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION);
|
this.TransformTo(nameof(FlashlightSize), getSizeFor(e.NewValue), FLASHLIGHT_FADE_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string FragmentShader => "CircularFlashlight";
|
protected override string FragmentShader => "CircularFlashlight";
|
||||||
@ -64,7 +67,11 @@ namespace osu.Game.Rulesets.Taiko.Mods
|
|||||||
|
|
||||||
if (!flashlightProperties.IsValid)
|
if (!flashlightProperties.IsValid)
|
||||||
{
|
{
|
||||||
FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this);
|
FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre);
|
||||||
|
|
||||||
|
ClearTransforms(targetMember: nameof(FlashlightSize));
|
||||||
|
FlashlightSize = getSizeFor(Combo.Value);
|
||||||
|
|
||||||
flashlightProperties.Validate();
|
flashlightProperties.Validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ using osu.Game.Rulesets.Objects.Drawables;
|
|||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -112,7 +113,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollBody),
|
protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollBody),
|
||||||
_ => new ElongatedCirclePiece());
|
_ => new ElongatedCirclePiece());
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
|
|
||||||
private void onNewResult(DrawableHitObject obj, JudgementResult result)
|
private void onNewResult(DrawableHitObject obj, JudgementResult result)
|
||||||
{
|
{
|
||||||
@ -196,7 +197,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -61,9 +62,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
JudgementType = action == TaikoAction.LeftRim || action == TaikoAction.RightRim ? HitType.Rim : HitType.Centre;
|
JudgementType = e.Action == TaikoAction.LeftRim || e.Action == TaikoAction.RightRim ? HitType.Rim : HitType.Centre;
|
||||||
return UpdateResult(true);
|
return UpdateResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
@ -145,19 +146,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = result);
|
ApplyResult(r => r.Type = result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
if (pressHandledThisFrame)
|
if (pressHandledThisFrame)
|
||||||
return true;
|
return true;
|
||||||
if (Judged)
|
if (Judged)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
validActionPressed = HitActions.Contains(action);
|
validActionPressed = HitActions.Contains(e.Action);
|
||||||
|
|
||||||
// Only count this as handled if the new judgement is a hit
|
// Only count this as handled if the new judgement is a hit
|
||||||
var result = UpdateResult(true);
|
var result = UpdateResult(true);
|
||||||
if (IsHit)
|
if (IsHit)
|
||||||
HitAction = action;
|
HitAction = e.Action;
|
||||||
|
|
||||||
// Regardless of whether we've hit or not, any secondary key presses in the same frame should be discarded
|
// Regardless of whether we've hit or not, any secondary key presses in the same frame should be discarded
|
||||||
// E.g. hitting a non-strong centre as a strong should not fall through and perform a hit on the next note
|
// E.g. hitting a non-strong centre as a strong should not fall through and perform a hit on the next note
|
||||||
@ -165,11 +166,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnReleased(TaikoAction action)
|
public override void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
if (action == HitAction)
|
if (e.Action == HitAction)
|
||||||
HitAction = null;
|
HitAction = null;
|
||||||
base.OnReleased(action);
|
base.OnReleased(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -265,7 +266,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
// Don't process actions until the main hitobject is hit
|
// Don't process actions until the main hitobject is hit
|
||||||
if (!ParentHitObject.IsHit)
|
if (!ParentHitObject.IsHit)
|
||||||
@ -276,7 +277,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Don't handle invalid hit action presses
|
// Don't handle invalid hit action presses
|
||||||
if (!ParentHitObject.HitActions.Contains(action))
|
if (!ParentHitObject.HitActions.Contains(e.Action))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return UpdateResult(true);
|
return UpdateResult(true);
|
||||||
|
@ -12,6 +12,7 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
||||||
@ -266,13 +267,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
private bool? lastWasCentre;
|
private bool? lastWasCentre;
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
// Don't handle keys before the swell starts
|
// Don't handle keys before the swell starts
|
||||||
if (Time.Current < HitObject.StartTime)
|
if (Time.Current < HitObject.StartTime)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var isCentre = action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre;
|
var isCentre = e.Action == TaikoAction.LeftCentre || e.Action == TaikoAction.RightCentre;
|
||||||
|
|
||||||
// Ensure alternating centre and rim hits
|
// Ensure alternating centre and rim hits
|
||||||
if (lastWasCentre == isCentre)
|
if (lastWasCentre == isCentre)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
using osu.Game.Rulesets.Taiko.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -34,7 +35,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(KeyBindingPressEvent<TaikoAction> e) => false;
|
||||||
|
|
||||||
protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick),
|
protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick),
|
||||||
_ => new TickPiece());
|
_ => new TickPiece());
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -76,9 +77,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Drawable CreateProxiedContent() => proxiedContent.CreateProxy();
|
public Drawable CreateProxiedContent() => proxiedContent.CreateProxy();
|
||||||
|
|
||||||
public abstract bool OnPressed(TaikoAction action);
|
public abstract bool OnPressed(KeyBindingPressEvent<TaikoAction> e);
|
||||||
|
|
||||||
public virtual void OnReleased(TaikoAction action)
|
public virtual void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.UI;
|
using osu.Game.Rulesets.Taiko.UI;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -141,16 +142,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
Centre.Texture = skin.GetTexture(@"taiko-drum-inner");
|
Centre.Texture = skin.GetTexture(@"taiko-drum-inner");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnPressed(TaikoAction action)
|
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
Drawable target = null;
|
Drawable target = null;
|
||||||
|
|
||||||
if (action == CentreAction)
|
if (e.Action == CentreAction)
|
||||||
{
|
{
|
||||||
target = Centre;
|
target = Centre;
|
||||||
sampleTriggerSource.Play(HitType.Centre);
|
sampleTriggerSource.Play(HitType.Centre);
|
||||||
}
|
}
|
||||||
else if (action == RimAction)
|
else if (e.Action == RimAction)
|
||||||
{
|
{
|
||||||
target = Rim;
|
target = Rim;
|
||||||
sampleTriggerSource.Play(HitType.Rim);
|
sampleTriggerSource.Play(HitType.Rim);
|
||||||
@ -173,7 +174,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(TaikoAction action)
|
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.UI
|
namespace osu.Game.Rulesets.Taiko.UI
|
||||||
{
|
{
|
||||||
@ -16,5 +17,26 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
this.MoveToY(-100, 500);
|
this.MoveToY(-100, 500);
|
||||||
base.ApplyHitAnimations();
|
base.ApplyHitAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Drawable CreateDefaultJudgement(HitResult result) => new TaikoJudgementPiece(result);
|
||||||
|
|
||||||
|
private class TaikoJudgementPiece : DefaultJudgementPiece
|
||||||
|
{
|
||||||
|
public TaikoJudgementPiece(HitResult result)
|
||||||
|
: base(result)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PlayAnimation()
|
||||||
|
{
|
||||||
|
if (Result != HitResult.Miss)
|
||||||
|
{
|
||||||
|
JudgementText.ScaleTo(0.9f);
|
||||||
|
JudgementText.ScaleTo(1, 500, Easing.OutElastic);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.PlayAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -151,19 +152,19 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private GameplayClock gameplayClock { get; set; }
|
private GameplayClock gameplayClock { get; set; }
|
||||||
|
|
||||||
public bool OnPressed(TaikoAction action)
|
public bool OnPressed(KeyBindingPressEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
Drawable target = null;
|
Drawable target = null;
|
||||||
Drawable back = null;
|
Drawable back = null;
|
||||||
|
|
||||||
if (action == CentreAction)
|
if (e.Action == CentreAction)
|
||||||
{
|
{
|
||||||
target = centreHit;
|
target = centreHit;
|
||||||
back = centre;
|
back = centre;
|
||||||
|
|
||||||
sampleTriggerSource.Play(HitType.Centre);
|
sampleTriggerSource.Play(HitType.Centre);
|
||||||
}
|
}
|
||||||
else if (action == RimAction)
|
else if (e.Action == RimAction)
|
||||||
{
|
{
|
||||||
target = rimHit;
|
target = rimHit;
|
||||||
back = rim;
|
back = rim;
|
||||||
@ -195,7 +196,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(TaikoAction action)
|
public void OnReleased(KeyBindingReleaseEvent<TaikoAction> e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,12 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NUnit.Framework;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Game.Tests.Resources;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
@ -19,9 +16,13 @@ using osu.Game.Rulesets.Catch.Beatmaps;
|
|||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu.Beatmaps;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Beatmaps.Formats
|
namespace osu.Game.Tests.Beatmaps.Formats
|
||||||
{
|
{
|
||||||
@ -63,6 +64,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
Assert.IsFalse(beatmapInfo.LetterboxInBreaks);
|
||||||
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
Assert.IsFalse(beatmapInfo.SpecialStyle);
|
||||||
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
Assert.IsFalse(beatmapInfo.WidescreenStoryboard);
|
||||||
|
Assert.IsFalse(beatmapInfo.SamplesMatchPlaybackRate);
|
||||||
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown);
|
||||||
Assert.AreEqual(0, beatmapInfo.CountdownOffset);
|
Assert.AreEqual(0, beatmapInfo.CountdownOffset);
|
||||||
}
|
}
|
||||||
@ -166,7 +168,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
using (var stream = new LineBufferedReader(resStream))
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
{
|
{
|
||||||
var beatmap = decoder.Decode(stream);
|
var beatmap = decoder.Decode(stream);
|
||||||
var controlPoints = beatmap.ControlPointInfo;
|
var controlPoints = (LegacyControlPointInfo)beatmap.ControlPointInfo;
|
||||||
|
|
||||||
Assert.AreEqual(4, controlPoints.TimingPoints.Count);
|
Assert.AreEqual(4, controlPoints.TimingPoints.Count);
|
||||||
Assert.AreEqual(5, controlPoints.DifficultyPoints.Count);
|
Assert.AreEqual(5, controlPoints.DifficultyPoints.Count);
|
||||||
@ -240,7 +242,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
using (var resStream = TestResources.OpenResource("overlapping-control-points.osu"))
|
using (var resStream = TestResources.OpenResource("overlapping-control-points.osu"))
|
||||||
using (var stream = new LineBufferedReader(resStream))
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
{
|
{
|
||||||
var controlPoints = decoder.Decode(stream).ControlPointInfo;
|
var controlPoints = (LegacyControlPointInfo)decoder.Decode(stream).ControlPointInfo;
|
||||||
|
|
||||||
Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(4));
|
Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(4));
|
||||||
Assert.That(controlPoints.DifficultyPoints.Count, Is.EqualTo(3));
|
Assert.That(controlPoints.DifficultyPoints.Count, Is.EqualTo(3));
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.IO.Stores;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.IO.Serialization;
|
using osu.Game.IO.Serialization;
|
||||||
using osu.Game.Rulesets.Catch;
|
using osu.Game.Rulesets.Catch;
|
||||||
@ -65,6 +66,47 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration));
|
Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCaseSource(nameof(allBeatmaps))]
|
||||||
|
public void TestEncodeDecodeStabilityWithNonLegacyControlPoints(string name)
|
||||||
|
{
|
||||||
|
var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name);
|
||||||
|
|
||||||
|
// we are testing that the transfer of relevant data to hitobjects (from legacy control points) sticks through encode/decode.
|
||||||
|
// before the encode step, the legacy information is removed here.
|
||||||
|
decoded.beatmap.ControlPointInfo = removeLegacyControlPointTypes(decoded.beatmap.ControlPointInfo);
|
||||||
|
|
||||||
|
var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name);
|
||||||
|
|
||||||
|
// in this process, we may lose some detail in the control points section.
|
||||||
|
// let's focus on only the hitobjects.
|
||||||
|
var originalHitObjects = decoded.beatmap.HitObjects.Serialize();
|
||||||
|
var newHitObjects = decodedAfterEncode.beatmap.HitObjects.Serialize();
|
||||||
|
|
||||||
|
Assert.That(newHitObjects, Is.EqualTo(originalHitObjects));
|
||||||
|
|
||||||
|
ControlPointInfo removeLegacyControlPointTypes(ControlPointInfo controlPointInfo)
|
||||||
|
{
|
||||||
|
// emulate non-legacy control points by cloning the non-legacy portion.
|
||||||
|
// the assertion is that the encoder can recreate this losslessly from hitobject data.
|
||||||
|
Assert.IsInstanceOf<LegacyControlPointInfo>(controlPointInfo);
|
||||||
|
|
||||||
|
var newControlPoints = new ControlPointInfo();
|
||||||
|
|
||||||
|
foreach (var point in controlPointInfo.AllControlPoints)
|
||||||
|
{
|
||||||
|
// completely ignore "legacy" types, which have been moved to HitObjects.
|
||||||
|
// even though these would mostly be ignored by the Add call, they will still be available in groups,
|
||||||
|
// which isn't what we want to be testing here.
|
||||||
|
if (point is SampleControlPoint)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
newControlPoints.Add(point.Time, point.DeepClone());
|
||||||
|
}
|
||||||
|
|
||||||
|
return newControlPoints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestEncodeMultiSegmentSliderWithFloatingPointError()
|
public void TestEncodeMultiSegmentSliderWithFloatingPointError()
|
||||||
{
|
{
|
||||||
@ -132,7 +174,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap)
|
private MemoryStream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap)
|
||||||
{
|
{
|
||||||
var (beatmap, beatmapSkin) = fullBeatmap;
|
var (beatmap, beatmapSkin) = fullBeatmap;
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
|
@ -424,14 +424,14 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
checkBeatmapCount(osu, 12);
|
checkBeatmapCount(osu, 12);
|
||||||
checkSingleReferencedFileCount(osu, 18);
|
checkSingleReferencedFileCount(osu, 18);
|
||||||
|
|
||||||
var breakTemp = TestResources.GetTestBeatmapForImport();
|
var brokenTempFilename = TestResources.GetTestBeatmapForImport();
|
||||||
|
|
||||||
MemoryStream brokenOsu = new MemoryStream();
|
MemoryStream brokenOsu = new MemoryStream();
|
||||||
MemoryStream brokenOsz = new MemoryStream(await File.ReadAllBytesAsync(breakTemp));
|
MemoryStream brokenOsz = new MemoryStream(await File.ReadAllBytesAsync(brokenTempFilename));
|
||||||
|
|
||||||
File.Delete(breakTemp);
|
File.Delete(brokenTempFilename);
|
||||||
|
|
||||||
using (var outStream = File.Open(breakTemp, FileMode.CreateNew))
|
using (var outStream = File.Open(brokenTempFilename, FileMode.CreateNew))
|
||||||
using (var zip = ZipArchive.Open(brokenOsz))
|
using (var zip = ZipArchive.Open(brokenOsz))
|
||||||
{
|
{
|
||||||
zip.AddEntry("broken.osu", brokenOsu, false);
|
zip.AddEntry("broken.osu", brokenOsu, false);
|
||||||
@ -441,7 +441,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
// this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu.
|
// this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await manager.Import(new ImportTask(breakTemp));
|
await manager.Import(new ImportTask(brokenTempFilename));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -456,6 +456,8 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
checkSingleReferencedFileCount(osu, 18);
|
checkSingleReferencedFileCount(osu, 18);
|
||||||
|
|
||||||
Assert.AreEqual(1, loggedExceptionCount);
|
Assert.AreEqual(1, loggedExceptionCount);
|
||||||
|
|
||||||
|
File.Delete(brokenTempFilename);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Database
|
namespace osu.Game.Tests.Database
|
||||||
@ -42,7 +43,7 @@ namespace osu.Game.Tests.Database
|
|||||||
|
|
||||||
KeyBindingContainer testContainer = new TestKeyBindingContainer();
|
KeyBindingContainer testContainer = new TestKeyBindingContainer();
|
||||||
|
|
||||||
keyBindingStore.Register(testContainer);
|
keyBindingStore.Register(testContainer, Enumerable.Empty<RulesetInfo>());
|
||||||
|
|
||||||
Assert.That(queryCount(), Is.EqualTo(3));
|
Assert.That(queryCount(), Is.EqualTo(3));
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
KeyBindingContainer testContainer = new TestKeyBindingContainer();
|
KeyBindingContainer testContainer = new TestKeyBindingContainer();
|
||||||
|
|
||||||
keyBindingStore.Register(testContainer);
|
keyBindingStore.Register(testContainer, Enumerable.Empty<RulesetInfo>());
|
||||||
|
|
||||||
using (var primaryUsage = realmContextFactory.GetForRead())
|
using (var primaryUsage = realmContextFactory.GetForRead())
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using NUnit.Framework;
|
|||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Beatmaps.Legacy;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Checks;
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -30,7 +31,7 @@ namespace osu.Game.Tests.Editing.Checks
|
|||||||
{
|
{
|
||||||
check = new CheckMutedObjects();
|
check = new CheckMutedObjects();
|
||||||
|
|
||||||
cpi = new ControlPointInfo();
|
cpi = new LegacyControlPointInfo();
|
||||||
cpi.Add(0, new SampleControlPoint { SampleVolume = volume_regular });
|
cpi.Add(0, new SampleControlPoint { SampleVolume = volume_regular });
|
||||||
cpi.Add(1000, new SampleControlPoint { SampleVolume = volume_low });
|
cpi.Add(1000, new SampleControlPoint { SampleVolume = volume_low });
|
||||||
cpi.Add(2000, new SampleControlPoint { SampleVolume = volume_muted });
|
cpi.Add(2000, new SampleControlPoint { SampleVolume = volume_muted });
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Mods
|
namespace osu.Game.Tests.Mods
|
||||||
@ -11,26 +12,42 @@ namespace osu.Game.Tests.Mods
|
|||||||
public class ModSettingsEqualityComparison
|
public class ModSettingsEqualityComparison
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void Test()
|
public void TestAPIMod()
|
||||||
{
|
{
|
||||||
|
var apiMod1 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.25 } });
|
||||||
|
var apiMod2 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.26 } });
|
||||||
|
var apiMod3 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.26 } });
|
||||||
|
|
||||||
|
Assert.That(apiMod1, Is.Not.EqualTo(apiMod2));
|
||||||
|
Assert.That(apiMod2, Is.EqualTo(apiMod2));
|
||||||
|
Assert.That(apiMod2, Is.EqualTo(apiMod3));
|
||||||
|
Assert.That(apiMod3, Is.EqualTo(apiMod2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMod()
|
||||||
|
{
|
||||||
|
var ruleset = new OsuRuleset();
|
||||||
|
|
||||||
var mod1 = new OsuModDoubleTime { SpeedChange = { Value = 1.25 } };
|
var mod1 = new OsuModDoubleTime { SpeedChange = { Value = 1.25 } };
|
||||||
var mod2 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
var mod2 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
||||||
var mod3 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
var mod3 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } };
|
||||||
var apiMod1 = new APIMod(mod1);
|
|
||||||
var apiMod2 = new APIMod(mod2);
|
var doubleConvertedMod1 = new APIMod(mod1).ToMod(ruleset);
|
||||||
var apiMod3 = new APIMod(mod3);
|
var doulbeConvertedMod2 = new APIMod(mod2).ToMod(ruleset);
|
||||||
|
var doulbeConvertedMod3 = new APIMod(mod3).ToMod(ruleset);
|
||||||
|
|
||||||
Assert.That(mod1, Is.Not.EqualTo(mod2));
|
Assert.That(mod1, Is.Not.EqualTo(mod2));
|
||||||
Assert.That(apiMod1, Is.Not.EqualTo(apiMod2));
|
Assert.That(doubleConvertedMod1, Is.Not.EqualTo(doulbeConvertedMod2));
|
||||||
|
|
||||||
Assert.That(mod2, Is.EqualTo(mod2));
|
Assert.That(mod2, Is.EqualTo(mod2));
|
||||||
Assert.That(apiMod2, Is.EqualTo(apiMod2));
|
Assert.That(doulbeConvertedMod2, Is.EqualTo(doulbeConvertedMod2));
|
||||||
|
|
||||||
Assert.That(mod2, Is.EqualTo(mod3));
|
Assert.That(mod2, Is.EqualTo(mod3));
|
||||||
Assert.That(apiMod2, Is.EqualTo(apiMod3));
|
Assert.That(doulbeConvertedMod2, Is.EqualTo(doulbeConvertedMod3));
|
||||||
|
|
||||||
Assert.That(mod3, Is.EqualTo(mod2));
|
Assert.That(mod3, Is.EqualTo(mod2));
|
||||||
Assert.That(apiMod3, Is.EqualTo(apiMod2));
|
Assert.That(doulbeConvertedMod3, Is.EqualTo(doulbeConvertedMod2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Beatmaps.Legacy;
|
||||||
|
|
||||||
namespace osu.Game.Tests.NonVisual
|
namespace osu.Game.Tests.NonVisual
|
||||||
{
|
{
|
||||||
@ -64,7 +65,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestAddRedundantSample()
|
public void TestAddRedundantSample()
|
||||||
{
|
{
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new LegacyControlPointInfo();
|
||||||
|
|
||||||
cpi.Add(0, new SampleControlPoint()); // is *not* redundant, special exception for first sample point
|
cpi.Add(0, new SampleControlPoint()); // is *not* redundant, special exception for first sample point
|
||||||
cpi.Add(1000, new SampleControlPoint()); // is redundant
|
cpi.Add(1000, new SampleControlPoint()); // is redundant
|
||||||
@ -142,7 +143,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestRemoveGroupAlsoRemovedControlPoints()
|
public void TestRemoveGroupAlsoRemovedControlPoints()
|
||||||
{
|
{
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new LegacyControlPointInfo();
|
||||||
|
|
||||||
var group = cpi.GroupAt(1000, true);
|
var group = cpi.GroupAt(1000, true);
|
||||||
|
|
||||||
|
@ -40,10 +40,10 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
|||||||
assertPlaybackPosition(0);
|
assertPlaybackPosition(0);
|
||||||
|
|
||||||
AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime.Value = 1000);
|
AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime.Value = 1000);
|
||||||
assertPlaybackPosition(-1000);
|
assertPlaybackPosition(0);
|
||||||
|
|
||||||
AddStep("set current time to 500", () => animationTimeReference.ManualClock.CurrentTime = 500);
|
AddStep("set current time to 500", () => animationTimeReference.ManualClock.CurrentTime = 500);
|
||||||
assertPlaybackPosition(-500);
|
assertPlaybackPosition(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertPlaybackPosition(double expectedPosition)
|
private void assertPlaybackPosition(double expectedPosition)
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Resources
|
namespace osu.Game.Tests.Resources
|
||||||
{
|
{
|
||||||
@ -11,6 +13,8 @@ namespace osu.Game.Tests.Resources
|
|||||||
{
|
{
|
||||||
public const double QUICK_BEATMAP_LENGTH = 10000;
|
public const double QUICK_BEATMAP_LENGTH = 10000;
|
||||||
|
|
||||||
|
private static readonly TemporaryNativeStorage temp_storage = new TemporaryNativeStorage("TestResources");
|
||||||
|
|
||||||
public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly);
|
public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly);
|
||||||
|
|
||||||
public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}");
|
public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}");
|
||||||
@ -25,7 +29,7 @@ namespace osu.Game.Tests.Resources
|
|||||||
/// <returns>A path to a copy of a beatmap archive (osz). Should be deleted after use.</returns>
|
/// <returns>A path to a copy of a beatmap archive (osz). Should be deleted after use.</returns>
|
||||||
public static string GetQuickTestBeatmapForImport()
|
public static string GetQuickTestBeatmapForImport()
|
||||||
{
|
{
|
||||||
var tempPath = Path.GetTempFileName() + ".osz";
|
var tempPath = getTempFilename();
|
||||||
using (var stream = OpenResource("Archives/241526 Soleily - Renatus_virtual_quick.osz"))
|
using (var stream = OpenResource("Archives/241526 Soleily - Renatus_virtual_quick.osz"))
|
||||||
using (var newFile = File.Create(tempPath))
|
using (var newFile = File.Create(tempPath))
|
||||||
stream.CopyTo(newFile);
|
stream.CopyTo(newFile);
|
||||||
@ -41,7 +45,7 @@ namespace osu.Game.Tests.Resources
|
|||||||
/// <returns>A path to a copy of a beatmap archive (osz). Should be deleted after use.</returns>
|
/// <returns>A path to a copy of a beatmap archive (osz). Should be deleted after use.</returns>
|
||||||
public static string GetTestBeatmapForImport(bool virtualTrack = false)
|
public static string GetTestBeatmapForImport(bool virtualTrack = false)
|
||||||
{
|
{
|
||||||
var tempPath = Path.GetTempFileName() + ".osz";
|
var tempPath = getTempFilename();
|
||||||
|
|
||||||
using (var stream = GetTestBeatmapStream(virtualTrack))
|
using (var stream = GetTestBeatmapStream(virtualTrack))
|
||||||
using (var newFile = File.Create(tempPath))
|
using (var newFile = File.Create(tempPath))
|
||||||
@ -50,5 +54,7 @@ namespace osu.Game.Tests.Resources
|
|||||||
Assert.IsTrue(File.Exists(tempPath));
|
Assert.IsTrue(File.Exists(tempPath));
|
||||||
return tempPath;
|
return tempPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string getTempFilename() => temp_storage.GetFullPath(Guid.NewGuid() + ".osz");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,9 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
[TestCase(ScoringMode.Standardised, HitResult.Meh, 750_000)]
|
[TestCase(ScoringMode.Standardised, HitResult.Meh, 750_000)]
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.Ok, 800_000)]
|
[TestCase(ScoringMode.Standardised, HitResult.Ok, 800_000)]
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
|
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Meh, 50)]
|
[TestCase(ScoringMode.Classic, HitResult.Meh, 41)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Ok, 100)]
|
[TestCase(ScoringMode.Classic, HitResult.Ok, 46)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Great, 300)]
|
[TestCase(ScoringMode.Classic, HitResult.Great, 72)]
|
||||||
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
||||||
{
|
{
|
||||||
scoreProcessor.Mode.Value = scoringMode;
|
scoreProcessor.Mode.Value = scoringMode;
|
||||||
@ -85,19 +85,18 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 575_000)] // (3 * 30) / (4 * 30) * 300_000 + (0 / 4) * 700_000
|
[TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 575_000)] // (3 * 30) / (4 * 30) * 300_000 + (0 / 4) * 700_000
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 10 (bonus points)
|
[TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 10 (bonus points)
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 50 (bonus points)
|
[TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 50 (bonus points)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)] // (0 * 4 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 156)] // (((3 * 50) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 68)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 312)] // (((3 * 100) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 81)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 594)] // (((3 * 200) / (4 * 350)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 109)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 936)] // (((3 * 300) / (4 * 300)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 149)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 936)] // (((3 * 350) / (4 * 350)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 149)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 0)] // (0 * 1 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 9)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 225)] // (((3 * 10) / (4 * 10)) * 1 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 15)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] // (0 * 4 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 936)] // (((3 * 50) / (4 * 50)) * 4 * 300) * (1 + 1 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 149)]
|
||||||
// TODO: The following two cases don't match expectations currently (a single hit is registered in acc portion when it shouldn't be). See https://github.com/ppy/osu/issues/12604.
|
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 18)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 330)] // (1 * 1 * 300) * (1 + 0 / 25) + 3 * 10 (bonus points)
|
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 18)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 450)] // (1 * 1 * 300) * (1 + 0 / 25) + 3 * 50 (bonus points)
|
|
||||||
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
|
public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
|
||||||
{
|
{
|
||||||
var minResult = new TestJudgement(hitResult).MinResult;
|
var minResult = new TestJudgement(hitResult).MinResult;
|
||||||
@ -129,8 +128,8 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, 978_571)] // (3 * 10 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000
|
[TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, 978_571)] // (3 * 10 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.SmallTickMiss, 914_286)] // (3 * 0 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000
|
[TestCase(ScoringMode.Standardised, HitResult.SmallTickMiss, 914_286)] // (3 * 0 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000
|
||||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, 279)] // (((3 * 10 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.SmallTickHit, 69)] // (((3 * 10 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25)
|
||||||
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, 214)] // (((3 * 0 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25)
|
[TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, 60)] // (((3 * 0 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25)
|
||||||
public void TestSmallTicksAccuracy(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
public void TestSmallTicksAccuracy(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
||||||
{
|
{
|
||||||
IEnumerable<HitObject> hitObjects = Enumerable
|
IEnumerable<HitObject> hitObjects = Enumerable
|
||||||
|
177
osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Tests.Beatmaps.IO;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
public class TestSceneDifficultySwitching : EditorTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
protected override bool IsolateSavingFromDatabase => false;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuGameBase game { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapManager beatmaps { get; set; }
|
||||||
|
|
||||||
|
private BeatmapSetInfo importedBeatmapSet;
|
||||||
|
|
||||||
|
public override void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result);
|
||||||
|
base.SetUpSteps();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadEditor()
|
||||||
|
{
|
||||||
|
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First());
|
||||||
|
base.LoadEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBasicSwitch()
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo)));
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
|
||||||
|
AddStep("exit editor", () => Stack.Exit());
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClockPositionPreservedBetweenSwitches()
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
AddStep("seek editor to 00:05:00", () => EditorClock.Seek(5000));
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo)));
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
AddAssert("editor clock at 00:05:00", () => EditorClock.CurrentTime == 5000);
|
||||||
|
|
||||||
|
AddStep("exit editor", () => Stack.Exit());
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestClipboardPreservedAfterSwitch([Values] bool sameRuleset)
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
|
||||||
|
AddStep("select first object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.First()));
|
||||||
|
AddStep("copy object", () => Editor.Copy());
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () =>
|
||||||
|
{
|
||||||
|
targetDifficulty = sameRuleset
|
||||||
|
? importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.RulesetID == Beatmap.Value.BeatmapInfo.RulesetID)
|
||||||
|
: importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo) && beatmap.RulesetID != Beatmap.Value.BeatmapInfo.RulesetID);
|
||||||
|
});
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
|
||||||
|
AddAssert("no objects selected", () => !EditorBeatmap.SelectedHitObjects.Any());
|
||||||
|
AddStep("paste object", () => Editor.Paste());
|
||||||
|
|
||||||
|
if (sameRuleset)
|
||||||
|
AddAssert("object was pasted", () => EditorBeatmap.SelectedHitObjects.Any());
|
||||||
|
else
|
||||||
|
AddAssert("object was not pasted", () => !EditorBeatmap.SelectedHitObjects.Any());
|
||||||
|
|
||||||
|
AddStep("exit editor", () => Stack.Exit());
|
||||||
|
|
||||||
|
if (sameRuleset)
|
||||||
|
{
|
||||||
|
AddUntilStep("prompt for save dialog shown", () => DialogOverlay.CurrentDialog is PromptForSaveDialog);
|
||||||
|
AddStep("discard changes", () => ((PromptForSaveDialog)DialogOverlay.CurrentDialog).PerformOkAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPreventSwitchDueToUnsavedChanges()
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
PromptForSaveDialog saveDialog = null;
|
||||||
|
|
||||||
|
AddStep("remove first hitobject", () => EditorBeatmap.RemoveAt(0));
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo)));
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
|
||||||
|
AddUntilStep("prompt for save dialog shown", () =>
|
||||||
|
{
|
||||||
|
saveDialog = this.ChildrenOfType<PromptForSaveDialog>().Single();
|
||||||
|
return saveDialog != null;
|
||||||
|
});
|
||||||
|
AddStep("continue editing", () =>
|
||||||
|
{
|
||||||
|
var continueButton = saveDialog.ChildrenOfType<PopupDialogCancelButton>().Last();
|
||||||
|
continueButton.TriggerClick();
|
||||||
|
});
|
||||||
|
|
||||||
|
confirmEditingBeatmap(() => importedBeatmapSet.Beatmaps.First());
|
||||||
|
|
||||||
|
AddRepeatStep("exit editor forcefully", () => Stack.Exit(), 2);
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestAllowSwitchAfterDiscardingUnsavedChanges()
|
||||||
|
{
|
||||||
|
BeatmapInfo targetDifficulty = null;
|
||||||
|
PromptForSaveDialog saveDialog = null;
|
||||||
|
|
||||||
|
AddStep("remove first hitobject", () => EditorBeatmap.RemoveAt(0));
|
||||||
|
|
||||||
|
AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo)));
|
||||||
|
switchToDifficulty(() => targetDifficulty);
|
||||||
|
|
||||||
|
AddUntilStep("prompt for save dialog shown", () =>
|
||||||
|
{
|
||||||
|
saveDialog = this.ChildrenOfType<PromptForSaveDialog>().Single();
|
||||||
|
return saveDialog != null;
|
||||||
|
});
|
||||||
|
AddStep("discard changes", () =>
|
||||||
|
{
|
||||||
|
var continueButton = saveDialog.ChildrenOfType<PopupDialogOkButton>().Single();
|
||||||
|
continueButton.TriggerClick();
|
||||||
|
});
|
||||||
|
|
||||||
|
confirmEditingBeatmap(() => targetDifficulty);
|
||||||
|
|
||||||
|
AddStep("exit editor forcefully", () => Stack.Exit());
|
||||||
|
// ensure editor loader didn't resume.
|
||||||
|
AddAssert("stack empty", () => Stack.CurrentScreen == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void switchToDifficulty(Func<BeatmapInfo> difficulty) => AddStep("switch to difficulty", () => Editor.SwitchToDifficulty(difficulty.Invoke()));
|
||||||
|
|
||||||
|
private void confirmEditingBeatmap(Func<BeatmapInfo> targetDifficulty)
|
||||||
|
{
|
||||||
|
AddUntilStep("current beatmap is correct", () => Beatmap.Value.BeatmapInfo.Equals(targetDifficulty.Invoke()));
|
||||||
|
AddUntilStep("current screen is editor", () => Stack.CurrentScreen == Editor && Editor?.IsLoaded == true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|