1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-01 18:09:58 +08:00

Compare commits

...

3389 Commits

1300 changed files with 107816 additions and 88912 deletions
+24 -19
View File
@@ -1,19 +1,24 @@
# This won't normalise line endings, but it will ensure that merge drivers use CRLF # Autodetect text files and ensure that we normalise their
* -text eol=crlf # line endings to lf internally. When checked out they may
# use different line endings.
# Currently in-use binary file extensions * text=auto
*.blend binary
*.bmp binary # Check out with crlf (Windows) line endings
*.dll binary *.sln text eol=crlf
*.exe binary *.csproj text eol=crlf
*.icns binary *.cs text diff=csharp eol=crlf
*.ico binary *.resx text eol=crlf
*.jpg binary *.vsixmanifest text eol=crlf
*.osz2 binary packages.config text eol=crlf
*.pdn binary App.config text eol=crlf
*.psd binary *.bat text eol=crlf
*.PSD binary *.cmd text eol=crlf
*.tga binary *.snippet text eol=crlf
*.ttf binary *.manifest text eol=crlf
*.wav binary
*.xnb binary # Check out with lf (UNIX) line endings
*.sh text eol=lf
.gitignore text eol=lf
.gitattributes text eol=lf
*.md text eol=lf
.travis.yml text eol=lf
+8
View File
@@ -0,0 +1,8 @@
Add any details pertaining to developers above the break.
- [ ] Depends on #PR
- Closes #ISSUE
---
Add a sentence or two describing this change in plain english. This will be displayed on the [changelog](https://osu.ppy.sh/home/changelog). A single screenshot or short gif is also welcomed.
+259 -259
View File
@@ -1,259 +1,259 @@
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons. ## files generated by popular Visual Studio add-ons.
# User-specific files # User-specific files
*.suo *.suo
*.user *.user
*.userosscache *.userosscache
*.sln.docstates *.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio) # User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs *.userprefs
# Build results # Build results
bin/[Dd]ebug/ bin/[Dd]ebug/
[Dd]ebugPublic/ [Dd]ebugPublic/
[Rr]elease/ [Rr]elease/
[Rr]eleases/ [Rr]eleases/
bld/ bld/
[Bb]in/ [Bb]in/
[Oo]bj/ [Oo]bj/
[Ll]og/ [Ll]og/
# Visual Studio 2015 cache/options directory # Visual Studio 2015 cache/options directory
.vs/ .vs/
# Uncomment if you have tasks that create the project's static files in wwwroot # Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/ #wwwroot/
# MSTest test Results # MSTest test Results
[Tt]est[Rr]esult*/ [Tt]est[Rr]esult*/
[Bb]uild[Ll]og.* [Bb]uild[Ll]og.*
# NUNIT # NUNIT
*.VisualState.xml *.VisualState.xml
TestResult.xml TestResult.xml
# Build Results of an ATL Project # Build Results of an ATL Project
[Dd]ebugPS/ [Dd]ebugPS/
[Rr]eleasePS/ [Rr]eleasePS/
dlldata.c dlldata.c
# DNX # DNX
project.lock.json project.lock.json
project.fragment.lock.json project.fragment.lock.json
artifacts/ artifacts/
*_i.c *_i.c
*_p.c *_p.c
*_i.h *_i.h
*.ilk *.ilk
*.meta *.meta
*.obj *.obj
*.pch *.pch
*.pdb *.pdb
*.pgc *.pgc
*.pgd *.pgd
*.rsp *.rsp
*.sbr *.sbr
*.tlb *.tlb
*.tli *.tli
*.tlh *.tlh
*.tmp *.tmp
*.tmp_proj *.tmp_proj
*.log *.log
*.vspscc *.vspscc
*.vssscc *.vssscc
.builds .builds
*.pidb *.pidb
*.svclog *.svclog
*.scc *.scc
# Chutzpah Test files # Chutzpah Test files
_Chutzpah* _Chutzpah*
# Visual C++ cache files # Visual C++ cache files
ipch/ ipch/
*.aps *.aps
*.ncb *.ncb
*.opendb *.opendb
*.opensdf *.opensdf
*.sdf *.sdf
*.cachefile *.cachefile
*.VC.db *.VC.db
*.VC.VC.opendb *.VC.VC.opendb
# Visual Studio profiler # Visual Studio profiler
*.psess *.psess
*.vsp *.vsp
*.vspx *.vspx
*.sap *.sap
# TFS 2012 Local Workspace # TFS 2012 Local Workspace
$tf/ $tf/
# Guidance Automation Toolkit # Guidance Automation Toolkit
*.gpState *.gpState
# ReSharper is a .NET coding add-in # ReSharper is a .NET coding add-in
_ReSharper*/ _ReSharper*/
*.[Rr]e[Ss]harper *.[Rr]e[Ss]harper
*.DotSettings.user *.DotSettings.user
# JustCode is a .NET coding add-in # JustCode is a .NET coding add-in
.JustCode .JustCode
# TeamCity is a build add-in # TeamCity is a build add-in
_TeamCity* _TeamCity*
# DotCover is a Code Coverage Tool # DotCover is a Code Coverage Tool
*.dotCover *.dotCover
# NCrunch # NCrunch
_NCrunch_* _NCrunch_*
.*crunch*.local.xml .*crunch*.local.xml
nCrunchTemp_* nCrunchTemp_*
# MightyMoose # MightyMoose
*.mm.* *.mm.*
AutoTest.Net/ AutoTest.Net/
# Web workbench (sass) # Web workbench (sass)
.sass-cache/ .sass-cache/
# Installshield output folder # Installshield output folder
[Ee]xpress/ [Ee]xpress/
# DocProject is a documentation generator add-in # DocProject is a documentation generator add-in
DocProject/buildhelp/ DocProject/buildhelp/
DocProject/Help/*.HxT DocProject/Help/*.HxT
DocProject/Help/*.HxC DocProject/Help/*.HxC
DocProject/Help/*.hhc DocProject/Help/*.hhc
DocProject/Help/*.hhk DocProject/Help/*.hhk
DocProject/Help/*.hhp DocProject/Help/*.hhp
DocProject/Help/Html2 DocProject/Help/Html2
DocProject/Help/html DocProject/Help/html
# Click-Once directory # Click-Once directory
publish/ publish/
# Publish Web Output # Publish Web Output
*.[Pp]ublish.xml *.[Pp]ublish.xml
*.azurePubxml *.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings # TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted # but database connection strings (with potential passwords) will be unencrypted
*.pubxml *.pubxml
*.publishproj *.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to # Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained # checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted # in these scripts will be unencrypted
PublishScripts/ PublishScripts/
# NuGet Packages # NuGet Packages
*.nupkg *.nupkg
# The packages folder can be ignored because of Package Restore # The packages folder can be ignored because of Package Restore
**/packages/* **/packages/*
# except build/, which is used as an MSBuild target. # except build/, which is used as an MSBuild target.
!**/packages/build/ !**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed # Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config #!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files # NuGet v3's project.json files produces more ignoreable files
*.nuget.props *.nuget.props
*.nuget.targets *.nuget.targets
# Microsoft Azure Build Output # Microsoft Azure Build Output
csx/ csx/
*.build.csdef *.build.csdef
# Microsoft Azure Emulator # Microsoft Azure Emulator
ecf/ ecf/
rcf/ rcf/
# Windows Store app package directories and files # Windows Store app package directories and files
AppPackages/ AppPackages/
BundleArtifacts/ BundleArtifacts/
Package.StoreAssociation.xml Package.StoreAssociation.xml
_pkginfo.txt _pkginfo.txt
# Visual Studio cache files # Visual Studio cache files
# files ending in .cache can be ignored # files ending in .cache can be ignored
*.[Cc]ache *.[Cc]ache
# but keep track of directories ending in .cache # but keep track of directories ending in .cache
!*.[Cc]ache/ !*.[Cc]ache/
# Others # Others
ClientBin/ ClientBin/
~$* ~$*
*~ *~
*.dbmdl *.dbmdl
*.dbproj.schemaview *.dbproj.schemaview
*.pfx *.pfx
*.publishsettings *.publishsettings
node_modules/ node_modules/
orleans.codegen.cs orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components # Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/ #bower_components/
# RIA/Silverlight projects # RIA/Silverlight projects
Generated_Code/ Generated_Code/
# Backup & report files from converting an old project file # Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed, # to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-) # because we have git ;-)
_UpgradeReport_Files/ _UpgradeReport_Files/
Backup*/ Backup*/
UpgradeLog*.XML UpgradeLog*.XML
UpgradeLog*.htm UpgradeLog*.htm
# SQL Server files # SQL Server files
*.mdf *.mdf
*.ldf *.ldf
# Business Intelligence projects # Business Intelligence projects
*.rdl.data *.rdl.data
*.bim.layout *.bim.layout
*.bim_*.settings *.bim_*.settings
# Microsoft Fakes # Microsoft Fakes
FakesAssemblies/ FakesAssemblies/
# GhostDoc plugin setting file # GhostDoc plugin setting file
*.GhostDoc.xml *.GhostDoc.xml
# Node.js Tools for Visual Studio # Node.js Tools for Visual Studio
.ntvs_analysis.dat .ntvs_analysis.dat
# Visual Studio 6 build log # Visual Studio 6 build log
*.plg *.plg
# Visual Studio 6 workspace options file # Visual Studio 6 workspace options file
*.opt *.opt
# Visual Studio LightSwitch build output # Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts **/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml **/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts **/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml **/*.Server/ModelManifest.xml
_Pvt_Extensions _Pvt_Extensions
# Paket dependency manager # Paket dependency manager
.paket/paket.exe .paket/paket.exe
paket-files/ paket-files/
# FAKE - F# Make # FAKE - F# Make
.fake/ .fake/
# JetBrains Rider # JetBrains Rider
.idea/ .idea/
*.sln.iml *.sln.iml
# CodeRush # CodeRush
.cr/ .cr/
# Python Tools for Visual Studio (PTVS) # Python Tools for Visual Studio (PTVS)
__pycache__/ __pycache__/
*.pyc *.pyc
Staging/ Staging/
+1 -4
View File
@@ -1,6 +1,3 @@
[submodule "osu-framework"]
path = osu-framework
url = https://github.com/ppy/osu-framework
[submodule "osu-resources"] [submodule "osu-resources"]
path = osu-resources path = osu-resources
url = https://github.com/ppy/osu-resources url = https://github.com/ppy/osu-resources
@@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (catch)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (mania)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Mania.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (osu!)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Osu.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
@@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="RulesetTests (taiko)" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Taiko.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<browser url="http://localhost:5000" />
<method />
</configuration>
</component>
+17
View File
@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="VisualTests" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tests" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Tests/osu.Game.Tests.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<method />
</configuration>
</component>
+17
View File
@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="osu!" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v2.1" />
<method />
</configuration>
</component>
+1 -1
View File
@@ -1,2 +1,2 @@
language: csharp language: csharp
solution: osu.sln solution: osu.sln
+44 -37
View File
@@ -1,65 +1,72 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [{ "configurations": [
"name": "osu! VisualTests (Debug)", {
"windows": { "name": "VisualTests (Debug)",
"type": "clr" "type": "coreclr",
},
"type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe", "program": "dotnet",
"args": [ "args": [
"--tests" "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1/osu.Game.Tests.dll"
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)", "preLaunchTask": "Build tests (Debug)",
"runtimeExecutable": null, "linux": {
"env": {}, "env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! VisualTests (Release)", "name": "VisualTests (Release)",
"windows": { "type": "coreclr",
"type": "clr"
},
"type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe", "program": "dotnet",
"args": [ "args": [
"--tests" "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1/osu.Game.Tests.dll"
], ],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)", "preLaunchTask": "Build tests (Release)",
"runtimeExecutable": null, "linux": {
"env": {}, "env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! (Debug)", "name": "osu! (Debug)",
"windows": { "type": "coreclr",
"type": "clr"
},
"type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe", "program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1/osu!.dll",
],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug)", "preLaunchTask": "Build osu! (Debug)",
"runtimeExecutable": null, "linux": {
"env": {}, "env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"console": "internalConsole" "console": "internalConsole"
}, },
{ {
"name": "osu! (Release)", "name": "osu! (Release)",
"windows": { "type": "coreclr",
"type": "clr"
},
"type": "mono",
"request": "launch", "request": "launch",
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe", "program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1/osu!.dll",
],
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release)", "preLaunchTask": "Build osu! (Release)",
"runtimeExecutable": null, "linux": {
"env": {}, "env": {
"LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp2.1:${env:LD_LIBRARY_PATH}"
}
},
"console": "internalConsole" "console": "internalConsole"
} }
] ]
-3
View File
@@ -1,3 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
}
+54 -43
View File
@@ -2,70 +2,81 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558 // See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format // for the documentation about the tasks.json format
"version": "2.0.0", "version": "2.0.0",
"tasks": [{ "tasks": [
"label": "Build (Debug)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:GenerateFullPaths=true",
"/p:DebugType=portable",
"/m",
"/v:m"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$msCompile"
},
{ {
"label": "Build (Release)", "label": "Build osu! (Debug)",
"type": "shell", "type": "shell",
"command": "msbuild", "command": "dotnet",
"args": [ "args": [
"/p:Configuration=Release", "build",
"/p:DebugType=portable", "--no-restore",
"osu.Desktop",
"/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/m", "/m",
"/v:m" "/verbosity:m"
], ],
"group": "build", "group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Clean (Debug)", "label": "Build osu! (Release)",
"type": "shell", "type": "shell",
"command": "msbuild", "command": "dotnet",
"args": [
"/p:DebugType=portable",
"/p:GenerateFullPaths=true",
"/m",
"/t:Clean",
"/v:m"
],
"problemMatcher": "$msCompile"
},
{
"label": "Clean (Release)",
"type": "shell",
"command": "msbuild",
"args": [ "args": [
"build",
"--no-restore",
"osu.Desktop",
"/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release", "/p:Configuration=Release",
"/p:GenerateFullPaths=true", "/p:GenerateFullPaths=true",
"/p:DebugType=portable",
"/m", "/m",
"/t:Clean", "/verbosity:m"
"/v:m"
], ],
"group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Clean All", "label": "Build tests (Debug)",
"dependsOn": [ "type": "shell",
"Clean (Debug)", "command": "dotnet",
"Clean (Release)" "args": [
"build",
"--no-restore",
"osu.Game.Tests",
"/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
], ],
"group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
},
{
"label": "Build tests (Release)",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"--no-restore",
"osu.Game.Tests",
"/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Restore (netcoreapp2.1)",
"type": "shell",
"command": "dotnet",
"args": [
"restore"
],
"problemMatcher": []
} }
] ]
} }
-36
View File
@@ -1,36 +0,0 @@
# Linux
### 1. Requirements:
Mono >= 5.4.0 (>= 5.8.0 recommended)
Please check [here](http://www.mono-project.com/download/) for stable or [here](http://www.mono-project.com/download/alpha/) for an alpha release.
NuGet >= 4.4.0
msbuild
git
### 2. Cloning project
Clone the entire repository with submodules using
```
git clone https://github.com/ppy/osu --recursive
```
Then restore NuGet packages from the repository
```
nuget restore
```
### 3. Compiling
Simply run `msbuild` where `osu.sln` is located, this will create all binaries in `osu/osu.Desktop/bin/Debug`.
### 4. Optimizing
If you want additional performance you can change build type to Release with
```
msbuild -p:Configuration=Release
```
Additionally, mono provides an AOT utility which attempts to precompile binaries. You can utilize that by running
```
mono --aot ./osu\!.exe
```
### 5. Troubleshooting
You may run into trouble with NuGet versioning, as the one in packaging system is almost always out of date. Simply run
```
nuget
sudo nuget update -self
```
**Warning** NuGet creates few config files when it's run for the first time.
Do not run NuGet as root on the first run or you might run into very peculiar issues.
+7 -5
View File
@@ -1,9 +1,11 @@
osu!lazer is currently in early stages of development and is not yet ready for end users. Please avoid creating issues or bugs if you do not personally intend to fix them. Some acceptable topics include: osu!lazer is currently still under heavy development!
Please ensure that you are making an issue for one of the following:
- A bug with currently implemented features (not features that don't exist)
- A feature you are considering adding, so we can collaborate on feedback and design.
- Discussions about technical design decisions - Discussions about technical design decisions
- Bugs that you have found and are personally willing and able to fix
- TODO lists of smaller tasks around larger features
Basically, issues are not a place for you to get help. They are a place for developers to collaborate on the game.
If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide. If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide.
Screenshots and log files are highly welcomed.
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -8,7 +8,7 @@ This is still heavily under development and is not intended for end-user use. Th
# Requirements # Requirements
- A desktop platform that can compile .NET 4.6.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here. - A desktop platform that can compile .NET 4.7.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
# Getting Started # Getting Started
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`) - Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
@@ -1,57 +1,46 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<assemblyIdentity version="1.0.0.0" name="osu!" /> <assemblyIdentity version="1.0.0.0" name="osu!" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security> <security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options <requestedExecutionLevel level="asInvoker" uiAccess="false" />
If you want to change the Windows User Account Control level replace the </requestedPrivileges>
requestedExecutionLevel node with one of the following. <applicationRequestMinimum>
<defaultAssemblyRequest permissionSetReference="Custom" />
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </applicationRequestMinimum>
<requestedExecutionLevel level="highestAvailable" uiAccess="false" /> </security>
</trustInfo>
If you want to utilize File and Registry Virtualization for backward <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
compatibility then delete the requestedExecutionLevel node. <application>
--> <!-- Windows Vista -->
<requestedExecutionLevel level="asInvoker" uiAccess="false" /> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
</requestedPrivileges> <!-- Windows 7 -->
<applicationRequestMinimum> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<defaultAssemblyRequest permissionSetReference="Custom" /> <!-- Windows 8 -->
<PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true" ID="Custom" SameSite="site" /> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
</applicationRequestMinimum> <!-- Windows 8.1 -->
</security> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
</trustInfo> <!-- Windows 10 -->
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
<application> </application>
<!-- Windows Vista --> </compatibility>
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /> <asmv3:application>
<!-- Windows 7 --> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /> <dpiAware>true</dpiAware>
<!-- Windows 8 --> </asmv3:windowsSettings>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> </asmv3:application>
<!-- Windows 8.1 --> <dependency>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> <dependentAssembly>
<!-- Windows 10 --> <assemblyIdentity
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> type="win32"
</application> name="Microsoft.Windows.Common-Controls"
</compatibility> version="6.0.0.0"
<asmv3:application> processorArchitecture="*"
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings"> publicKeyToken="6595b64144ccf1df"
<dpiAware>true</dpiAware> language="*"
</asmv3:windowsSettings> />
</asmv3:application> </dependentAssembly>
<dependency> </dependency>
<dependentAssembly> </asmv1:assembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</asmv1:assembly>
+20 -24
View File
@@ -1,25 +1,21 @@
# 2017-09-14 clone_depth: 1
clone_depth: 1 version: '{branch}-{build}'
version: '{branch}-{build}' image: Visual Studio 2017
image: Visual Studio 2017 configuration: Debug
configuration: Debug install:
cache: - cmd: git submodule update --init --recursive --depth=5
- C:\ProgramData\chocolatey\bin -> appveyor.yml - cmd: choco install resharper-clt -y
- C:\ProgramData\chocolatey\lib -> appveyor.yml - cmd: choco install nvika -y
- inspectcode -> appveyor.yml - cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.5/CodeFileSanity.exe
- packages -> **\packages.config before_build:
install: - cmd: CodeFileSanity.exe
- cmd: git submodule update --init --recursive --depth=5 - cmd: nuget restore -verbosity quiet
- cmd: choco install resharper-clt -y environment:
- cmd: choco install nvika -y TargetFramework: net471
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.3/CodeFileSanity.exe build:
before_build: project: osu.sln
- cmd: CodeFileSanity.exe parallel: true
- cmd: nuget restore -verbosity quiet verbosity: minimal
build: after_build:
project: osu.sln - cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
parallel: true
verbosity: minimal
after_build:
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
+32
View File
@@ -0,0 +1,32 @@
clone_depth: 1
version: '{build}'
skip_non_tags: true
image: Visual Studio 2017
install:
- git clone https://github.com/ppy/osu-deploy
before_build:
- ps: if($env:appveyor_repo_tag -eq 'True') { Update-AppveyorBuild -Version $env:appveyor_repo_tag_name }
- cmd: git submodule update --init --recursive --depth=5
- cmd: nuget restore -verbosity quiet
build_script:
- ps: iex ((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/appveyor/secure-file/master/install.ps1'))
- appveyor DownloadFile https://puu.sh/A6g5K/4d08705438.enc # signing certificate
- cmd: appveyor-tools\secure-file -decrypt 4d08705438.enc -secret %decode_secret% -out %HOMEPATH%\deanherbert.pfx
- appveyor DownloadFile https://puu.sh/A6g75/fdc6f19b04.enc # deploy configuration
- cd osu-deploy
- nuget restore -verbosity quiet
- msbuild osu.Desktop.Deploy.csproj
- cmd: ..\appveyor-tools\secure-file -decrypt ..\fdc6f19b04.enc -secret %decode_secret% -out bin\Debug\net471\osu.Desktop.Deploy.exe.config
- cd bin\Debug\net471\
- osu.Desktop.Deploy.exe %code_signing_password% %APPVEYOR_REPO_TAG_NAME%
environment:
TargetFramework: net471
decode_secret:
secure: i67IC2xj6DjjxmA6Oj2jing3+MwzLkq6CbGsjfZ7rdY=
code_signing_password:
secure: 34tLNqvjmmZEi97MLKfrnQ==
artifacts:
- path: 'Releases\*'
deploy:
- provider: Environment
name: github
Submodule osu-framework deleted from 8f36ddab94
-40
View File
@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<configuration>
<appSettings>
<add key="StagingFolder" value="Staging" />
<add key="ReleasesFolder" value="Releases" />
<add key="GitHubAccessToken" value="" />
<add key="GitHubUsername" value="ppy" />
<add key="GitHubRepoName" value="osu" />
<add key="ProjectName" value="osu.Desktop" />
<add key="NuSpecName" value="osu.Desktop\osu.nuspec" />
<add key="SolutionName" value="osu" />
<add key="TargetName" value="osu.Desktop" />
<add key="PackageName" value="osulazer" />
<add key="IconName" value="lazer.ico" />
<add key="CodeSigningCertificate" value="" />
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="DeltaCompressionDotNet.MsDelta" publicKeyToken="46b2138a390abf55" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
-28
View File
@@ -1,28 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
namespace osu.Desktop.Deploy
{
public class GitHubRelease
{
[JsonProperty(@"id")]
public int Id;
[JsonProperty(@"tag_name")]
public string TagName => $"v{Name}";
[JsonProperty(@"name")]
public string Name;
[JsonProperty(@"draft")]
public bool Draft;
[JsonProperty(@"prerelease")]
public bool PreRelease;
[JsonProperty(@"upload_url")]
public string UploadUrl;
}
}
-431
View File
@@ -1,431 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
using WebRequest = osu.Framework.IO.Network.WebRequest;
namespace osu.Desktop.Deploy
{
internal static class Program
{
private const string nuget_path = @"packages\NuGet.CommandLine.4.3.0\tools\NuGet.exe";
private const string squirrel_path = @"packages\squirrel.windows.1.7.8\tools\Squirrel.exe";
private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
public static string ReleasesFolder = ConfigurationManager.AppSettings["ReleasesFolder"];
public static string GitHubAccessToken = ConfigurationManager.AppSettings["GitHubAccessToken"];
public static string GitHubUsername = ConfigurationManager.AppSettings["GitHubUsername"];
public static string GitHubRepoName = ConfigurationManager.AppSettings["GitHubRepoName"];
public static string SolutionName = ConfigurationManager.AppSettings["SolutionName"];
public static string ProjectName = ConfigurationManager.AppSettings["ProjectName"];
public static string NuSpecName = ConfigurationManager.AppSettings["NuSpecName"];
public static string TargetNames = ConfigurationManager.AppSettings["TargetName"];
public static string PackageName = ConfigurationManager.AppSettings["PackageName"];
public static string IconName = ConfigurationManager.AppSettings["IconName"];
public static string CodeSigningCertificate = ConfigurationManager.AppSettings["CodeSigningCertificate"];
public static string GitHubApiEndpoint => $"https://api.github.com/repos/{GitHubUsername}/{GitHubRepoName}/releases";
public static string GitHubReleasePage => $"https://github.com/{GitHubUsername}/{GitHubRepoName}/releases";
/// <summary>
/// How many previous build deltas we want to keep when publishing.
/// </summary>
private const int keep_delta_count = 3;
private static string codeSigningCmd => string.IsNullOrEmpty(codeSigningPassword) ? "" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\"";
private static string homeDir => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
private static string codeSigningCertPath => Path.Combine(homeDir, CodeSigningCertificate);
private static string solutionPath => Environment.CurrentDirectory;
private static string stagingPath => Path.Combine(solutionPath, StagingFolder);
private static string iconPath => Path.Combine(solutionPath, ProjectName, IconName);
private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
private static readonly Stopwatch sw = new Stopwatch();
private static string codeSigningPassword;
public static void Main(string[] args)
{
displayHeader();
findSolutionPath();
if (!Directory.Exists(ReleasesFolder))
{
write("WARNING: No release directory found. Make sure you want this!", ConsoleColor.Yellow);
Directory.CreateDirectory(ReleasesFolder);
}
checkGitHubReleases();
refreshDirectory(StagingFolder);
//increment build number until we have a unique one.
string verBase = DateTime.Now.ToString("yyyy.Mdd.");
int increment = 0;
while (Directory.GetFiles(ReleasesFolder, $"*{verBase}{increment}*").Any())
increment++;
string version = $"{verBase}{increment}";
Console.ForegroundColor = ConsoleColor.White;
Console.Write($"Ready to deploy {version}: ");
Console.ReadLine();
sw.Start();
if (!string.IsNullOrEmpty(CodeSigningCertificate))
{
Console.Write("Enter code signing password: ");
codeSigningPassword = readLineMasked();
}
write("Restoring NuGet packages...");
runCommand(nuget_path, "restore " + solutionPath);
write("Updating AssemblyInfo...");
updateAssemblyInfo(version);
write("Running build process...");
foreach (string targetName in TargetNames.Split(','))
runCommand(msbuild_path, $"/v:quiet /m /t:{targetName.Replace('.', '_')} /p:OutputPath={stagingPath};Targets=\"Clean;Build\";Configuration=Release {SolutionName}.sln");
write("Creating NuGet deployment package...");
runCommand(nuget_path, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");
//prune once before checking for files so we can avoid erroring on files which aren't even needed for this build.
pruneReleases();
checkReleaseFiles();
write("Running squirrel build...");
runCommand(squirrel_path, $"--releasify {stagingPath}\\{nupkgFilename(version)} --setupIcon {iconPath} --icon {iconPath} {codeSigningCmd} --no-msi");
//prune again to clean up before upload.
pruneReleases();
//rename setup to install.
File.Copy(Path.Combine(ReleasesFolder, "Setup.exe"), Path.Combine(ReleasesFolder, "install.exe"), true);
File.Delete(Path.Combine(ReleasesFolder, "Setup.exe"));
uploadBuild(version);
//reset assemblyinfo.
updateAssemblyInfo("0.0.0");
write("Done!", ConsoleColor.White);
Console.ReadLine();
}
private static void displayHeader()
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine();
Console.WriteLine(" Please note that OSU! and PPY are registered trademarks and as such covered by trademark law.");
Console.WriteLine(" Do not distribute builds of this project publicly that make use of these.");
Console.ResetColor();
Console.WriteLine();
}
/// <summary>
/// Ensure we have all the files in the release directory which are expected to be there.
/// This should have been accounted for in earlier steps, and just serves as a verification step.
/// </summary>
private static void checkReleaseFiles()
{
if (!canGitHub) return;
var releaseLines = getReleaseLines();
//ensure we have all files necessary
foreach (var l in releaseLines)
if (!File.Exists(Path.Combine(ReleasesFolder, l.Filename)))
error($"Local file missing {l.Filename}");
}
private static IEnumerable<ReleaseLine> getReleaseLines() => File.ReadAllLines(Path.Combine(ReleasesFolder, "RELEASES")).Select(l => new ReleaseLine(l));
private static void pruneReleases()
{
if (!canGitHub) return;
write("Pruning RELEASES...");
var releaseLines = getReleaseLines().ToList();
var fulls = releaseLines.Where(l => l.Filename.Contains("-full")).Reverse().Skip(1);
//remove any FULL releases (except most recent)
foreach (var l in fulls)
{
write($"- Removing old release {l.Filename}", ConsoleColor.Yellow);
File.Delete(Path.Combine(ReleasesFolder, l.Filename));
releaseLines.Remove(l);
}
//remove excess deltas
var deltas = releaseLines.Where(l => l.Filename.Contains("-delta")).ToArray();
if (deltas.Length > keep_delta_count)
{
foreach (var l in deltas.Take(deltas.Length - keep_delta_count))
{
write($"- Removing old delta {l.Filename}", ConsoleColor.Yellow);
File.Delete(Path.Combine(ReleasesFolder, l.Filename));
releaseLines.Remove(l);
}
}
var lines = new List<string>();
releaseLines.ForEach(l => lines.Add(l.ToString()));
File.WriteAllLines(Path.Combine(ReleasesFolder, "RELEASES"), lines);
}
private static void uploadBuild(string version)
{
if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
return;
write("Publishing to GitHub...");
write($"- Creating release {version}...", ConsoleColor.Yellow);
var req = new JsonWebRequest<GitHubRelease>($"{GitHubApiEndpoint}")
{
Method = HttpMethod.POST,
};
req.AddRaw(JsonConvert.SerializeObject(new GitHubRelease
{
Name = version,
Draft = true,
PreRelease = true
}));
req.AuthenticatedBlockingPerform();
var assetUploadUrl = req.ResponseObject.UploadUrl.Replace("{?name,label}", "?name={0}");
foreach (var a in Directory.GetFiles(ReleasesFolder).Reverse()) //reverse to upload RELEASES first.
{
write($"- Adding asset {a}...", ConsoleColor.Yellow);
var upload = new WebRequest(assetUploadUrl, Path.GetFileName(a))
{
Method = HttpMethod.POST,
Timeout = 240000,
ContentType = "application/octet-stream",
};
upload.AddRaw(File.ReadAllBytes(a));
upload.AuthenticatedBlockingPerform();
}
openGitHubReleasePage();
}
private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
private static void checkGitHubReleases()
{
if (!canGitHub) return;
write("Checking GitHub releases...");
var req = new JsonWebRequest<List<GitHubRelease>>($"{GitHubApiEndpoint}");
req.AuthenticatedBlockingPerform();
var lastRelease = req.ResponseObject.FirstOrDefault();
if (lastRelease == null)
return;
if (lastRelease.Draft)
{
openGitHubReleasePage();
error("There's a pending draft release! You probably don't want to push a build with this present.");
}
//there's a previous release for this project.
var assetReq = new JsonWebRequest<List<GitHubObject>>($"{GitHubApiEndpoint}/{lastRelease.Id}/assets");
assetReq.AuthenticatedBlockingPerform();
var assets = assetReq.ResponseObject;
//make sure our RELEASES file is the same as the last build on the server.
var releaseAsset = assets.FirstOrDefault(a => a.Name == "RELEASES");
//if we don't have a RELEASES asset then the previous release likely wasn't a Squirrel one.
if (releaseAsset == null) return;
write($"Last GitHub release was {lastRelease.Name}.");
bool requireDownload = false;
if (!File.Exists(Path.Combine(ReleasesFolder, nupkgDistroFilename(lastRelease.Name))))
{
write("Last version's package not found locally.", ConsoleColor.Red);
requireDownload = true;
}
else
{
var lastReleases = new RawFileWebRequest($"{GitHubApiEndpoint}/assets/{releaseAsset.Id}");
lastReleases.AuthenticatedBlockingPerform();
if (File.ReadAllText(Path.Combine(ReleasesFolder, "RELEASES")) != lastReleases.ResponseString)
{
write("Server's RELEASES differed from ours.", ConsoleColor.Red);
requireDownload = true;
}
}
if (!requireDownload) return;
write("Refreshing local releases directory...");
refreshDirectory(ReleasesFolder);
foreach (var a in assets)
{
if (a.Name.EndsWith(".exe")) continue;
write($"- Downloading {a.Name}...", ConsoleColor.Yellow);
new FileWebRequest(Path.Combine(ReleasesFolder, a.Name), $"{GitHubApiEndpoint}/assets/{a.Id}").AuthenticatedBlockingPerform();
}
}
private static void refreshDirectory(string directory)
{
if (Directory.Exists(directory))
Directory.Delete(directory, true);
Directory.CreateDirectory(directory);
}
private static void updateAssemblyInfo(string version)
{
string file = Path.Combine(ProjectName, "Properties", "AssemblyInfo.cs");
var l1 = File.ReadAllLines(file);
List<string> l2 = new List<string>();
foreach (var l in l1)
{
if (l.StartsWith("[assembly: AssemblyVersion("))
l2.Add($"[assembly: AssemblyVersion(\"{version}\")]");
else if (l.StartsWith("[assembly: AssemblyFileVersion("))
l2.Add($"[assembly: AssemblyFileVersion(\"{version}\")]");
else
l2.Add(l);
}
File.WriteAllLines(file, l2);
}
/// <summary>
/// Find the base path of the active solution (git checkout location)
/// </summary>
private static void findSolutionPath()
{
string path = Path.GetDirectoryName(Environment.CommandLine.Replace("\"", "").Trim());
if (string.IsNullOrEmpty(path))
path = Environment.CurrentDirectory;
while (!File.Exists(Path.Combine(path, $"{SolutionName}.sln")))
path = path.Remove(path.LastIndexOf('\\'));
path += "\\";
Environment.CurrentDirectory = path;
}
private static bool runCommand(string command, string args)
{
var psi = new ProcessStartInfo(command, args)
{
WorkingDirectory = solutionPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
};
Process p = Process.Start(psi);
if (p == null) return false;
string output = p.StandardOutput.ReadToEnd();
output += p.StandardError.ReadToEnd();
if (p.ExitCode == 0) return true;
write(output);
error($"Command {command} {args} failed!");
return false;
}
private static string readLineMasked()
{
var fg = Console.ForegroundColor;
Console.ForegroundColor = Console.BackgroundColor;
var ret = Console.ReadLine();
Console.ForegroundColor = fg;
return ret;
}
private static void error(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"FATAL ERROR: {message}");
Console.ReadLine();
Environment.Exit(-1);
}
private static void write(string message, ConsoleColor col = ConsoleColor.Gray)
{
if (sw.ElapsedMilliseconds > 0)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(sw.ElapsedMilliseconds.ToString().PadRight(8));
}
Console.ForegroundColor = col;
Console.WriteLine(message);
}
public static void AuthenticatedBlockingPerform(this WebRequest r)
{
r.AddHeader("Authorization", $"token {GitHubAccessToken}");
r.Perform();
}
}
internal class RawFileWebRequest : WebRequest
{
public RawFileWebRequest(string url) : base(url)
{
}
protected override string Accept => "application/octet-stream";
}
internal class ReleaseLine
{
public string Hash;
public string Filename;
public int Filesize;
public ReleaseLine(string line)
{
var split = line.Split(' ');
Hash = split[0];
Filename = split[1];
Filesize = int.Parse(split[2]);
}
public override string ToString() => $"{Hash} {Filename} {Filesize}";
}
}
@@ -1,38 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu.Desktop.Deploy")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("osu.Desktop.Deploy")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("baea2f74-0315-4667-84e0-acac0b4bf785")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\osu.Game.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BAEA2F74-0315-4667-84E0-ACAC0B4BF785}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>osu.Desktop.Deploy</RootNamespace>
<AssemblyName>osu.Desktop.Deploy</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject>osu.Desktop.Deploy.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.1.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.1.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="GitHubObject.cs" />
<Compile Include="GitHubRelease.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
<Name>osu.Framework</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<packages>
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net452" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
<package id="NuGet.CommandLine" version="4.3.0" targetFramework="net461" developmentDependency="true" />
<package id="SharpCompress" version="0.18.1" targetFramework="net461" />
<package id="Splat" version="2.0.0" targetFramework="net452" />
<package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
</packages>
-25
View File
@@ -1,25 +0,0 @@
<configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
<!-- XQuartz compatibility (X11 on Mac) -->
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>
+121 -126
View File
@@ -1,126 +1,121 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Drawing; using System.IO;
using System.IO; using System.Linq;
using System.Linq; using System.Reflection;
using System.Reflection; using System.Threading.Tasks;
using System.Threading.Tasks; using osu.Desktop.Overlays;
using Microsoft.Win32; using osu.Framework.Graphics.Containers;
using osu.Desktop.Overlays; using osu.Framework.Platform;
using osu.Framework.Graphics.Containers; using osu.Game;
using osu.Framework.Platform; using OpenTK.Input;
using osu.Game; using Microsoft.Win32;
using OpenTK.Input; using osu.Framework.Platform.Windows;
namespace osu.Desktop namespace osu.Desktop
{ {
internal class OsuGameDesktop : OsuGame internal class OsuGameDesktop : OsuGame
{ {
private readonly bool noVersionOverlay; private readonly bool noVersionOverlay;
public OsuGameDesktop(string[] args = null) public OsuGameDesktop(string[] args = null)
: base(args) : base(args)
{ {
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false; noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
} }
public override Storage GetStorageForStableInstall() public override Storage GetStorageForStableInstall()
{ {
try try
{ {
return new StableStorage(); return new StableStorage();
} }
catch catch
{ {
return null; return null;
} }
} }
/// <summary> /// <summary>
/// A method of accessing an osu-stable install in a controlled fashion. /// A method of accessing an osu-stable install in a controlled fashion.
/// </summary> /// </summary>
private class StableStorage : DesktopStorage private class StableStorage : WindowsStorage
{ {
protected override string LocateBasePath() protected override string LocateBasePath()
{ {
bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs")); bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs"));
string stableInstallPath; string stableInstallPath;
try try
{ {
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu")) using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", ""); stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
if (checkExists(stableInstallPath)) if (checkExists(stableInstallPath))
return stableInstallPath; return stableInstallPath;
} }
catch catch
{ {
} }
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!"); stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
if (checkExists(stableInstallPath)) if (checkExists(stableInstallPath))
return stableInstallPath; return stableInstallPath;
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu"); stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
if (checkExists(stableInstallPath)) if (checkExists(stableInstallPath))
return stableInstallPath; return stableInstallPath;
return null; return null;
} }
public StableStorage() public StableStorage()
: base(string.Empty) : base(string.Empty, null)
{ {
} }
} }
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
if (!noVersionOverlay) if (!noVersionOverlay)
{ {
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v => LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{ {
Add(v); Add(v);
v.State = Visibility.Visible; v.State = Visibility.Visible;
}); });
} }
} }
public override void SetHost(GameHost host) public override void SetHost(GameHost host)
{ {
base.SetHost(host); base.SetHost(host);
var desktopWindow = host.Window as DesktopGameWindow; var desktopWindow = host.Window as DesktopGameWindow;
if (desktopWindow != null) if (desktopWindow != null)
{ {
desktopWindow.CursorState |= CursorState.Hidden; desktopWindow.CursorState |= CursorState.Hidden;
desktopWindow.Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico")); desktopWindow.SetIconFromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
desktopWindow.Title = Name; desktopWindow.Title = Name;
desktopWindow.FileDrop += fileDrop; desktopWindow.FileDrop += fileDrop;
} }
} }
private void fileDrop(object sender, FileDropEventArgs e) private void fileDrop(object sender, FileDropEventArgs e)
{ {
var filePaths = new [] { e.FileName }; var filePaths = new[] { e.FileName };
if (filePaths.All(f => Path.GetExtension(f) == @".osz")) var firstExtension = Path.GetExtension(filePaths.First());
Task.Factory.StartNew(() => BeatmapManager.Import(filePaths), TaskCreationOptions.LongRunning);
else if (filePaths.All(f => Path.GetExtension(f) == @".osr")) if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
Task.Run(() =>
{ Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
var score = ScoreStore.ReadReplayFile(filePaths.First()); }
Schedule(() => LoadScore(score)); }
}); }
}
private static readonly string[] allowed_extensions = { @".osz", @".osr" };
}
}
@@ -0,0 +1,164 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
#if NET_FRAMEWORK
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging;
using osu.Game;
using osu.Game.Graphics;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using OpenTK;
using OpenTK.Graphics;
using Squirrel;
namespace osu.Desktop.Overlays
{
public class SquirrelUpdateManager : Component
{
private UpdateManager updateManager;
private NotificationOverlay notificationOverlay;
public void PrepareUpdate()
{
// Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
UpdateManager.RestartAppWhenExited().Wait();
}
[BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuGameBase game)
{
notificationOverlay = notification;
if (game.IsDeployedBuild)
Schedule(() => checkForUpdateAsync());
}
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
{
//should we schedule a retry on completion of this check?
bool scheduleRetry = true;
try
{
if (updateManager == null) updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
var info = await updateManager.CheckForUpdate(!useDeltaPatching);
if (info.ReleasesToApply.Count == 0)
//no updates available. bail and retry later.
return;
if (notification == null)
{
notification = new UpdateProgressNotification(this) { State = ProgressNotificationState.Active };
Schedule(() => notificationOverlay.Post(notification));
}
notification.Progress = 0;
notification.Text = @"Downloading update...";
try
{
await updateManager.DownloadReleases(info.ReleasesToApply, p => notification.Progress = p / 100f);
notification.Progress = 0;
notification.Text = @"Installing update...";
await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f);
notification.State = ProgressNotificationState.Completed;
}
catch (Exception e)
{
if (useDeltaPatching)
{
Logger.Error(e, @"delta patching failed!");
//could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
//try again without deltas.
checkForUpdateAsync(false, notification);
scheduleRetry = false;
}
else
{
Logger.Error(e, @"update failed!");
}
}
}
catch (Exception)
{
// we'll ignore this and retry later. can be triggered by no internet connection or thread abortion.
}
finally
{
if (scheduleRetry)
{
if (notification != null)
notification.State = ProgressNotificationState.Cancelled;
//check again in 30 minutes.
Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
}
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
updateManager?.Dispose();
}
private class UpdateProgressNotification : ProgressNotification
{
private readonly SquirrelUpdateManager updateManager;
private OsuGame game;
public UpdateProgressNotification(SquirrelUpdateManager updateManager)
{
this.updateManager = updateManager;
}
protected override Notification CreateCompletionNotification()
{
return new ProgressCompletionNotification
{
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
updateManager.PrepareUpdate();
game.GracefullyExit();
return true;
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, OsuGame game)
{
this.game = game;
IconContent.AddRange(new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
},
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_upload,
Colour = Color4.White,
Size = new Vector2(20),
}
});
}
}
}
}
#endif
+145 -266
View File
@@ -1,266 +1,145 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Diagnostics; using osu.Framework.Allocation;
using osu.Framework.Allocation; using osu.Framework.Graphics;
using osu.Framework.Development; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Containers; using osu.Framework.Platform;
using osu.Framework.Graphics.Shapes; using osu.Game;
using osu.Framework.Graphics.Sprites; using osu.Game.Configuration;
using osu.Framework.Graphics.Textures; using osu.Game.Graphics;
using osu.Framework.Logging; using osu.Game.Graphics.Sprites;
using osu.Game; using osu.Game.Overlays;
using osu.Game.Configuration; using osu.Game.Overlays.Notifications;
using osu.Game.Graphics; using osu.Game.Utils;
using osu.Game.Graphics.Sprites; using OpenTK;
using osu.Game.Overlays; using OpenTK.Graphics;
using osu.Game.Overlays.Notifications;
using OpenTK; namespace osu.Desktop.Overlays
using OpenTK.Graphics; {
using Squirrel; public class VersionManager : OverlayContainer
{
namespace osu.Desktop.Overlays private OsuConfigManager config;
{ private OsuGameBase game;
public class VersionManager : OverlayContainer private NotificationOverlay notificationOverlay;
{ private GameHost host;
private UpdateManager updateManager;
private NotificationOverlay notificationOverlay; public override bool HandleKeyboardInput => false;
private OsuConfigManager config; public override bool HandleMouseInput => false;
private OsuGameBase game;
[BackgroundDependencyLoader]
public override bool HandleKeyboardInput => false; private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config, GameHost host)
public override bool HandleMouseInput => false; {
notificationOverlay = notification;
[BackgroundDependencyLoader] this.config = config;
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config) this.game = game;
{ this.host = host;
notificationOverlay = notification;
this.config = config; AutoSizeAxes = Axes.Both;
this.game = game; Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
AutoSizeAxes = Axes.Both;
Anchor = Anchor.BottomCentre; Alpha = 0;
Origin = Anchor.BottomCentre;
Children = new Drawable[]
Alpha = 0; {
new FillFlowContainer
Children = new Drawable[] {
{ AutoSizeAxes = Axes.Both,
new FillFlowContainer Direction = FillDirection.Vertical,
{ Children = new Drawable[]
AutoSizeAxes = Axes.Both, {
Direction = FillDirection.Vertical, new FillFlowContainer
Children = new Drawable[] {
{ AutoSizeAxes = Axes.Both,
new FillFlowContainer Direction = FillDirection.Horizontal,
{ Spacing = new Vector2(5),
AutoSizeAxes = Axes.Both, Anchor = Anchor.TopCentre,
Direction = FillDirection.Horizontal, Origin = Anchor.TopCentre,
Spacing = new Vector2(5), Children = new Drawable[]
Anchor = Anchor.TopCentre, {
Origin = Anchor.TopCentre, new OsuSpriteText
Children = new Drawable[] {
{ Font = @"Exo2.0-Bold",
new OsuSpriteText Text = game.Name
{ },
Font = @"Exo2.0-Bold", new OsuSpriteText
Text = game.Name {
}, Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
new OsuSpriteText Text = game.Version
{ },
Colour = DebugUtils.IsDebug ? colours.Red : Color4.White, }
Text = game.Version },
}, new OsuSpriteText
} {
}, Anchor = Anchor.TopCentre,
new OsuSpriteText Origin = Anchor.TopCentre,
{ TextSize = 12,
Anchor = Anchor.TopCentre, Colour = colours.Yellow,
Origin = Anchor.TopCentre, Font = @"Venera",
TextSize = 12, Text = @"Development Build"
Colour = colours.Yellow, },
Font = @"Venera", new Sprite
Text = @"Development Build" {
}, Anchor = Anchor.TopCentre,
new Sprite Origin = Anchor.TopCentre,
{ Texture = textures.Get(@"Menu/dev-build-footer"),
Anchor = Anchor.TopCentre, },
Origin = Anchor.TopCentre, }
Texture = textures.Get(@"Menu/dev-build-footer"), }
}, };
}
} #if NET_FRAMEWORK
}; Add(new SquirrelUpdateManager());
#endif
if (game.IsDeployedBuild) }
checkForUpdateAsync();
} protected override void LoadComplete()
{
protected override void LoadComplete() base.LoadComplete();
{
base.LoadComplete(); var version = game.Version;
var lastVersion = config.Get<string>(OsuSetting.Version);
var version = game.Version; if (game.IsDeployedBuild && version != lastVersion)
var lastVersion = config.Get<string>(OsuSetting.Version); {
if (game.IsDeployedBuild && version != lastVersion) config.Set(OsuSetting.Version, version);
{
config.Set(OsuSetting.Version, version); // only show a notification if we've previously saved a version to the config file (ie. not the first run).
if (!string.IsNullOrEmpty(lastVersion))
// only show a notification if we've previously saved a version to the config file (ie. not the first run). notificationOverlay.Post(new UpdateCompleteNotification(version, host.OpenUrlExternally));
if (!string.IsNullOrEmpty(lastVersion)) }
notificationOverlay.Post(new UpdateCompleteNotification(version)); }
}
} private class UpdateCompleteNotification : SimpleNotification
{
private class UpdateCompleteNotification : SimpleNotification public UpdateCompleteNotification(string version, Action<string> openUrl = null)
{ {
public UpdateCompleteNotification(string version) Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
{ Icon = FontAwesome.fa_check_square;
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!"; Activated = delegate
Icon = FontAwesome.fa_check_square; {
Activated = delegate openUrl?.Invoke($"https://osu.ppy.sh/home/changelog/lazer/{version}");
{ return true;
Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}"); };
return true; }
};
} [BackgroundDependencyLoader]
private void load(OsuColour colours)
[BackgroundDependencyLoader] {
private void load(OsuColour colours) IconBackgound.Colour = colours.BlueDark;
{ }
IconBackgound.Colour = colours.BlueDark; }
}
} protected override void PopIn()
{
protected override void Dispose(bool isDisposing) this.FadeIn(1000);
{ }
base.Dispose(isDisposing);
updateManager?.Dispose(); protected override void PopOut()
} {
}
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null) }
{ }
//should we schedule a retry on completion of this check?
bool scheduleRetry = true;
try
{
if (updateManager == null) updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
var info = await updateManager.CheckForUpdate(!useDeltaPatching);
if (info.ReleasesToApply.Count == 0)
//no updates available. bail and retry later.
return;
if (notification == null)
{
notification = new UpdateProgressNotification { State = ProgressNotificationState.Active };
Schedule(() => notificationOverlay.Post(notification));
}
Schedule(() =>
{
notification.Progress = 0;
notification.Text = @"Downloading update...";
});
try
{
await updateManager.DownloadReleases(info.ReleasesToApply, p => Schedule(() => notification.Progress = p / 100f));
Schedule(() =>
{
notification.Progress = 0;
notification.Text = @"Installing update...";
});
await updateManager.ApplyReleases(info, p => Schedule(() => notification.Progress = p / 100f));
Schedule(() => notification.State = ProgressNotificationState.Completed);
}
catch (Exception e)
{
if (useDeltaPatching)
{
Logger.Error(e, @"delta patching failed!");
//could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
//try again without deltas.
checkForUpdateAsync(false, notification);
scheduleRetry = false;
}
else
{
Logger.Error(e, @"update failed!");
}
}
}
catch (Exception)
{
// we'll ignore this and retry later. can be triggered by no internet connection or thread abortion.
}
finally
{
if (scheduleRetry)
{
//check again in 30 minutes.
Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
if (notification != null)
notification.State = ProgressNotificationState.Cancelled;
}
}
}
protected override void PopIn()
{
this.FadeIn(1000);
}
protected override void PopOut()
{
}
private class UpdateProgressNotification : ProgressNotification
{
private OsuGame game;
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification
{
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
// Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
UpdateManager.RestartAppWhenExited().Wait();
game.GracefullyExit();
return true;
}
};
[BackgroundDependencyLoader]
private void load(OsuColour colours, OsuGame game)
{
this.game = game;
IconContent.AddRange(new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
},
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = FontAwesome.fa_upload,
Colour = Color4.White,
Size = new Vector2(20),
}
});
}
}
}
}
+66 -51
View File
@@ -1,51 +1,66 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using osu.Framework; using osu.Framework;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.IPC; using osu.Game.IPC;
#if NET_FRAMEWORK
namespace osu.Desktop using System.Runtime;
{ #endif
public static class Program
{ namespace osu.Desktop
[STAThread] {
public static int Main(string[] args) public static class Program
{ {
// Back up the cwd before DesktopGameHost changes it [STAThread]
var cwd = Environment.CurrentDirectory; public static int Main(string[] args)
{
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true)) // required to initialise native SQLite libraries on some platforms.
{
if (!host.IsPrimaryInstance) if (!RuntimeInfo.IsMono)
{ useMulticoreJit();
var importer = new BeatmapIPCChannel(host);
// Restore the cwd so relative paths given at the command line work correctly // Back up the cwd before DesktopGameHost changes it
Directory.SetCurrentDirectory(cwd); var cwd = Environment.CurrentDirectory;
foreach (var file in args)
{ using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
Console.WriteLine(@"Importing {0}", file); {
if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000)) if (!host.IsPrimaryInstance)
throw new TimeoutException(@"IPC took too long to send"); {
} var importer = new ArchiveImportIPCChannel(host);
} // Restore the cwd so relative paths given at the command line work correctly
else Directory.SetCurrentDirectory(cwd);
{ foreach (var file in args)
switch (args.FirstOrDefault() ?? string.Empty) {
{ Console.WriteLine(@"Importing {0}", file);
case "--tests": if (!importer.ImportAsync(Path.GetFullPath(file)).Wait(3000))
host.Run(new OsuTestBrowser()); throw new TimeoutException(@"IPC took too long to send");
break; }
default: }
host.Run(new OsuGameDesktop(args)); else
break; {
} switch (args.FirstOrDefault() ?? string.Empty)
} {
return 0; default:
} host.Run(new OsuGameDesktop(args));
} break;
} }
} }
return 0;
}
}
private static void useMulticoreJit()
{
#if NET_FRAMEWORK
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
ProfileOptimization.SetProfileRoot(directory.FullName);
ProfileOptimization.StartProfile("Startup.Profile");
#endif
}
}
}
-28
View File
@@ -1,28 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("osu!lazer")]
[assembly: AssemblyDescription("click the circles. to the beat.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ppy Pty Ltd")]
[assembly: AssemblyProduct("osu!lazer")]
[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b0cb1d48-e4c2-4612-a347-beea7b1a71e7")]
[assembly: AssemblyVersion("0.0.0")]
[assembly: AssemblyFileVersion("0.0.0")]
-44
View File
@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
+38 -283
View File
@@ -1,284 +1,39 @@
<?xml version="1.0" encoding="utf-8"?> <Project Sdk="Microsoft.NET.Sdk">
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0"> <Import Project="..\osu.Game.props" />
<Import Project="..\osu.Game.props" /> <PropertyGroup Label="Project">
<PropertyGroup> <TargetFrameworks>net471;netcoreapp2.1</TargetFrameworks>
<ProjectGuid>{419659FD-72EA-4678-9EB8-B22A746CED70}</ProjectGuid> <OutputType>WinExe</OutputType>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <PlatformTarget>AnyCPU</PlatformTarget>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>WinExe</OutputType> <Description>click the circles. to the beat.</Description>
<AppDesignerFolder>Properties</AppDesignerFolder> <AssemblyName>osu!</AssemblyName>
<RootNamespace>osu.Desktop</RootNamespace> <Title>osu!lazer</Title>
<AssemblyName>osu!</AssemblyName> <Product>osu!lazer</Product>
<ManifestCertificateThumbprint>3CF060CD28877D0E3112948951A64B2A7CEEC909</ManifestCertificateThumbprint> <ApplicationIcon>lazer.ico</ApplicationIcon>
<ManifestKeyFile>codesigning.pfx</ManifestKeyFile> <Version>0.0.0</Version>
<GenerateManifests>false</GenerateManifests> <FileVersion>0.0.0</FileVersion>
<SignManifests>false</SignManifests> </PropertyGroup>
<IsWebBootstrapper>false</IsWebBootstrapper> <PropertyGroup Label="Defines">
<FileUpgradeFlags> <DefineConstants Condition="'$(TargetFramework)' == 'net471'">$(DefineConstants);NET_FRAMEWORK</DefineConstants>
</FileUpgradeFlags> </PropertyGroup>
<OldToolsVersion>3.5</OldToolsVersion> <PropertyGroup>
<UpgradeBackupLocation> <StartupObject>osu.Desktop.Program</StartupObject>
</UpgradeBackupLocation> </PropertyGroup>
<StartupObject>osu.Desktop.Program</StartupObject> <ItemGroup Label="Project References">
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent> <ProjectReference Include="..\osu.Game\osu.Game.csproj" />
<SignAssembly>false</SignAssembly> <ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj" />
<TargetZone>LocalIntranet</TargetZone> <ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion> <ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj" />
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj" />
<PublishUrl>publish\</PublishUrl> <ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj" />
<Install>true</Install> <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
<InstallFrom>Disk</InstallFrom> </ItemGroup>
<UpdateEnabled>false</UpdateEnabled> <ItemGroup Label="Package References">
<UpdateMode>Foreground</UpdateMode> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
<UpdateInterval>7</UpdateInterval> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
<UpdateIntervalUnits>Days</UpdateIntervalUnits> <PackageReference Include="squirrel.windows" Version="1.8.0" Condition="'$(TargetFramework)' == 'net471'" />
<UpdatePeriodically>false</UpdatePeriodically> </ItemGroup>
<UpdateRequired>false</UpdateRequired> <ItemGroup Label="Resources">
<MapFileExtensions>true</MapFileExtensions> <EmbeddedResource Include="lazer.ico" />
<ApplicationRevision>2</ApplicationRevision> </ItemGroup>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<ProductVersion>12.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>0</WarningLevel>
<NoStdLib>true</NoStdLib>
<UseVSHostingProcess>false</UseVSHostingProcess>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RunCodeAnalysis>false</RunCodeAnalysis>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<Commandlineparameters>
</Commandlineparameters>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>CuttingEdge NoUpdate</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
<UseVSHostingProcess>false</UseVSHostingProcess>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<Win32Resource>
</Win32Resource>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>lazer.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'VisualTests|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<WarningLevel>0</WarningLevel>
<NoStdLib>true</NoStdLib>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<ErrorReport>prompt</ErrorReport>
<StartArguments>--tests</StartArguments>
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.1.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.1.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.11\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>$(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="OpenTK.dll.config" />
<None Include="osu!.res" />
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
<Visible>False</Visible>
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
<Visible>False</Visible>
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Compile Include="OsuGameDesktop.cs" />
<Compile Include="OsuTestBrowser.cs" />
<Compile Include="Overlays\VersionManager.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="lazer.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
<Name>osu.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
<Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj">
<Project>{54377672-20b1-40af-8087-5cf73bf3953a}</Project>
<Name>osu.Game.Tests</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
<Name>osu.Game</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
</Target>
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
</Project> </Project>
+4 -6
View File
@@ -12,15 +12,13 @@
<description>click the circles. to the beat.</description> <description>click the circles. to the beat.</description>
<summary>click the circles.</summary> <summary>click the circles.</summary>
<releaseNotes>testing</releaseNotes> <releaseNotes>testing</releaseNotes>
<copyright>Copyright ppy Pty Ltd 2007-2017</copyright> <copyright>Copyright ppy Pty Ltd 2007-2018</copyright>
<language>en-AU</language> <language>en-AU</language>
</metadata> </metadata>
<files> <files>
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/> <file src="**.exe" target="lib\net45\" exclude="**vshost**"/>
<file src="*.dll" target="lib\net45\"/> <file src="**.dll" target="lib\net45\"/>
<file src="*.config" target="lib\net45\"/> <file src="**.config" target="lib\net45\"/>
<file src="x86\*.dll" target="lib\net45\x86\"/>
<file src="x64\*.dll" target="lib\net45\x64\"/>
</files> </files>
</package> </package>
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-->
<packages>
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="ppy.OpenTK" version="3.0.11" targetFramework="net461" />
<package id="SharpCompress" version="0.18.1" targetFramework="net461" />
<package id="Splat" version="2.0.0" targetFramework="net45" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
<package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
</packages>
+59
View File
@@ -0,0 +1,59 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "VisualTests (Debug, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Debug/net471/osu.Game.Rulesets.Catch.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Release, net471)",
"windows": {
"type": "clr"
},
"type": "mono",
"request": "launch",
"program": "${workspaceRoot}/bin/Release/net471/osu.Game.Rulesets.Catch.Tests.exe",
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, msbuild)",
"runtimeExecutable": null,
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Debug, netcoreapp2.1)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Debug/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Debug, dotnet)",
"env": {},
"console": "internalConsole"
},
{
"name": "VisualTests (Release, netcoreapp2.1)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/bin/Release/netcoreapp2.1/osu.Game.Rulesets.Catch.Tests.dll"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build (Release, dotnet)",
"env": {},
"console": "internalConsole"
}
]
}
+87
View File
@@ -0,0 +1,87 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build (Debug, msbuild)",
"type": "shell",
"command": "msbuild",
"args": [
"osu.Game.Rulesets.Catch.Tests.csproj",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build (Release, msbuild)",
"type": "shell",
"command": "msbuild",
"args": [
"osu.Game.Rulesets.Catch.Tests.csproj",
"/p:Configuration=Release",
"/p:TargetFramework=net471",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build (Debug, dotnet)",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"--no-restore",
"osu.Game.Rulesets.Catch.Tests.csproj",
"/p:TargetFramework=netcoreapp2.1",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build (Release, dotnet)",
"type": "shell",
"command": "dotnet",
"args": [
"build",
"--no-restore",
"osu.Game.Rulesets.Catch.Tests.csproj",
"/p:TargetFramework=netcoreapp2.1",
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/m",
"/verbosity:m"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Restore (net471)",
"type": "shell",
"command": "nuget",
"args": [
"restore"
],
"problemMatcher": []
},
{
"label": "Restore (netcoreapp2.1)",
"type": "shell",
"command": "dotnet",
"args": [
"restore"
],
"problemMatcher": []
}
]
}
@@ -0,0 +1,85 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using NUnit.Framework;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
public class CatchBeatmapConversionTest : BeatmapConversionTest<ConvertValue>
{
protected override string ResourceAssembly => "osu.Game.Rulesets.Catch";
[TestCase("basic")]
[TestCase("spinner")]
[TestCase("spinner-and-circles")]
public new void Test(string name)
{
base.Test(name);
}
protected override IEnumerable<ConvertValue> CreateConvertValue(HitObject hitObject)
{
if (hitObject is JuiceStream stream)
{
foreach (var nested in stream.NestedHitObjects)
yield return new ConvertValue((CatchHitObject)nested);
}
else if (hitObject is BananaShower shower)
{
foreach (var nested in shower.NestedHitObjects)
yield return new ConvertValue((CatchHitObject)nested);
}
else
yield return new ConvertValue((CatchHitObject)hitObject);
}
protected override Ruleset CreateRuleset() => new CatchRuleset();
}
public struct ConvertValue : IEquatable<ConvertValue>
{
/// <summary>
/// A sane value to account for osu!stable using ints everwhere.
/// </summary>
private const float conversion_lenience = 2;
[JsonIgnore]
public readonly CatchHitObject HitObject;
public ConvertValue(CatchHitObject hitObject)
{
HitObject = hitObject;
startTime = 0;
position = 0;
}
private double startTime;
public double StartTime
{
get => HitObject?.StartTime ?? startTime;
set => startTime = value;
}
private float position;
public float Position
{
get => HitObject?.X * CatchPlayfield.BASE_WIDTH ?? position;
set => position = value;
}
public bool Equals(ConvertValue other)
=> Precision.AlmostEquals(StartTime, other.StartTime, conversion_lenience)
&& Precision.AlmostEquals(Position, other.Position, conversion_lenience);
}
}
@@ -0,0 +1,62 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
using OpenTK;
namespace osu.Game.Rulesets.Catch.Tests
{
public class TestCaseAutoJuiceStream : TestCasePlayer
{
public TestCaseAutoJuiceStream()
: base(new CatchRuleset())
{
}
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
{
var beatmap = new Beatmap
{
BeatmapInfo = new BeatmapInfo
{
BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 },
Ruleset = ruleset.RulesetInfo
}
};
for (int i = 0; i < 100; i++)
{
float width = (i % 10 + 1) / 20f;
beatmap.HitObjects.Add(new JuiceStream
{
X = 0.5f - width / 2,
ControlPoints = new List<Vector2>
{
Vector2.Zero,
new Vector2(width * CatchPlayfield.BASE_WIDTH, 0)
},
CurveType = CurveType.Linear,
Distance = width * CatchPlayfield.BASE_WIDTH,
StartTime = i * 2000,
NewCombo = i % 8 == 0
});
}
return beatmap;
}
protected override Player CreatePlayer(Ruleset ruleset)
{
Beatmap.Value.Mods.Value = Beatmap.Value.Mods.Value.Concat(new[] { ruleset.GetAutoplayMod() });
return base.CreatePlayer(ruleset);
}
}
}
@@ -1,50 +1,47 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
[Ignore("getting CI working")] public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer
public class TestCaseBananaShower : Game.Tests.Visual.TestCasePlayer {
{ public override IReadOnlyList<Type> RequiredTypes => new[]
public override IReadOnlyList<Type> RequiredTypes => new[] {
{ typeof(BananaShower),
typeof(BananaShower), typeof(DrawableBananaShower),
typeof(DrawableBananaShower),
typeof(CatchRuleset),
typeof(CatchRuleset), typeof(CatchRulesetContainer),
typeof(CatchRulesetContainer), };
};
public TestCaseBananaShower()
public TestCaseBananaShower() : base(new CatchRuleset())
: base(new CatchRuleset()) {
{ }
}
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
protected override Beatmap CreateBeatmap() {
{ var beatmap = new Beatmap
var beatmap = new Beatmap {
{ BeatmapInfo = new BeatmapInfo
BeatmapInfo = new BeatmapInfo {
{ BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
BaseDifficulty = new BeatmapDifficulty Ruleset = ruleset.RulesetInfo
{ }
CircleSize = 6, };
}
} beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
};
return beatmap;
beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true }); }
}
return beatmap; }
}
}
}
@@ -1,16 +1,15 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework; using NUnit.Framework;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
[Ignore("getting CI working")] public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer {
{ public TestCaseCatchPlayer() : base(new CatchRuleset())
public TestCaseCatchPlayer() : base(new CatchRuleset()) {
{ }
} }
} }
}
@@ -1,38 +1,36 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
[Ignore("getting CI working")] public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer
public class TestCaseCatchStacker : Game.Tests.Visual.TestCasePlayer {
{ public TestCaseCatchStacker()
public TestCaseCatchStacker() : base(new CatchRuleset())
: base(new CatchRuleset()) {
{ }
}
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
protected override Beatmap CreateBeatmap() {
{ var beatmap = new Beatmap
var beatmap = new Beatmap {
{ BeatmapInfo = new BeatmapInfo
BeatmapInfo = new BeatmapInfo {
{ BaseDifficulty = new BeatmapDifficulty { CircleSize = 6 },
BaseDifficulty = new BeatmapDifficulty Ruleset = ruleset.RulesetInfo
{ }
CircleSize = 6, };
}
}
}; for (int i = 0; i < 512; i++)
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
for (int i = 0; i < 512; i++)
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 }); return beatmap;
}
return beatmap; }
} }
}
}
@@ -1,62 +1,61 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
[Ignore("getting CI working")] public class TestCaseCatcherArea : OsuTestCase
public class TestCaseCatcherArea : OsuTestCase {
{ private RulesetInfo catchRuleset;
private RulesetInfo catchRuleset; private TestCatcherArea catcherArea;
private TestCatcherArea catcherArea;
public override IReadOnlyList<Type> RequiredTypes => new[]
public override IReadOnlyList<Type> RequiredTypes => new[] {
{ typeof(CatcherArea),
typeof(CatcherArea), };
};
public TestCaseCatcherArea()
public TestCaseCatcherArea() {
{ AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher); AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t));
AddToggleStep("Hyperdash", t => catcherArea.ToggleHyperDash(t)); }
}
private void createCatcher(float size)
private void createCatcher(float size) {
{ Child = new CatchInputManager(catchRuleset)
Child = new CatchInputManager(catchRuleset) {
{ RelativeSizeAxes = Axes.Both,
RelativeSizeAxes = Axes.Both, Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size })
Child = catcherArea = new TestCatcherArea(new BeatmapDifficulty { CircleSize = size }) {
{ Anchor = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft, Origin = Anchor.TopLeft
Origin = Anchor.BottomLeft },
}, };
}; }
}
[BackgroundDependencyLoader]
[BackgroundDependencyLoader] private void load(RulesetStore rulesets)
private void load(RulesetStore rulesets) {
{ catchRuleset = rulesets.GetRuleset(2);
catchRuleset = rulesets.GetRuleset(2); }
}
private class TestCatcherArea : CatcherArea
private class TestCatcherArea : CatcherArea {
{ public TestCatcherArea(BeatmapDifficulty beatmapDifficulty)
public TestCatcherArea(BeatmapDifficulty beatmapDifficulty) : base(beatmapDifficulty)
: base(beatmapDifficulty) {
{ }
}
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperdashState(status ? 2 : 1);
public void ToggleHyperDash(bool status) => MovableCatcher.HyperDashModifier = status ? 2 : 1; }
} }
} }
}
@@ -1,104 +1,82 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using osu.Game.Tests.Visual;
using osu.Game.Tests.Visual; using OpenTK;
using OpenTK;
using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.Tests
{
namespace osu.Game.Rulesets.Catch.Tests [TestFixture]
{ public class TestCaseFruitObjects : OsuTestCase
[Ignore("getting CI working")] {
public class TestCaseFruitObjects : OsuTestCase public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] typeof(CatchHitObject),
{ typeof(Fruit),
typeof(CatchHitObject), typeof(Droplet),
typeof(Fruit), typeof(DrawableCatchHitObject),
typeof(Droplet), typeof(DrawableFruit),
typeof(DrawableCatchHitObject), typeof(DrawableDroplet),
typeof(DrawableFruit), typeof(BananaShower),
typeof(DrawableDroplet), typeof(Pulp),
typeof(Pulp), };
};
public TestCaseFruitObjects()
public TestCaseFruitObjects() {
{ Add(new GridContainer
Add(new GridContainer {
{ RelativeSizeAxes = Axes.Both,
RelativeSizeAxes = Axes.Both, Content = new[]
Content = new[] {
{ new Drawable[]
new Drawable[] {
{ createDrawable(0),
createDrawable(0), createDrawable(1),
createDrawable(1), createDrawable(2),
createDrawable(2), },
}, new Drawable[]
new Drawable[] {
{ createDrawable(3),
createDrawable(3), createDrawable(4),
createDrawable(4), createDrawable(5),
createDrawable(5), },
}, }
} });
}); }
}
private DrawableFruit createDrawable(int index)
private DrawableFruit createDrawable(int index) {
{ Fruit fruit = index == 5
var fruit = new Fruit ? new Banana
{ {
StartTime = 1000000000000, StartTime = 1000000000000,
IndexInBeatmap = index, IndexInBeatmap = index,
Scale = 1.5f, Scale = 1.5f,
}; }
: new Fruit
fruit.ComboColour = colourForRrepesentation(fruit.VisualRepresentation); {
StartTime = 1000000000000,
return new DrawableFruit(fruit) IndexInBeatmap = index,
{ Scale = 1.5f,
Anchor = Anchor.Centre, };
RelativePositionAxes = Axes.Both,
Position = Vector2.Zero, return new DrawableFruit(fruit)
Alpha = 1, {
LifetimeStart = double.NegativeInfinity, Anchor = Anchor.Centre,
LifetimeEnd = double.PositiveInfinity, RelativePositionAxes = Axes.Both,
}; Position = Vector2.Zero,
} Alpha = 1,
LifetimeStart = double.NegativeInfinity,
private Color4 colourForRrepesentation(FruitVisualRepresentation representation) LifetimeEnd = double.PositiveInfinity,
{ };
switch (representation) }
{ }
default: }
case FruitVisualRepresentation.Pear:
return new Color4(17, 136, 170, 255);
case FruitVisualRepresentation.Grape:
return new Color4(204, 102, 0, 255);
case FruitVisualRepresentation.Raspberry:
return new Color4(121, 9, 13, 255);
case FruitVisualRepresentation.Pineapple:
return new Color4(102, 136, 0, 255);
case FruitVisualRepresentation.Banana:
switch (RNG.Next(0, 3))
{
default:
return new Color4(255, 240, 0, 255);
case 1:
return new Color4(255, 192, 0, 255);
case 2:
return new Color4(214, 221, 28, 255);
}
}
}
}
}
@@ -1,30 +1,30 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
[Ignore("getting CI working")] public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer
public class TestCaseHyperdash : Game.Tests.Visual.TestCasePlayer {
{ public TestCaseHyperdash()
public TestCaseHyperdash() : base(new CatchRuleset())
: base(new CatchRuleset()) {
{ }
}
protected override IBeatmap CreateBeatmap(Ruleset ruleset)
protected override Beatmap CreateBeatmap() {
{ var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
var beatmap = new Beatmap();
for (int i = 0; i < 512; i++) for (int i = 0; i < 512; i++)
if (i % 5 < 3) if (i % 5 < 3)
beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 }); beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 });
return beatmap; return beatmap;
} }
} }
} }
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\osu.TestProject.props" />
<PropertyGroup Label="Project">
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp2.1;net471</TargetFrameworks>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,43 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps
{
public class CatchBeatmap : Beatmap<CatchHitObject>
{
public override IEnumerable<BeatmapStatistic> GetStatistics()
{
int fruits = HitObjects.Count(s => s is Fruit);
int juiceStreams = HitObjects.Count(s => s is JuiceStream);
int bananaShowers = HitObjects.Count(s => s is BananaShower);
return new[]
{
new BeatmapStatistic
{
Name = @"Fruit Count",
Content = fruits.ToString(),
Icon = FontAwesome.fa_circle_o
},
new BeatmapStatistic
{
Name = @"Juice Stream Count",
Content = juiceStreams.ToString(),
Icon = FontAwesome.fa_circle
},
new BeatmapStatistic
{
Name = @"Banana Shower Count",
Content = bananaShowers.ToString(),
Icon = FontAwesome.fa_circle
}
};
}
}
}
@@ -1,68 +1,71 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using System.Collections.Generic; using System.Collections.Generic;
using System; using System;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Catch.Beatmaps namespace osu.Game.Rulesets.Catch.Beatmaps
{ {
public class CatchBeatmapConverter : BeatmapConverter<CatchHitObject> public class CatchBeatmapConverter : BeatmapConverter<CatchHitObject>
{ {
protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) }; public CatchBeatmapConverter(IBeatmap beatmap)
: base(beatmap)
protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, Beatmap beatmap) {
{ }
var curveData = obj as IHasCurve;
var positionData = obj as IHasXPosition; protected override IEnumerable<Type> ValidConversionTypes { get; } = new[] { typeof(IHasXPosition) };
var comboData = obj as IHasCombo;
var endTime = obj as IHasEndTime; protected override IEnumerable<CatchHitObject> ConvertHitObject(HitObject obj, IBeatmap beatmap)
{
if (positionData == null) var curveData = obj as IHasCurve;
yield break; var positionData = obj as IHasXPosition;
var comboData = obj as IHasCombo;
if (curveData != null) var endTime = obj as IHasEndTime;
{ var legacyOffset = obj as IHasLegacyLastTickOffset;
yield return new JuiceStream
{ if (curveData != null)
StartTime = obj.StartTime, {
Samples = obj.Samples, yield return new JuiceStream
ControlPoints = curveData.ControlPoints, {
CurveType = curveData.CurveType, StartTime = obj.StartTime,
Distance = curveData.Distance, Samples = obj.Samples,
RepeatSamples = curveData.RepeatSamples, ControlPoints = curveData.ControlPoints,
RepeatCount = curveData.RepeatCount, CurveType = curveData.CurveType,
X = positionData.X / CatchPlayfield.BASE_WIDTH, Distance = curveData.Distance,
NewCombo = comboData?.NewCombo ?? false RepeatSamples = curveData.RepeatSamples,
}; RepeatCount = curveData.RepeatCount,
X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH,
yield break; NewCombo = comboData?.NewCombo ?? false,
} LegacyLastTickOffset = legacyOffset?.LegacyLastTickOffset ?? 0
};
if (endTime != null) }
{ else if (endTime != null)
yield return new BananaShower {
{ yield return new BananaShower
StartTime = obj.StartTime, {
Samples = obj.Samples, StartTime = obj.StartTime,
Duration = endTime.Duration, Samples = obj.Samples,
NewCombo = comboData?.NewCombo ?? false Duration = endTime.Duration,
}; NewCombo = comboData?.NewCombo ?? false
};
yield break; }
} else
{
yield return new Fruit yield return new Fruit
{ {
StartTime = obj.StartTime, StartTime = obj.StartTime,
Samples = obj.Samples, Samples = obj.Samples,
NewCombo = comboData?.NewCombo ?? false, NewCombo = comboData?.NewCombo ?? false,
X = positionData.X / CatchPlayfield.BASE_WIDTH X = (positionData?.X ?? 0) / CatchPlayfield.BASE_WIDTH
}; };
} }
} }
}
protected override Beatmap<CatchHitObject> CreateBeatmap() => new CatchBeatmap();
}
}
@@ -1,88 +1,119 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using OpenTK; using OpenTK;
using osu.Game.Rulesets.Catch.MathUtils;
namespace osu.Game.Rulesets.Catch.Beatmaps
{ namespace osu.Game.Rulesets.Catch.Beatmaps
public class CatchBeatmapProcessor : BeatmapProcessor<CatchHitObject> {
{ public class CatchBeatmapProcessor : BeatmapProcessor
public override void PostProcess(Beatmap<CatchHitObject> beatmap) {
{ public const int RNG_SEED = 1337;
if (beatmap.ComboColors.Count == 0)
return; public CatchBeatmapProcessor(IBeatmap beatmap)
: base(beatmap)
int index = 0; {
int colourIndex = 0; }
CatchHitObject lastObj = null; public override void PostProcess()
{
initialiseHyperDash(beatmap.HitObjects); base.PostProcess();
foreach (var obj in beatmap.HitObjects) applyPositionOffsets();
{
if (obj.NewCombo) initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
{
if (lastObj != null) lastObj.LastInCombo = true; int index = 0;
colourIndex = (colourIndex + 1) % beatmap.ComboColors.Count; foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
} {
obj.IndexInBeatmap = index++;
obj.IndexInBeatmap = index++; if (obj.LastInCombo && obj.NestedHitObjects.LastOrDefault() is IHasComboInformation lastNested)
obj.ComboColour = beatmap.ComboColors[colourIndex]; lastNested.LastInCombo = true;
}
lastObj = obj; }
}
} private void applyPositionOffsets()
{
private void initialiseHyperDash(List<CatchHitObject> objects) var rng = new FastRandom(RNG_SEED);
{ // todo: HardRock displacement should be applied here
// todo: add difficulty adjust.
double halfCatcherWidth = CatcherArea.CATCHER_SIZE * (objects.FirstOrDefault()?.Scale ?? 1) / CatchPlayfield.BASE_WIDTH / 2; foreach (var obj in Beatmap.HitObjects)
{
int lastDirection = 0; switch (obj)
double lastExcess = halfCatcherWidth; {
case BananaShower bananaShower:
int objCount = objects.Count; foreach (var banana in bananaShower.NestedHitObjects.OfType<Banana>())
{
for (int i = 0; i < objCount - 1; i++) banana.X = (float)rng.NextDouble();
{ rng.Next(); // osu!stable retrieved a random banana type
CatchHitObject currentObject = objects[i]; rng.Next(); // osu!stable retrieved a random banana rotation
rng.Next(); // osu!stable retrieved a random banana colour
// not needed? }
// if (currentObject is TinyDroplet) continue; break;
case JuiceStream juiceStream:
CatchHitObject nextObject = objects[i + 1]; foreach (var nested in juiceStream.NestedHitObjects)
{
// while (nextObject is TinyDroplet) var hitObject = (CatchHitObject)nested;
// { if (hitObject is TinyDroplet)
// if (++i == objCount - 1) break; hitObject.X += rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH;
// nextObject = objects[i + 1]; else if (hitObject is Droplet)
// } rng.Next(); // osu!stable retrieved a random droplet rotation
hitObject.X = MathHelper.Clamp(hitObject.X, 0, 1);
int thisDirection = nextObject.X > currentObject.X ? 1 : -1; }
double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4; break;
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth); }
}
if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext) }
{
currentObject.HyperDashTarget = nextObject; private void initialiseHyperDash(List<CatchHitObject> objects)
lastExcess = halfCatcherWidth; {
} // todo: add difficulty adjust.
else double halfCatcherWidth = CatcherArea.CATCHER_SIZE * (objects.FirstOrDefault()?.Scale ?? 1) / CatchPlayfield.BASE_WIDTH / 2;
{
//currentObject.DistanceToHyperDash = timeToNext - distanceToNext; int lastDirection = 0;
lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, halfCatcherWidth); double lastExcess = halfCatcherWidth;
}
int objCount = objects.Count;
lastDirection = thisDirection;
} for (int i = 0; i < objCount - 1; i++)
} {
} CatchHitObject currentObject = objects[i];
}
// not needed?
// if (currentObject is TinyDroplet) continue;
CatchHitObject nextObject = objects[i + 1];
// while (nextObject is TinyDroplet)
// {
// if (++i == objCount - 1) break;
// nextObject = objects[i + 1];
// }
int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
double timeToNext = nextObject.StartTime - ((currentObject as IHasEndTime)?.EndTime ?? currentObject.StartTime) - 4;
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
if (timeToNext * CatcherArea.Catcher.BASE_SPEED < distanceToNext)
{
currentObject.HyperDashTarget = nextObject;
lastExcess = halfCatcherWidth;
}
else
{
//currentObject.DistanceToHyperDash = timeToNext - distanceToNext;
lastExcess = MathHelper.Clamp(timeToNext - distanceToNext, 0, halfCatcherWidth);
}
lastDirection = thisDirection;
}
}
}
}
@@ -1,21 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using System.Collections.Generic;
namespace osu.Game.Rulesets.Catch
{
public class CatchDifficultyCalculator : DifficultyCalculator<CatchHitObject>
{
public CatchDifficultyCalculator(Beatmap beatmap) : base(beatmap)
{
}
public override double Calculate(Dictionary<string, double> categoryDifficulty = null) => 0;
protected override BeatmapConverter<CatchHitObject> CreateBeatmapConverter(Beatmap beatmap) => new CatchBeatmapConverter();
}
}
+27 -28
View File
@@ -1,28 +1,27 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Catch namespace osu.Game.Rulesets.Catch
{ {
public class CatchInputManager : RulesetInputManager<CatchAction> public class CatchInputManager : RulesetInputManager<CatchAction>
{ {
public CatchInputManager(RulesetInfo ruleset) public CatchInputManager(RulesetInfo ruleset)
: base(ruleset, 0, SimultaneousBindingMode.Unique) : base(ruleset, 0, SimultaneousBindingMode.Unique)
{ {
} }
} }
public enum CatchAction public enum CatchAction
{ {
[Description("Move left")] [Description("Move left")]
MoveLeft, MoveLeft,
[Description("Move right")] [Description("Move right")]
MoveRight, MoveRight,
[Description("Engage dash")] [Description("Engage dash")]
Dash, Dash,
PositionUpdate }
} }
}
+126 -109
View File
@@ -1,109 +1,126 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Catch.Replays;
namespace osu.Game.Rulesets.Catch using osu.Game.Rulesets.Replays.Types;
{ using osu.Game.Beatmaps.Legacy;
public class CatchRuleset : Ruleset using osu.Game.Rulesets.Catch.Beatmaps;
{ using osu.Game.Rulesets.Catch.Difficulty;
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchRulesetContainer(this, beatmap, isForCurrentRuleset); using osu.Game.Rulesets.Difficulty;
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[] namespace osu.Game.Rulesets.Catch
{ {
new KeyBinding(InputKey.Z, CatchAction.MoveLeft), public class CatchRuleset : Ruleset
new KeyBinding(InputKey.Left, CatchAction.MoveLeft), {
new KeyBinding(InputKey.X, CatchAction.MoveRight), public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap) => new CatchRulesetContainer(this, beatmap);
new KeyBinding(InputKey.Right, CatchAction.MoveRight), public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap);
new KeyBinding(InputKey.Shift, CatchAction.Dash), public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
new KeyBinding(InputKey.Shift, CatchAction.Dash),
}; public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{
public override IEnumerable<Mod> GetModsFor(ModType type) new KeyBinding(InputKey.Z, CatchAction.MoveLeft),
{ new KeyBinding(InputKey.Left, CatchAction.MoveLeft),
switch (type) new KeyBinding(InputKey.X, CatchAction.MoveRight),
{ new KeyBinding(InputKey.Right, CatchAction.MoveRight),
case ModType.DifficultyReduction: new KeyBinding(InputKey.Shift, CatchAction.Dash),
return new Mod[] new KeyBinding(InputKey.Shift, CatchAction.Dash),
{ };
new CatchModEasy(),
new CatchModNoFail(), public override IEnumerable<Mod> ConvertLegacyMods(LegacyMods mods)
new MultiMod {
{ if (mods.HasFlag(LegacyMods.Nightcore))
Mods = new Mod[] yield return new CatchModNightcore();
{ else if (mods.HasFlag(LegacyMods.DoubleTime))
new CatchModHalfTime(), yield return new CatchModDoubleTime();
new CatchModDaycore(),
}, if (mods.HasFlag(LegacyMods.Autoplay))
}, yield return new CatchModAutoplay();
};
if (mods.HasFlag(LegacyMods.Easy))
case ModType.DifficultyIncrease: yield return new CatchModEasy();
return new Mod[]
{ if (mods.HasFlag(LegacyMods.Flashlight))
new CatchModHardRock(), yield return new CatchModFlashlight();
new MultiMod
{ if (mods.HasFlag(LegacyMods.HalfTime))
Mods = new Mod[] yield return new CatchModHalfTime();
{
new CatchModSuddenDeath(), if (mods.HasFlag(LegacyMods.HardRock))
new CatchModPerfect(), yield return new CatchModHardRock();
},
}, if (mods.HasFlag(LegacyMods.Hidden))
new MultiMod yield return new CatchModHidden();
{
Mods = new Mod[] if (mods.HasFlag(LegacyMods.NoFail))
{ yield return new CatchModNoFail();
new CatchModDoubleTime(),
new CatchModNightcore(), if (mods.HasFlag(LegacyMods.Perfect))
}, yield return new CatchModPerfect();
},
new CatchModHidden(), if (mods.HasFlag(LegacyMods.Relax))
new CatchModFlashlight(), yield return new CatchModRelax();
};
if (mods.HasFlag(LegacyMods.SuddenDeath))
case ModType.Special: yield return new CatchModSuddenDeath();
return new Mod[] }
{
new CatchModRelax(), public override IEnumerable<Mod> GetModsFor(ModType type)
null, {
null, switch (type)
new MultiMod {
{ case ModType.DifficultyReduction:
Mods = new Mod[] return new Mod[]
{ {
new CatchModAutoplay(), new CatchModEasy(),
new ModCinema(), new CatchModNoFail(),
}, new MultiMod(new CatchModHalfTime(), new CatchModDaycore())
}, };
}; case ModType.DifficultyIncrease:
return new Mod[]
default: {
return new Mod[] { }; new CatchModHardRock(),
} new MultiMod(new CatchModSuddenDeath(), new CatchModPerfect()),
} new MultiMod(new CatchModDoubleTime(), new CatchModNightcore()),
new CatchModHidden(),
public override string Description => "osu!catch"; new CatchModFlashlight(),
};
public override string ShortName => "fruits"; case ModType.Special:
return new Mod[]
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; {
new CatchModRelax(),
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap, Mod[] mods = null) => new CatchDifficultyCalculator(beatmap); null,
null,
public override int LegacyID => 2; new MultiMod(new CatchModAutoplay(), new ModCinema()),
};
public CatchRuleset(RulesetInfo rulesetInfo = null) default:
: base(rulesetInfo) return new Mod[] { };
{ }
} }
}
} public override string Description => "osu!catch";
public override string ShortName => "fruits";
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
public override int? LegacyID => 2;
public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame();
public CatchRuleset(RulesetInfo rulesetInfo = null)
: base(rulesetInfo)
{
}
}
}
@@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyAttributes : DifficultyAttributes
{
public double ApproachRate;
public int MaxCombo;
public CatchDifficultyAttributes(Mod[] mods, double starRating)
: base(mods, starRating)
{
}
}
}
@@ -0,0 +1,146 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyCalculator : DifficultyCalculator
{
/// <summary>
/// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
/// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
/// The higher this value, the less strains there will be, indirectly giving long beatmaps an advantage.
/// </summary>
private const double strain_step = 750;
/// <summary>
/// The weighting of each strain value decays to this number * it's previous value
/// </summary>
private const double decay_weight = 0.94;
private const double star_scaling_factor = 0.145;
public CatchDifficultyCalculator(Ruleset ruleset, WorkingBeatmap beatmap)
: base(ruleset, beatmap)
{
}
protected override DifficultyAttributes Calculate(IBeatmap beatmap, Mod[] mods, double timeRate)
{
if (!beatmap.HitObjects.Any())
return new CatchDifficultyAttributes(mods, 0);
var catcher = new CatcherArea.Catcher(beatmap.BeatmapInfo.BaseDifficulty);
float halfCatchWidth = catcher.CatchWidth * 0.5f;
var difficultyHitObjects = new List<CatchDifficultyHitObject>();
foreach (var hitObject in beatmap.HitObjects)
{
// We want to only consider fruits that contribute to the combo. Droplets are addressed as accuracy and spinners are not relevant for "skill" calculations.
if (hitObject is Fruit)
{
difficultyHitObjects.Add(new CatchDifficultyHitObject((CatchHitObject)hitObject, halfCatchWidth));
}
if (hitObject is JuiceStream)
difficultyHitObjects.AddRange(hitObject.NestedHitObjects.OfType<CatchHitObject>().Where(o => !(o is TinyDroplet)).Select(o => new CatchDifficultyHitObject(o, halfCatchWidth)));
}
difficultyHitObjects.Sort((a, b) => a.BaseHitObject.StartTime.CompareTo(b.BaseHitObject.StartTime));
if (!calculateStrainValues(difficultyHitObjects, timeRate))
return new CatchDifficultyAttributes(mods, 0);
// this is the same as osu!, so there's potential to share the implementation... maybe
double preEmpt = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.ApproachRate, 1800, 1200, 450) / timeRate;
double starRating = Math.Sqrt(calculateDifficulty(difficultyHitObjects, timeRate)) * star_scaling_factor;
return new CatchDifficultyAttributes(mods, starRating)
{
ApproachRate = preEmpt > 1200.0 ? -(preEmpt - 1800.0) / 120.0 : -(preEmpt - 1200.0) / 150.0 + 5.0,
MaxCombo = difficultyHitObjects.Count
};
}
private bool calculateStrainValues(List<CatchDifficultyHitObject> objects, double timeRate)
{
CatchDifficultyHitObject lastObject = null;
if (!objects.Any()) return false;
// Traverse hitObjects in pairs to calculate the strain value of NextHitObject from the strain value of CurrentHitObject and environment.
foreach (var currentObject in objects)
{
if (lastObject != null)
currentObject.CalculateStrains(lastObject, timeRate);
lastObject = currentObject;
}
return true;
}
private double calculateDifficulty(List<CatchDifficultyHitObject> objects, double timeRate)
{
// The strain step needs to be adjusted for the algorithm to be considered equal with speed changing mods
double actualStrainStep = strain_step * timeRate;
// Find the highest strain value within each strain step
var highestStrains = new List<double>();
double intervalEndTime = actualStrainStep;
double maximumStrain = 0; // We need to keep track of the maximum strain in the current interval
CatchDifficultyHitObject previousHitObject = null;
foreach (CatchDifficultyHitObject hitObject in objects)
{
// While we are beyond the current interval push the currently available maximum to our strain list
while (hitObject.BaseHitObject.StartTime > intervalEndTime)
{
highestStrains.Add(maximumStrain);
// The maximum strain of the next interval is not zero by default! We need to take the last hitObject we encountered, take its strain and apply the decay
// until the beginning of the next interval.
if (previousHitObject == null)
{
maximumStrain = 0;
}
else
{
double decay = Math.Pow(CatchDifficultyHitObject.DECAY_BASE, (intervalEndTime - previousHitObject.BaseHitObject.StartTime) / 1000);
maximumStrain = previousHitObject.Strain * decay;
}
// Go to the next time interval
intervalEndTime += actualStrainStep;
}
// Obtain maximum strain
maximumStrain = Math.Max(hitObject.Strain, maximumStrain);
previousHitObject = hitObject;
}
// Build the weighted sum over the highest strains for each interval
double difficulty = 0;
double weight = 1;
highestStrains.Sort((a, b) => b.CompareTo(a)); // Sort from highest to lowest strain.
foreach (double strain in highestStrains)
{
difficulty += weight * strain;
weight *= decay_weight;
}
return difficulty;
}
}
}
@@ -0,0 +1,130 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using OpenTK;
namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyHitObject
{
internal static readonly double DECAY_BASE = 0.20;
private const float normalized_hitobject_radius = 41.0f;
private const float absolute_player_positioning_error = 16f;
private readonly float playerPositioningError;
internal CatchHitObject BaseHitObject;
/// <summary>
/// Measures jump difficulty. CtB doesn't have something like button pressing speed or accuracy
/// </summary>
internal double Strain = 1;
/// <summary>
/// This is required to keep track of lazy player movement (always moving only as far as necessary)
/// Without this quick repeat sliders / weirdly shaped streams might become ridiculously overrated
/// </summary>
internal float PlayerPositionOffset;
internal float LastMovement;
internal float NormalizedPosition;
internal float ActualNormalizedPosition => NormalizedPosition + PlayerPositionOffset;
internal CatchDifficultyHitObject(CatchHitObject baseHitObject, float catcherWidthHalf)
{
BaseHitObject = baseHitObject;
// We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps.
float scalingFactor = normalized_hitobject_radius / catcherWidthHalf;
playerPositioningError = absolute_player_positioning_error; // * scalingFactor;
NormalizedPosition = baseHitObject.X * CatchPlayfield.BASE_WIDTH * scalingFactor;
}
private const double direction_change_bonus = 12.5;
internal void CalculateStrains(CatchDifficultyHitObject previousHitObject, double timeRate)
{
// Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make.
// See Taiko feedback thread.
double timeElapsed = (BaseHitObject.StartTime - previousHitObject.BaseHitObject.StartTime) / timeRate;
double decay = Math.Pow(DECAY_BASE, timeElapsed / 1000);
// Update new position with lazy movement.
PlayerPositionOffset =
MathHelper.Clamp(
previousHitObject.ActualNormalizedPosition,
NormalizedPosition - (normalized_hitobject_radius - playerPositioningError),
NormalizedPosition + (normalized_hitobject_radius - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player.
- NormalizedPosition; // Subtract HitObject position to obtain offset
LastMovement = DistanceTo(previousHitObject);
double addition = spacingWeight(LastMovement);
if (NormalizedPosition < previousHitObject.NormalizedPosition)
{
LastMovement = -LastMovement;
}
CatchHitObject previousHitCircle = previousHitObject.BaseHitObject;
double additionBonus = 0;
double sqrtTime = Math.Sqrt(Math.Max(timeElapsed, 25));
// Direction changes give an extra point!
if (Math.Abs(LastMovement) > 0.1)
{
if (Math.Abs(previousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(previousHitObject.LastMovement))
{
double bonus = direction_change_bonus / sqrtTime;
// Weight bonus by how
double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError;
// We want time to play a role twice here!
addition += bonus * bonusFactor;
// Bonus for tougher direction switches and "almost" hyperdashes at this point
if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH)
{
additionBonus += 0.3 * bonusFactor;
}
}
// Base bonus for every movement, giving some weight to streams.
addition += 7.5 * Math.Min(Math.Abs(LastMovement), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtTime;
}
// Bonus for "almost" hyperdashes at corner points
if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10.0f / CatchPlayfield.BASE_WIDTH)
{
if (!previousHitCircle.HyperDash)
{
additionBonus += 1.0;
}
else
{
// After a hyperdash we ARE in the correct position. Always!
PlayerPositionOffset = 0;
}
addition *= 1.0 + additionBonus * ((10 - previousHitCircle.DistanceToHyperDash * CatchPlayfield.BASE_WIDTH) / 10);
}
addition *= 850.0 / Math.Max(timeElapsed, 25);
Strain = previousHitObject.Strain * decay + addition;
}
private static double spacingWeight(float distance)
{
return Math.Pow(distance, 1.3) / 500;
}
internal float DistanceTo(CatchDifficultyHitObject other)
{
return Math.Abs(ActualNormalizedPosition - other.ActualNormalizedPosition);
}
}
}
@@ -0,0 +1,36 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchBananaJudgement : CatchJudgement
{
public override bool AffectsCombo => false;
public override bool ShouldExplode => true;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 1100;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 8;
}
}
}
}
@@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchDropletJudgement : CatchJudgement
{
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 30;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 7;
}
}
}
}
@@ -1,12 +1,52 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Catch.Judgements using osu.Game.Rulesets.Scoring;
{
public class CatchJudgement : Judgement namespace osu.Game.Rulesets.Catch.Judgements
{ {
// todo: wangs public class CatchJudgement : Judgement
} {
} public override HitResult MaxResult => HitResult.Perfect;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 300;
}
}
/// <summary>
/// The base health increase for the result achieved.
/// </summary>
public float HealthIncrease => HealthIncreaseFor(Result);
/// <summary>
/// Whether fruit on the platter should explode or drop.
/// Note that this is only checked if the owning object is also <see cref="IHasComboInformation.LastInCombo" />
/// </summary>
public virtual bool ShouldExplode => IsHit;
/// <summary>
/// Convert a <see cref="HitResult"/> to a base health increase.
/// </summary>
/// <param name="result">The value to convert.</param>
/// <returns>The base health increase.</returns>
protected virtual float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 10.2f;
}
}
}
}
@@ -0,0 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Judgements
{
public class CatchTinyDropletJudgement : CatchJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 10;
}
}
protected override float HealthIncreaseFor(HitResult result)
{
switch (result)
{
default:
return 0;
case HitResult.Perfect:
return 4;
}
}
}
}
@@ -0,0 +1,91 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
namespace osu.Game.Rulesets.Catch.MathUtils
{
/// <summary>
/// A PRNG specified in http://heliosphan.org/fastrandom.html.
/// </summary>
public class FastRandom
{
private const double int_to_real = 1.0 / (int.MaxValue + 1.0);
private const uint int_mask = 0x7FFFFFFF;
private const uint y = 842502087;
private const uint z = 3579807591;
private const uint w = 273326509;
private uint _x, _y = y, _z = z, _w = w;
public FastRandom(int seed)
{
_x = (uint)seed;
}
public FastRandom()
: this(Environment.TickCount)
{
}
/// <summary>
/// Generates a random unsigned integer within the range [<see cref="uint.MinValue"/>, <see cref="uint.MaxValue"/>).
/// </summary>
/// <returns>The random value.</returns>
public uint NextUInt()
{
uint t = _x ^ _x << 11;
_x = _y;
_y = _z;
_z = _w;
return _w = _w ^ _w >> 19 ^ t ^ t >> 8;
}
/// <summary>
/// Generates a random integer value within the range [0, <see cref="int.MaxValue"/>).
/// </summary>
/// <returns>The random value.</returns>
public int Next() => (int)(int_mask & NextUInt());
/// <summary>
/// Generates a random integer value within the range [0, <paramref name="upperBound"/>).
/// </summary>
/// <param name="upperBound">The upper bound.</param>
/// <returns>The random value.</returns>
public int Next(int upperBound) => (int)(NextDouble() * upperBound);
/// <summary>
/// Generates a random integer value within the range [<paramref name="lowerBound"/>, <paramref name="upperBound"/>).
/// </summary>
/// <param name="lowerBound">The lower bound of the range.</param>
/// <param name="upperBound">The upper bound of the range.</param>
/// <returns>The random value.</returns>
public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound));
/// <summary>
/// Generates a random double value within the range [0, 1).
/// </summary>
/// <returns>The random value.</returns>
public double NextDouble() => int_to_real * Next();
private uint bitBuffer;
private int bitIndex = 32;
/// <summary>
/// Generates a reandom boolean value. Cached such that a random value is only generated once in every 32 calls.
/// </summary>
/// <returns>The random value.</returns>
public bool NextBool()
{
if (bitIndex == 32)
{
bitBuffer = NextUInt();
bitIndex = 1;
return (bitBuffer & 1) == 1;
}
bitIndex++;
return ((bitBuffer >>= 1) & 1) == 1;
}
}
}
@@ -1,24 +1,24 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Users; using osu.Game.Users;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModAutoplay : ModAutoplay<CatchHitObject> public class CatchModAutoplay : ModAutoplay<CatchHitObject>
{ {
protected override Score CreateReplayScore(Beatmap<CatchHitObject> beatmap) protected override Score CreateReplayScore(Beatmap<CatchHitObject> beatmap)
{ {
return new Score return new Score
{ {
User = new User { Username = "osu!salad!" }, User = new User { Username = "osu!salad!" },
Replay = new CatchAutoGenerator(beatmap).Generate(), Replay = new CatchAutoGenerator(beatmap).Generate(),
}; };
} }
} }
} }
+12 -12
View File
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModDaycore : ModDaycore public class CatchModDaycore : ModDaycore
{ {
public override double ScoreMultiplier => 0.5; public override double ScoreMultiplier => 0.3;
} }
} }
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModDoubleTime : ModDoubleTime public class CatchModDoubleTime : ModDoubleTime
{ {
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
} }
} }
+12 -11
View File
@@ -1,11 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModEasy : ModEasy public class CatchModEasy : ModEasy
{ {
} public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!";
} }
}
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModFlashlight : ModFlashlight public class CatchModFlashlight : ModFlashlight
{ {
public override double ScoreMultiplier => 1.12; public override double ScoreMultiplier => 1.12;
} }
} }
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModHalfTime : ModHalfTime public class CatchModHalfTime : ModHalfTime
{ {
public override double ScoreMultiplier => 0.5; public override double ScoreMultiplier => 0.3;
} }
} }
@@ -1,13 +1,91 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
namespace osu.Game.Rulesets.Catch.Mods using osu.Game.Rulesets.Catch.UI;
{ using osu.Game.Rulesets.Mods;
public class CatchModHardRock : ModHardRock using System;
{ using osu.Game.Rulesets.Objects;
public override double ScoreMultiplier => 1.12;
public override bool Ranked => true; namespace osu.Game.Rulesets.Catch.Mods
} {
} public class CatchModHardRock : ModHardRock, IApplicableToHitObject
{
public override double ScoreMultiplier => 1.12;
public override bool Ranked => true;
private float lastStartX;
private int lastStartTime;
public void ApplyToHitObject(HitObject hitObject)
{
var catchObject = (CatchHitObject)hitObject;
float position = catchObject.X;
int startTime = (int)hitObject.StartTime;
if (lastStartX == 0)
{
lastStartX = position;
lastStartTime = startTime;
return;
}
float diff = lastStartX - position;
int timeDiff = startTime - lastStartTime;
if (timeDiff > 1000)
{
lastStartX = position;
lastStartTime = startTime;
return;
}
if (diff == 0)
{
bool right = RNG.NextBool();
float rand = Math.Min(20, (float)RNG.NextDouble(0, timeDiff / 4d)) / CatchPlayfield.BASE_WIDTH;
if (right)
{
if (position + rand <= 1)
position += rand;
else
position -= rand;
}
else
{
if (position - rand >= 0)
position -= rand;
else
position += rand;
}
catchObject.X = position;
return;
}
if (Math.Abs(diff) < timeDiff / 3d)
{
if (diff > 0)
{
if (position - diff > 0)
position -= diff;
}
else
{
if (position - diff < 1)
position -= diff;
}
}
catchObject.X = position;
lastStartX = position;
lastStartTime = startTime;
}
}
}
+13 -13
View File
@@ -1,13 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModHidden : ModHidden public class CatchModHidden : ModHidden
{ {
public override string Description => @"Play with fading notes for a slight score advantage."; public override string Description => @"Play with fading fruits.";
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
} }
} }
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModNightcore : ModNightcore public class CatchModNightcore : ModNightcore
{ {
public override double ScoreMultiplier => 1.06; public override double ScoreMultiplier => 1.06;
} }
} }
+11 -11
View File
@@ -1,11 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModNoFail : ModNoFail public class CatchModNoFail : ModNoFail
{ {
} }
} }
+11 -11
View File
@@ -1,11 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModPerfect : ModPerfect public class CatchModPerfect : ModPerfect
{ {
} }
} }
+12 -12
View File
@@ -1,12 +1,12 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModRelax : ModRelax public class CatchModRelax : ModRelax
{ {
public override string Description => @"Use the mouse to control the catcher."; public override string Description => @"Use the mouse to control the catcher.";
} }
} }
@@ -1,11 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModSuddenDeath : ModSuddenDeath public class CatchModSuddenDeath : ModSuddenDeath
{ {
} }
} }
+10
View File
@@ -0,0 +1,10 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Catch.Objects
{
public class Banana : Fruit
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
}
}
+41 -63
View File
@@ -1,63 +1,41 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.MathUtils; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects
{
namespace osu.Game.Rulesets.Catch.Objects public class BananaShower : CatchHitObject, IHasEndTime
{ {
public class BananaShower : CatchHitObject, IHasEndTime public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana; public override bool LastInCombo => true;
public override bool LastInCombo => true; protected override void CreateNestedHitObjects()
{
protected override void CreateNestedHitObjects() base.CreateNestedHitObjects();
{ createBananas();
base.CreateNestedHitObjects(); }
createBananas();
} private void createBananas()
{
private void createBananas() double spacing = Duration;
{ while (spacing > 100)
double spacing = Duration; spacing /= 2;
while (spacing > 100)
spacing /= 2; if (spacing <= 0)
return;
if (spacing <= 0)
return; for (double i = StartTime; i <= EndTime; i += spacing)
AddNested(new Banana
for (double i = StartTime; i <= EndTime; i += spacing) {
AddNested(new Banana Samples = Samples,
{ StartTime = i
Samples = Samples, });
ComboColour = getNextComboColour(), }
StartTime = i,
X = RNG.NextSingle() public double EndTime => StartTime + Duration;
});
} public double Duration { get; set; }
}
private Color4 getNextComboColour() }
{
switch (RNG.Next(0, 3))
{
default:
return new Color4(255, 240, 0, 255);
case 1:
return new Color4(255, 192, 0, 255);
case 2:
return new Color4(214, 221, 28, 255);
}
}
public double EndTime => StartTime + Duration;
public double Duration { get; set; }
public class Banana : Fruit
{
public override FruitVisualRepresentation VisualRepresentation => FruitVisualRepresentation.Banana;
}
}
}
@@ -1,59 +1,67 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects
namespace osu.Game.Rulesets.Catch.Objects {
{ public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboInformation
public abstract class CatchHitObject : HitObject, IHasXPosition, IHasCombo {
{ public const double OBJECT_RADIUS = 44;
public const double OBJECT_RADIUS = 44;
public float X { get; set; }
public float X { get; set; }
public int IndexInBeatmap { get; set; }
public Color4 ComboColour { get; set; }
public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
public int IndexInBeatmap { get; set; }
public virtual bool NewCombo { get; set; }
public virtual FruitVisualRepresentation VisualRepresentation => (FruitVisualRepresentation)(IndexInBeatmap % 4);
public int IndexInCurrentCombo { get; set; }
public virtual bool NewCombo { get; set; }
public int ComboIndex { get; set; }
/// <summary>
/// The next fruit starts a new combo. Used for explodey. /// <summary>
/// </summary> /// The distance for a fruit to to next hyper if it's not a hyper.
public virtual bool LastInCombo { get; set; } /// </summary>
public float DistanceToHyperDash { get; set; }
public float Scale { get; set; } = 1;
/// <summary>
/// <summary> /// The next fruit starts a new combo. Used for explodey.
/// Whether this fruit can initiate a hyperdash. /// </summary>
/// </summary> public virtual bool LastInCombo { get; set; }
public bool HyperDash => HyperDashTarget != null;
public float Scale { get; set; } = 1;
/// <summary>
/// The target fruit if we are to initiate a hyperdash. /// <summary>
/// </summary> /// Whether this fruit can initiate a hyperdash.
public CatchHitObject HyperDashTarget; /// </summary>
public bool HyperDash => HyperDashTarget != null;
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ /// <summary>
base.ApplyDefaultsToSelf(controlPointInfo, difficulty); /// The target fruit if we are to initiate a hyperdash.
/// </summary>
Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5; public CatchHitObject HyperDashTarget;
}
} protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
public enum FruitVisualRepresentation base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
{
Pear, Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
Grape, }
Raspberry,
Pineapple, protected override HitWindows CreateHitWindows() => null;
Banana // banananananannaanana }
}
} public enum FruitVisualRepresentation
{
Pear,
Grape,
Raspberry,
Pineapple,
Banana // banananananannaanana
}
}
@@ -0,0 +1,17 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public class DrawableBanana : DrawableFruit
{
public DrawableBanana(Banana h)
: base(h)
{
}
protected override CatchJudgement CreateJudgement() => new CatchBananaJudgement();
}
}
@@ -1,44 +1,38 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
namespace osu.Game.Rulesets.Catch.Objects.Drawable public class DrawableBananaShower : DrawableCatchHitObject<BananaShower>
{ {
public class DrawableBananaShower : DrawableCatchHitObject<BananaShower> private readonly Container bananaContainer;
{
private readonly Container bananaContainer; public DrawableBananaShower(BananaShower s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null)
: base(s)
public DrawableBananaShower(BananaShower s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null) {
: base(s) RelativeSizeAxes = Axes.X;
{ Origin = Anchor.BottomLeft;
RelativeSizeAxes = Axes.X; X = 0;
Origin = Anchor.BottomLeft;
X = 0; InternalChild = bananaContainer = new Container { RelativeSizeAxes = Axes.Both };
Child = bananaContainer = new Container { RelativeSizeAxes = Axes.Both }; foreach (var b in s.NestedHitObjects.Cast<Banana>())
AddNested(getVisualRepresentation?.Invoke(b));
foreach (var b in s.NestedHitObjects.Cast<BananaShower.Banana>()) }
AddNested(getVisualRepresentation?.Invoke(b));
} protected override bool ProvidesJudgement => false;
protected override void CheckForJudgements(bool userTriggered, double timeOffset) protected override void AddNested(DrawableHitObject h)
{ {
if (timeOffset >= 0) ((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
AddJudgement(new Judgement { Result = NestedHitObjects.Cast<DrawableCatchHitObject>().Any(n => n.Judgements.Any(j => j.IsHit)) ? HitResult.Perfect : HitResult.Miss }); bananaContainer.Add(h);
} base.AddNested(h);
}
protected override void AddNested(DrawableHitObject h) }
{ }
((DrawableCatchHitObject)h).CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
bananaContainer.Add(h);
base.AddNested(h);
}
}
}
@@ -1,83 +1,101 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Graphics; using OpenTK;
using osu.Game.Rulesets.Judgements; using OpenTK.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Catch.Judgements;
using OpenTK; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Objects.Drawable using osu.Game.Skinning;
{
public abstract class PalpableCatchHitObject<TObject> : DrawableCatchHitObject<TObject> namespace osu.Game.Rulesets.Catch.Objects.Drawable
where TObject : CatchHitObject {
{ public abstract class PalpableCatchHitObject<TObject> : DrawableCatchHitObject<TObject>
public override bool CanBePlated => true; where TObject : CatchHitObject
{
protected PalpableCatchHitObject(TObject hitObject) public override bool CanBePlated => true;
: base(hitObject)
{ protected PalpableCatchHitObject(TObject hitObject)
Scale = new Vector2(HitObject.Scale); : base(hitObject)
} {
} Scale = new Vector2(HitObject.Scale);
}
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject }
where TObject : CatchHitObject
{ public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject
public new TObject HitObject; where TObject : CatchHitObject
{
protected DrawableCatchHitObject(TObject hitObject) public new TObject HitObject;
: base(hitObject)
{ protected DrawableCatchHitObject(TObject hitObject)
HitObject = hitObject; : base(hitObject)
Anchor = Anchor.BottomLeft; {
} HitObject = hitObject;
} Anchor = Anchor.BottomLeft;
}
public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject> }
{
public virtual bool CanBePlated => false; public abstract class DrawableCatchHitObject : DrawableHitObject<CatchHitObject>
{
protected DrawableCatchHitObject(CatchHitObject hitObject) public virtual bool CanBePlated => false;
: base(hitObject)
{ public virtual bool StaysOnPlate => CanBePlated;
RelativePositionAxes = Axes.X;
X = hitObject.X; protected DrawableCatchHitObject(CatchHitObject hitObject)
} : base(hitObject)
{
public Func<CatchHitObject, bool> CheckPosition; RelativePositionAxes = Axes.X;
X = hitObject.X;
protected override void CheckForJudgements(bool userTriggered, double timeOffset) }
{
if (CheckPosition == null) return; public Func<CatchHitObject, bool> CheckPosition;
if (timeOffset > 0) protected override void CheckForJudgements(bool userTriggered, double timeOffset)
AddJudgement(new Judgement { Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss }); {
} if (CheckPosition == null) return;
private const float preempt = 1000; if (timeOffset >= 0)
{
protected override void UpdateState(ArmedState state) var judgement = CreateJudgement();
{ judgement.Result = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss;
using (BeginAbsoluteSequence(HitObject.StartTime - preempt)) AddJudgement(judgement);
this.FadeIn(200); }
}
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
protected virtual CatchJudgement CreateJudgement() => new CatchJudgement();
using (BeginAbsoluteSequence(endTime, true))
{ protected override void SkinChanged(ISkinSource skin, bool allowFallback)
switch (state) {
{ base.SkinChanged(skin, allowFallback);
case ArmedState.Miss:
this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire(); if (HitObject is IHasComboInformation combo)
break; AccentColour = skin.GetValue<SkinConfiguration, Color4>(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
case ArmedState.Hit: }
this.FadeOut().Expire();
break; private const float preempt = 1000;
}
} protected override void UpdateState(ArmedState state)
} {
} using (BeginAbsoluteSequence(HitObject.StartTime - preempt))
} this.FadeIn(200);
var endTime = (HitObject as IHasEndTime)?.EndTime ?? HitObject.StartTime;
using (BeginAbsoluteSequence(endTime, true))
{
switch (state)
{
case ArmedState.Miss:
this.FadeOut(250).RotateTo(Rotation * 2, 250, Easing.Out).Expire();
break;
case ArmedState.Hit:
this.FadeOut().Expire();
break;
}
}
}
}
}
@@ -1,32 +1,48 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable using osu.Game.Rulesets.Catch.Judgements;
{
public class DrawableDroplet : PalpableCatchHitObject<Droplet> namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
public DrawableDroplet(Droplet h) public class DrawableDroplet : PalpableCatchHitObject<Droplet>
: base(h) {
{ private Pulp pulp;
Origin = Anchor.Centre;
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4; public override bool StaysOnPlate => false;
AccentColour = h.ComboColour;
Masking = false; public DrawableDroplet(Droplet h)
} : base(h)
{
[BackgroundDependencyLoader] Origin = Anchor.Centre;
private void load() Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4;
{ Masking = false;
Child = new Pulp }
{
AccentColour = AccentColour, protected override CatchJudgement CreateJudgement() => new CatchDropletJudgement();
Size = Size
}; [BackgroundDependencyLoader]
} private void load()
} {
} InternalChild = pulp = new Pulp
{
Size = Size
};
}
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
base.AccentColour = value;
pulp.AccentColour = AccentColour;
}
}
}
}
@@ -1,277 +1,304 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces; using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
public class DrawableFruit : PalpableCatchHitObject<Fruit> public class DrawableFruit : PalpableCatchHitObject<Fruit>
{ {
private Circle border; private Circle border;
public DrawableFruit(Fruit h) private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust;
: base(h)
{ /// <summary>
Origin = Anchor.Centre; /// Because we're adding a border around the fruit, we need to scale down some.
/// </summary>
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS); private const float radius_adjust = 1.1f;
AccentColour = HitObject.ComboColour;
Masking = false; public DrawableFruit(Fruit h)
: base(h)
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40; {
} Origin = Anchor.Centre;
[BackgroundDependencyLoader] Size = new Vector2(drawable_radius);
private void load() Masking = false;
{
Children = new[] Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
{ }
createPulp(HitObject.VisualRepresentation),
border = new Circle [BackgroundDependencyLoader]
{ private void load()
EdgeEffect = new EdgeEffectParameters {
{ // todo: this should come from the skin.
Hollow = !HitObject.HyperDash, AccentColour = colourForRrepesentation(HitObject.VisualRepresentation);
Type = EdgeEffectType.Glow,
Radius = 4, InternalChildren = new[]
Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f) {
}, createPulp(HitObject.VisualRepresentation),
Size = new Vector2(Height * 1.5f), border = new Circle
Anchor = Anchor.Centre, {
Origin = Anchor.Centre, EdgeEffect = new EdgeEffectParameters
BorderColour = Color4.White, {
BorderThickness = 4f, Hollow = !HitObject.HyperDash,
Children = new Framework.Graphics.Drawable[] Type = EdgeEffectType.Glow,
{ Radius = 4 * radius_adjust,
new Box Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Darken(1).Opacity(0.6f)
{ },
AlwaysPresent = true, Size = new Vector2(Height),
Colour = AccentColour, Anchor = Anchor.Centre,
Alpha = 0, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both BorderColour = Color4.White,
} BorderThickness = 3f * radius_adjust,
} Children = new Framework.Graphics.Drawable[]
}, {
}; new Box
{
if (HitObject.HyperDash) AlwaysPresent = true,
{ Colour = AccentColour,
Add(new Pulp Alpha = 0,
{ RelativeSizeAxes = Axes.Both
RelativePositionAxes = Axes.Both, }
Anchor = Anchor.Centre, }
Origin = Anchor.Centre, },
AccentColour = Color4.Red, };
Blending = BlendingMode.Additive,
Alpha = 0.5f, if (HitObject.HyperDash)
Scale = new Vector2(1.333f) {
}); AddInternal(new Pulp
} {
} RelativePositionAxes = Axes.Both,
Anchor = Anchor.Centre,
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation) Origin = Anchor.Centre,
{ AccentColour = Color4.Red,
const float large_pulp_3 = 13f; Blending = BlendingMode.Additive,
const float distance_from_centre_3 = 0.23f; Alpha = 0.5f,
Scale = new Vector2(1.333f)
const float large_pulp_4 = large_pulp_3 * 0.925f; });
const float distance_from_centre_4 = distance_from_centre_3 / 0.925f; }
}
const float small_pulp = large_pulp_3 / 2;
private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
Vector2 positionAt(float angle, float distance) => new Vector2( {
distance * (float)Math.Sin(angle * Math.PI / 180), const float large_pulp_3 = 8f * radius_adjust;
distance * (float)Math.Cos(angle * Math.PI / 180)); const float distance_from_centre_3 = 0.15f;
switch (representation) const float large_pulp_4 = large_pulp_3 * 0.925f;
{ const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
default:
return new Container(); const float small_pulp = large_pulp_3 / 2;
case FruitVisualRepresentation.Raspberry:
return new Container Vector2 positionAt(float angle, float distance) => new Vector2(
{ distance * (float)Math.Sin(angle * Math.PI / 180),
RelativeSizeAxes = Axes.Both, distance * (float)Math.Cos(angle * Math.PI / 180));
Children = new Framework.Graphics.Drawable[]
{ switch (representation)
new Pulp {
{ default:
Anchor = Anchor.TopCentre, return new Container();
Origin = Anchor.BottomCentre, case FruitVisualRepresentation.Raspberry:
AccentColour = AccentColour, return new Container
Size = new Vector2(small_pulp), {
Y = 0.05f, RelativeSizeAxes = Axes.Both,
}, Children = new Framework.Graphics.Drawable[]
new Pulp {
{ new Pulp
AccentColour = AccentColour, {
Size = new Vector2(large_pulp_4), AccentColour = AccentColour,
Position = positionAt(0, distance_from_centre_4), Size = new Vector2(small_pulp),
}, Y = -0.34f,
new Pulp },
{ new Pulp
AccentColour = AccentColour, {
Size = new Vector2(large_pulp_4), AccentColour = AccentColour,
Position = positionAt(90, distance_from_centre_4), Size = new Vector2(large_pulp_4),
}, Position = positionAt(0, distance_from_centre_4),
new Pulp },
{ new Pulp
AccentColour = AccentColour, {
Size = new Vector2(large_pulp_4), AccentColour = AccentColour,
Position = positionAt(180, distance_from_centre_4), Size = new Vector2(large_pulp_4),
}, Position = positionAt(90, distance_from_centre_4),
new Pulp },
{ new Pulp
Size = new Vector2(large_pulp_4), {
AccentColour = AccentColour, AccentColour = AccentColour,
Position = positionAt(270, distance_from_centre_4), Size = new Vector2(large_pulp_4),
}, Position = positionAt(180, distance_from_centre_4),
} },
}; new Pulp
case FruitVisualRepresentation.Pineapple: {
return new Container Size = new Vector2(large_pulp_4),
{ AccentColour = AccentColour,
RelativeSizeAxes = Axes.Both, Position = positionAt(270, distance_from_centre_4),
Children = new Framework.Graphics.Drawable[] },
{ }
new Pulp };
{ case FruitVisualRepresentation.Pineapple:
Anchor = Anchor.TopCentre, return new Container
Origin = Anchor.BottomCentre, {
AccentColour = AccentColour, RelativeSizeAxes = Axes.Both,
Size = new Vector2(small_pulp), Children = new Framework.Graphics.Drawable[]
Y = 0.1f, {
}, new Pulp
new Pulp {
{ AccentColour = AccentColour,
AccentColour = AccentColour, Size = new Vector2(small_pulp),
Size = new Vector2(large_pulp_4), Y = -0.3f,
Position = positionAt(45, distance_from_centre_4), },
}, new Pulp
new Pulp {
{ AccentColour = AccentColour,
AccentColour = AccentColour, Size = new Vector2(large_pulp_4),
Size = new Vector2(large_pulp_4), Position = positionAt(45, distance_from_centre_4),
Position = positionAt(135, distance_from_centre_4), },
}, new Pulp
new Pulp {
{ AccentColour = AccentColour,
AccentColour = AccentColour, Size = new Vector2(large_pulp_4),
Size = new Vector2(large_pulp_4), Position = positionAt(135, distance_from_centre_4),
Position = positionAt(225, distance_from_centre_4), },
}, new Pulp
new Pulp {
{ AccentColour = AccentColour,
Size = new Vector2(large_pulp_4), Size = new Vector2(large_pulp_4),
AccentColour = AccentColour, Position = positionAt(225, distance_from_centre_4),
Position = positionAt(315, distance_from_centre_4), },
}, new Pulp
} {
}; Size = new Vector2(large_pulp_4),
case FruitVisualRepresentation.Pear: AccentColour = AccentColour,
return new Container Position = positionAt(315, distance_from_centre_4),
{ },
RelativeSizeAxes = Axes.Both, }
Children = new Framework.Graphics.Drawable[] };
{ case FruitVisualRepresentation.Pear:
new Pulp return new Container
{ {
Anchor = Anchor.TopCentre, RelativeSizeAxes = Axes.Both,
Origin = Anchor.TopCentre, Children = new Framework.Graphics.Drawable[]
AccentColour = AccentColour, {
Size = new Vector2(small_pulp), new Pulp
Y = -0.1f, {
}, AccentColour = AccentColour,
new Pulp Size = new Vector2(small_pulp),
{ Y = -0.33f,
AccentColour = AccentColour, },
Size = new Vector2(large_pulp_3), new Pulp
Position = positionAt(60, distance_from_centre_3), {
}, AccentColour = AccentColour,
new Pulp Size = new Vector2(large_pulp_3),
{ Position = positionAt(60, distance_from_centre_3),
AccentColour = AccentColour, },
Size = new Vector2(large_pulp_3), new Pulp
Position = positionAt(180, distance_from_centre_3), {
}, AccentColour = AccentColour,
new Pulp Size = new Vector2(large_pulp_3),
{ Position = positionAt(180, distance_from_centre_3),
Size = new Vector2(large_pulp_3), },
AccentColour = AccentColour, new Pulp
Position = positionAt(300, distance_from_centre_3), {
}, Size = new Vector2(large_pulp_3),
} AccentColour = AccentColour,
}; Position = positionAt(300, distance_from_centre_3),
case FruitVisualRepresentation.Grape: },
return new Container }
{ };
RelativeSizeAxes = Axes.Both, case FruitVisualRepresentation.Grape:
Children = new Framework.Graphics.Drawable[] return new Container
{ {
new Pulp RelativeSizeAxes = Axes.Both,
{ Children = new Framework.Graphics.Drawable[]
Anchor = Anchor.TopCentre, {
Origin = Anchor.TopCentre, new Pulp
AccentColour = AccentColour, {
Size = new Vector2(small_pulp), AccentColour = AccentColour,
}, Size = new Vector2(small_pulp),
new Pulp Y = -0.25f,
{ },
AccentColour = AccentColour, new Pulp
Size = new Vector2(large_pulp_3), {
Position = positionAt(0, distance_from_centre_3), AccentColour = AccentColour,
}, Size = new Vector2(large_pulp_3),
new Pulp Position = positionAt(0, distance_from_centre_3),
{ },
AccentColour = AccentColour, new Pulp
Size = new Vector2(large_pulp_3), {
Position = positionAt(120, distance_from_centre_3), AccentColour = AccentColour,
}, Size = new Vector2(large_pulp_3),
new Pulp Position = positionAt(120, distance_from_centre_3),
{ },
Size = new Vector2(large_pulp_3), new Pulp
AccentColour = AccentColour, {
Position = positionAt(240, distance_from_centre_3), Size = new Vector2(large_pulp_3),
}, AccentColour = AccentColour,
} Position = positionAt(240, distance_from_centre_3),
}; },
case FruitVisualRepresentation.Banana: }
return new Container };
{ case FruitVisualRepresentation.Banana:
RelativeSizeAxes = Axes.Both, return new Container
Children = new Framework.Graphics.Drawable[] {
{ RelativeSizeAxes = Axes.Both,
new Pulp Children = new Framework.Graphics.Drawable[]
{ {
Anchor = Anchor.TopCentre, new Pulp
Origin = Anchor.TopCentre, {
AccentColour = AccentColour, AccentColour = AccentColour,
Size = new Vector2(small_pulp), Size = new Vector2(small_pulp),
Y = -0.15f Y = -0.3f
}, },
new Pulp new Pulp
{ {
AccentColour = AccentColour, AccentColour = AccentColour,
Size = new Vector2(large_pulp_4 * 1.2f, large_pulp_4 * 3), Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
}, Y = 0.05f,
} },
}; }
} };
} }
}
protected override void Update()
{ protected override void Update()
base.Update(); {
base.Update();
border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
} border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
} }
}
private Color4 colourForRrepesentation(FruitVisualRepresentation representation)
{
switch (representation)
{
default:
case FruitVisualRepresentation.Pear:
return new Color4(17, 136, 170, 255);
case FruitVisualRepresentation.Grape:
return new Color4(204, 102, 0, 255);
case FruitVisualRepresentation.Raspberry:
return new Color4(121, 9, 13, 255);
case FruitVisualRepresentation.Pineapple:
return new Color4(102, 136, 0, 255);
case FruitVisualRepresentation.Banana:
switch (RNG.Next(0, 3))
{
default:
return new Color4(255, 240, 0, 255);
case 1:
return new Color4(255, 192, 0, 255);
case 2:
return new Color4(214, 221, 28, 255);
}
}
}
}
}
@@ -1,40 +1,41 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Catch.Objects.Drawable namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
public class DrawableJuiceStream : DrawableCatchHitObject<JuiceStream> public class DrawableJuiceStream : DrawableCatchHitObject<JuiceStream>
{ {
private readonly Container dropletContainer; private readonly Container dropletContainer;
public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null) public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> getVisualRepresentation = null)
: base(s) : base(s)
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Origin = Anchor.BottomLeft; Origin = Anchor.BottomLeft;
X = 0; X = 0;
Child = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, }; InternalChild = dropletContainer = new Container { RelativeSizeAxes = Axes.Both, };
foreach (var o in s.NestedHitObjects.Cast<CatchHitObject>()) foreach (var o in s.NestedHitObjects.Cast<CatchHitObject>())
AddNested(getVisualRepresentation?.Invoke(o)); AddNested(getVisualRepresentation?.Invoke(o));
} }
protected override void AddNested(DrawableHitObject h) protected override bool ProvidesJudgement => false;
{
var catchObject = (DrawableCatchHitObject)h; protected override void AddNested(DrawableHitObject h)
{
catchObject.CheckPosition = o => CheckPosition?.Invoke(o) ?? false; var catchObject = (DrawableCatchHitObject)h;
catchObject.AccentColour = HitObject.ComboColour;
catchObject.CheckPosition = o => CheckPosition?.Invoke(o) ?? false;
dropletContainer.Add(h);
base.AddNested(h); dropletContainer.Add(h);
} base.AddNested(h);
} }
} }
}
@@ -0,0 +1,19 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Game.Rulesets.Catch.Judgements;
namespace osu.Game.Rulesets.Catch.Objects.Drawable
{
public class DrawableTinyDroplet : DrawableDroplet
{
public DrawableTinyDroplet(Droplet h)
: base(h)
{
Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
}
protected override CatchJudgement CreateJudgement() => new CatchTinyDropletJudgement();
}
}
@@ -1,42 +1,52 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
{ {
public class Pulp : Circle, IHasAccentColour public class Pulp : Circle, IHasAccentColour
{ {
public Pulp() public Pulp()
{ {
RelativePositionAxes = Axes.Both; RelativePositionAxes = Axes.Both;
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Blending = BlendingMode.Additive; Blending = BlendingMode.Additive;
Colour = Color4.White.Opacity(0.9f); Colour = Color4.White.Opacity(0.9f);
} }
private Color4 accentColour; private Color4 accentColour;
public Color4 AccentColour public Color4 AccentColour
{ {
get { return accentColour; } get { return accentColour; }
set set
{ {
accentColour = value; accentColour = value;
if (IsLoaded) updateAccentColour();
EdgeEffect = new EdgeEffectParameters }
{ }
Type = EdgeEffectType.Glow,
Radius = 8, private void updateAccentColour()
Colour = accentColour.Darken(0.2f).Opacity(0.75f) {
}; EdgeEffect = new EdgeEffectParameters
} {
} Type = EdgeEffectType.Glow,
} Radius = Size.X / 2,
} Colour = accentColour.Darken(0.2f).Opacity(0.75f)
};
}
protected override void LoadComplete()
{
base.LoadComplete();
updateAccentColour();
}
}
}
+9 -9
View File
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {
public class Droplet : CatchHitObject public class Droplet : CatchHitObject
{ {
} }
} }
+9 -9
View File
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {
public class Fruit : CatchHitObject public class Fruit : CatchHitObject
{ {
} }
} }
+165 -168
View File
@@ -1,168 +1,165 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
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.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using OpenTK; using OpenTK;
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {
public class JuiceStream : CatchHitObject, IHasCurve public class JuiceStream : CatchHitObject, IHasCurve
{ {
/// <summary> /// <summary>
/// Positional distance that results in a duration of one second, before any speed adjustments. /// Positional distance that results in a duration of one second, before any speed adjustments.
/// </summary> /// </summary>
private const float base_scoring_distance = 100; private const float base_scoring_distance = 100;
public readonly SliderCurve Curve = new SliderCurve(); public int RepeatCount { get; set; }
public int RepeatCount { get; set; } = 1; public double Velocity;
public double TickDistance;
public double Velocity;
public double TickDistance; protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
{
base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime);
TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime);
DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier;
double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; Velocity = scoringDistance / timingPoint.BeatLength;
TickDistance = scoringDistance / difficulty.SliderTickRate;
Velocity = scoringDistance / timingPoint.BeatLength; }
TickDistance = scoringDistance / difficulty.SliderTickRate;
} protected override void CreateNestedHitObjects()
{
protected override void CreateNestedHitObjects() base.CreateNestedHitObjects();
{ createTicks();
base.CreateNestedHitObjects(); }
createTicks(); private void createTicks()
} {
if (TickDistance == 0)
private void createTicks() return;
{
if (TickDistance == 0) var length = Curve.Distance;
return; var tickDistance = Math.Min(TickDistance, length);
var spanDuration = length / Velocity;
var length = Curve.Distance;
var tickDistance = Math.Min(TickDistance, length); var minDistanceFromEnd = Velocity * 0.01;
var repeatDuration = length / Velocity;
AddNested(new Fruit
var minDistanceFromEnd = Velocity * 0.01; {
Samples = Samples,
AddNested(new Fruit StartTime = StartTime,
{ X = X
Samples = Samples, });
ComboColour = ComboColour,
StartTime = StartTime, double lastDropletTime = StartTime;
X = X
}); for (int span = 0; span < this.SpanCount(); span++)
{
for (var repeat = 0; repeat < RepeatCount; repeat++) var spanStartTime = StartTime + span * spanDuration;
{ var reversed = span % 2 == 1;
var repeatStartTime = StartTime + repeat * repeatDuration;
var reversed = repeat % 2 == 1; for (double d = 0; d <= length; d += tickDistance)
{
for (var d = tickDistance; d <= length; d += tickDistance) var timeProgress = d / length;
{ var distanceProgress = reversed ? 1 - timeProgress : timeProgress;
if (d > length - minDistanceFromEnd)
break; double time = spanStartTime + timeProgress * spanDuration;
var timeProgress = d / length; if (LegacyLastTickOffset != null)
var distanceProgress = reversed ? 1 - timeProgress : timeProgress; {
// If we're the last tick, apply the legacy offset
var lastTickTime = repeatStartTime + timeProgress * repeatDuration; if (span == this.SpanCount() - 1 && d + tickDistance > length)
AddNested(new Droplet time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value);
{ }
StartTime = lastTickTime,
ComboColour = ComboColour, double tinyTickInterval = time - lastDropletTime;
X = Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, while (tinyTickInterval > 100)
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo tinyTickInterval /= 2;
{
Bank = s.Bank, for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval)
Name = @"slidertick", {
Volume = s.Volume double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration;
}))
}); AddNested(new TinyDroplet
} {
StartTime = t,
double tinyTickInterval = tickDistance / length * repeatDuration; X = X + Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH,
while (tinyTickInterval > 100) Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
tinyTickInterval /= 2; {
Bank = s.Bank,
for (double t = 0; t < repeatDuration; t += tinyTickInterval) Name = @"slidertick",
{ Volume = s.Volume
double progress = reversed ? 1 - t / repeatDuration : t / repeatDuration; }))
});
AddNested(new TinyDroplet }
{
StartTime = repeatStartTime + t, if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd)
ComboColour = ComboColour, {
X = Curve.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, AddNested(new Droplet
Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo {
{ StartTime = time,
Bank = s.Bank, X = X + Curve.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH,
Name = @"slidertick", Samples = new List<SampleInfo>(Samples.Select(s => new SampleInfo
Volume = s.Volume {
})) Bank = s.Bank,
}); Name = @"slidertick",
} Volume = s.Volume
}))
AddNested(new Fruit });
{ }
Samples = Samples,
ComboColour = ComboColour, lastDropletTime = time;
StartTime = repeatStartTime + repeatDuration, }
X = Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
}); AddNested(new Fruit
} {
} Samples = Samples,
StartTime = spanStartTime + spanDuration,
public double EndTime => StartTime + RepeatCount * Curve.Distance / Velocity; X = X + Curve.PositionAt(reversed ? 0 : 1).X / CatchPlayfield.BASE_WIDTH
});
public float EndX => Curve.PositionAt(ProgressAt(1)).X / CatchPlayfield.BASE_WIDTH; }
}
public double Duration => EndTime - StartTime;
public double EndTime => StartTime + this.SpanCount() * Curve.Distance / Velocity;
public double Distance
{ public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
get { return Curve.Distance; }
set { Curve.Distance = value; } public double Duration => EndTime - StartTime;
}
public double Distance
public List<Vector2> ControlPoints {
{ get { return Curve.Distance; }
get { return Curve.ControlPoints; } set { Curve.Distance = value; }
set { Curve.ControlPoints = value; } }
}
public SliderCurve Curve { get; } = new SliderCurve();
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
public List<Vector2> ControlPoints
public CurveType CurveType {
{ get { return Curve.ControlPoints; }
get { return Curve.CurveType; } set { Curve.ControlPoints = value; }
set { Curve.CurveType = value; } }
}
public List<List<SampleInfo>> RepeatSamples { get; set; } = new List<List<SampleInfo>>();
public Vector2 PositionAt(double progress) => Curve.PositionAt(ProgressAt(progress));
public CurveType CurveType
public double ProgressAt(double progress) {
{ get { return Curve.CurveType; }
double p = progress * RepeatCount % 1; set { Curve.CurveType = value; }
if (RepeatAt(progress) % 2 == 1) }
p = 1 - p;
return p; public double? LegacyLastTickOffset { get; set; }
} }
}
public int RepeatAt(double progress) => (int)(progress * RepeatCount);
}
}
@@ -1,9 +1,9 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Rulesets.Catch.Objects namespace osu.Game.Rulesets.Catch.Objects
{ {
public class TinyDroplet : Droplet public class TinyDroplet : Droplet
{ {
} }
} }
-25
View File
@@ -1,25 +0,0 @@
<configuration>
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
<!-- XQuartz compatibility (X11 on Mac) -->
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
</configuration>
@@ -1,28 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// We publish our internal attributes to other sub-projects of the framework.
// General Information about an assembly is controlled through the following // Note, that we omit visual tests as they are meant to test the framework
// set of attributes. Change these attribute values to modify the information // behavior "in the wild".
// associated with an assembly.
[assembly: AssemblyTitle("osu.Game.Rulesets.Catch")] [assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests")]
[assembly: AssemblyDescription("catch the fruit. to the beat.")] [assembly: InternalsVisibleTo("osu.Game.Rulesets.Catch.Tests.Dynamic")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ppy Pty Ltd")]
[assembly: AssemblyProduct("osu.Game.Rulesets.Catch")]
[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("58f6c80c-1253-4a0e-a465-b8c85ebeadf3")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,54 +1,121 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq; using System;
using osu.Game.Beatmaps; using System.Linq;
using osu.Game.Rulesets.Catch.Objects; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Replays; using osu.Game.Beatmaps;
using osu.Game.Users; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
namespace osu.Game.Rulesets.Catch.Replays using osu.Game.Rulesets.Replays;
{ using osu.Game.Users;
internal class CatchAutoGenerator : AutoGenerator<CatchHitObject>
{ namespace osu.Game.Rulesets.Catch.Replays
public const double RELEASE_DELAY = 20; {
internal class CatchAutoGenerator : AutoGenerator<CatchHitObject>
public CatchAutoGenerator(Beatmap<CatchHitObject> beatmap) {
: base(beatmap) public const double RELEASE_DELAY = 20;
{
Replay = new Replay { User = new User { Username = @"Autoplay" } }; public CatchAutoGenerator(Beatmap<CatchHitObject> beatmap)
} : base(beatmap)
{
protected Replay Replay; Replay = new Replay { User = new User { Username = @"Autoplay" } };
}
public override Replay Generate()
{ protected Replay Replay;
// Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
Replay.Frames.Add(new CatchReplayFrame(-100000, 0)); public override Replay Generate()
{
foreach (var obj in Beatmap.HitObjects) // todo: add support for HT DT
{ const double dash_speed = CatcherArea.Catcher.BASE_SPEED;
switch (obj) const double movement_speed = dash_speed / 2;
{ float lastPosition = 0.5f;
case Fruit _: double lastTime = 0;
Replay.Frames.Add(new CatchReplayFrame(obj.StartTime, obj.X));
break; // Todo: Realistically this shouldn't be needed, but the first frame is skipped with the way replays are currently handled
} Replay.Frames.Add(new CatchReplayFrame(-100000, lastPosition));
foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>()) void moveToNext(CatchHitObject h)
{ {
switch (nestedObj) float positionChange = Math.Abs(lastPosition - h.X);
{ double timeAvailable = h.StartTime - lastTime;
case BananaShower.Banana _:
case TinyDroplet _: //So we can either make it there without a dash or not.
case Droplet _: double speedRequired = positionChange / timeAvailable;
Replay.Frames.Add(new CatchReplayFrame(nestedObj.StartTime, nestedObj.X));
break; bool dashRequired = speedRequired > movement_speed && h.StartTime != 0;
}
} // todo: get correct catcher size, based on difficulty CS.
} const float catcher_width_half = CatcherArea.CATCHER_SIZE / CatchPlayfield.BASE_WIDTH * 0.3f * 0.5f;
return Replay; if (lastPosition - catcher_width_half < h.X && lastPosition + catcher_width_half > h.X)
} {
} //we are already in the correct range.
} lastTime = h.StartTime;
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, lastPosition));
return;
}
if (h is Banana)
{
// auto bananas unrealistically warp to catch 100% combo.
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
}
else if (h.HyperDash)
{
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable, lastPosition));
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
}
else if (dashRequired)
{
//we do a movement in two parts - the dash part then the normal part...
double timeAtNormalSpeed = positionChange / movement_speed;
double timeWeNeedToSave = timeAtNormalSpeed - timeAvailable;
double timeAtDashSpeed = timeWeNeedToSave / 2;
float midPosition = (float)Interpolation.Lerp(lastPosition, h.X, (float)timeAtDashSpeed / timeAvailable);
//dash movement
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + 1, lastPosition, true));
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeAvailable + timeAtDashSpeed, midPosition));
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
}
else
{
double timeBefore = positionChange / movement_speed;
Replay.Frames.Add(new CatchReplayFrame(h.StartTime - timeBefore, lastPosition));
Replay.Frames.Add(new CatchReplayFrame(h.StartTime, h.X));
}
lastTime = h.StartTime;
lastPosition = h.X;
}
foreach (var obj in Beatmap.HitObjects)
{
switch (obj)
{
case Fruit _:
moveToNext(obj);
break;
}
foreach (var nestedObj in obj.NestedHitObjects.Cast<CatchHitObject>())
{
switch (nestedObj)
{
case Banana _:
case TinyDroplet _:
case Droplet _:
case Fruit _:
moveToNext(nestedObj);
break;
}
}
}
return Replay;
}
}
}
@@ -1,32 +1,60 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Rulesets.Replays; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Replays;
namespace osu.Game.Rulesets.Catch.Replays
{ namespace osu.Game.Rulesets.Catch.Replays
public class CatchFramedReplayInputHandler : FramedReplayInputHandler {
{ public class CatchFramedReplayInputHandler : FramedReplayInputHandler<CatchReplayFrame>
public CatchFramedReplayInputHandler(Replay replay) {
: base(replay) public CatchFramedReplayInputHandler(Replay replay)
{ : base(replay)
} {
}
public override List<InputState> GetPendingStates() => new List<InputState>
{ protected override bool IsImportant(CatchReplayFrame frame) => frame.Position > 0;
new CatchReplayState
{ protected float? Position
PressedActions = new List<CatchAction> { CatchAction.PositionUpdate }, {
CatcherX = ((CatchReplayFrame)CurrentFrame).MouseX get
}, {
new CatchReplayState { PressedActions = new List<CatchAction>() }, if (!HasFrames)
}; return null;
public class CatchReplayState : ReplayState<CatchAction> return Interpolation.ValueAt(CurrentTime, CurrentFrame.Position, NextFrame.Position, CurrentFrame.Time, NextFrame.Time);
{ }
public float? CatcherX { get; set; } }
}
} public override List<IInput> GetPendingInputs()
} {
if (!Position.HasValue) return new List<IInput>();
var actions = new List<CatchAction>();
if (CurrentFrame.Dashing)
actions.Add(CatchAction.Dash);
if (Position.Value > CurrentFrame.Position)
actions.Add(CatchAction.MoveRight);
else if (Position.Value < CurrentFrame.Position)
actions.Add(CatchAction.MoveLeft);
return new List<IInput>
{
new CatchReplayState
{
PressedActions = actions,
CatcherX = Position.Value
},
};
}
public class CatchReplayState : ReplayState<CatchAction>
{
public float? CatcherX { get; set; }
}
}
}
@@ -1,17 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets.Replays; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.UI;
namespace osu.Game.Rulesets.Catch.Replays using osu.Game.Rulesets.Replays;
{ using osu.Game.Rulesets.Replays.Legacy;
public class CatchReplayFrame : ReplayFrame using osu.Game.Rulesets.Replays.Types;
{
public override bool IsImportant => MouseX > 0; namespace osu.Game.Rulesets.Catch.Replays
{
public CatchReplayFrame(double time, float? x = null) public class CatchReplayFrame : ReplayFrame, IConvertibleReplayFrame
: base(time, x ?? -1, null, ReplayButtonState.None) {
{ public float Position;
} public bool Dashing;
}
} public CatchReplayFrame()
{
}
public CatchReplayFrame(double time, float? position = null, bool dashing = false)
: base(time)
{
Position = position ?? -1;
Dashing = dashing;
}
public void ConvertFrom(LegacyReplayFrame legacyFrame, IBeatmap beatmap)
{
Position = legacyFrame.Position.X / CatchPlayfield.BASE_WIDTH;
Dashing = legacyFrame.ButtonState == ReplayButtonState.Left1;
}
}
}
@@ -0,0 +1,27 @@
osu file format v14
[Difficulty]
HPDrainRate:6
CircleSize:4
OverallDifficulty:7
ApproachRate:8.3
SliderMultiplier:1.6
SliderTickRate:1
[TimingPoints]
500,500,4,2,1,50,1,0
13426,-100,4,3,1,45,0,0
14884,-100,4,2,1,50,0,0
[HitObjects]
96,192,500,6,0,L|416:192,2,320
256,192,3000,12,0,4000,0:0:0:0:
256,192,4500,12,0,5500,0:0:0:0:
256,192,6000,12,0,6500,0:0:0:0:
256,128,7000,6,0,L|352:128,4,80
32,192,8500,6,0,B|32:384|256:384|256:192|256:192|256:0|512:0|512:192,1,800
256,192,11500,12,0,12000,0:0:0:0:
512,320,12500,6,0,B|0:256|0:256|512:96|512:96|256:32,1,1280
256,256,17000,6,0,L|160:256,4,80
256,192,18500,12,0,19450,0:0:0:0:
216,231,19875,6,0,B|216:135|280:135|344:135|344:199|344:263|248:327|248:327|120:327|120:327|56:39|408:39|408:39|472:150|408:342,1,1280
@@ -0,0 +1,65 @@
{
"Mappings": [{
"StartTime": 2589,
"Objects": [{
"StartTime": 2589,
"Position": 256
}]
},
{
"StartTime": 2915,
"Objects": [{
"StartTime": 2915,
"Position": 65
},
{
"StartTime": 2916,
"Position": 482
}
]
},
{
"StartTime": 3078,
"Objects": [{
"StartTime": 3078,
"Position": 164
},
{
"StartTime": 3079,
"Position": 315
}
]
},
{
"StartTime": 3241,
"Objects": [{
"StartTime": 3241,
"Position": 145
},
{
"StartTime": 3242,
"Position": 159
}
]
},
{
"StartTime": 3404,
"Objects": [{
"StartTime": 3404,
"Position": 310
},
{
"StartTime": 3405,
"Position": 441
}
]
},
{
"StartTime": 5197,
"Objects": [{
"StartTime": 5197,
"Position": 256
}]
}
]
}

Some files were not shown because too many files have changed in this diff Show More