mirror of
https://github.com/ppy/osu.git
synced 2026-05-15 07:42:37 +08:00
Compare commits
32 Commits
2020.325.0
..
0.7.2v
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"cake.tool": {
|
||||
"version": "0.35.0",
|
||||
"commands": [
|
||||
"dotnet-cake"
|
||||
]
|
||||
},
|
||||
"dotnet-format": {
|
||||
"version": "3.1.37601",
|
||||
"commands": [
|
||||
"dotnet-format"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-173
@@ -12,183 +12,16 @@ trim_trailing_whitespace = true
|
||||
|
||||
#PascalCase for public and protected members
|
||||
dotnet_naming_style.pascalcase.capitalization = pascal_case
|
||||
dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
|
||||
dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event
|
||||
dotnet_naming_rule.public_members_pascalcase.severity = error
|
||||
dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal
|
||||
dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event,delegate
|
||||
dotnet_naming_rule.public_members_pascalcase.severity = suggestion
|
||||
dotnet_naming_rule.public_members_pascalcase.symbols = public_members
|
||||
dotnet_naming_rule.public_members_pascalcase.style = pascalcase
|
||||
|
||||
#camelCase for private members
|
||||
dotnet_naming_style.camelcase.capitalization = camel_case
|
||||
|
||||
dotnet_naming_symbols.private_members.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event
|
||||
dotnet_naming_rule.private_members_camelcase.severity = warning
|
||||
dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event,delegate
|
||||
dotnet_naming_rule.private_members_camelcase.severity = suggestion
|
||||
dotnet_naming_rule.private_members_camelcase.symbols = private_members
|
||||
dotnet_naming_rule.private_members_camelcase.style = camelcase
|
||||
|
||||
dotnet_naming_symbols.local_function.applicable_kinds = local_function
|
||||
dotnet_naming_rule.local_function_camelcase.severity = warning
|
||||
dotnet_naming_rule.local_function_camelcase.symbols = local_function
|
||||
dotnet_naming_rule.local_function_camelcase.style = camelcase
|
||||
|
||||
#all_lower for private and local constants/static readonlys
|
||||
dotnet_naming_style.all_lower.capitalization = all_lower
|
||||
dotnet_naming_style.all_lower.word_separator = _
|
||||
|
||||
dotnet_naming_symbols.private_constants.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_constants.required_modifiers = const
|
||||
dotnet_naming_symbols.private_constants.applicable_kinds = field
|
||||
dotnet_naming_rule.private_const_all_lower.severity = warning
|
||||
dotnet_naming_rule.private_const_all_lower.symbols = private_constants
|
||||
dotnet_naming_rule.private_const_all_lower.style = all_lower
|
||||
|
||||
dotnet_naming_symbols.private_static_readonly.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_static_readonly.required_modifiers = static,readonly
|
||||
dotnet_naming_symbols.private_static_readonly.applicable_kinds = field
|
||||
dotnet_naming_rule.private_static_readonly_all_lower.severity = warning
|
||||
dotnet_naming_rule.private_static_readonly_all_lower.symbols = private_static_readonly
|
||||
dotnet_naming_rule.private_static_readonly_all_lower.style = all_lower
|
||||
|
||||
dotnet_naming_symbols.local_constants.applicable_kinds = local
|
||||
dotnet_naming_symbols.local_constants.required_modifiers = const
|
||||
dotnet_naming_rule.local_const_all_lower.severity = warning
|
||||
dotnet_naming_rule.local_const_all_lower.symbols = local_constants
|
||||
dotnet_naming_rule.local_const_all_lower.style = all_lower
|
||||
|
||||
#ALL_UPPER for non private constants/static readonlys
|
||||
dotnet_naming_style.all_upper.capitalization = all_upper
|
||||
dotnet_naming_style.all_upper.word_separator = _
|
||||
|
||||
dotnet_naming_symbols.public_constants.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
|
||||
dotnet_naming_symbols.public_constants.required_modifiers = const
|
||||
dotnet_naming_symbols.public_constants.applicable_kinds = field
|
||||
dotnet_naming_rule.public_const_all_upper.severity = warning
|
||||
dotnet_naming_rule.public_const_all_upper.symbols = public_constants
|
||||
dotnet_naming_rule.public_const_all_upper.style = all_upper
|
||||
|
||||
dotnet_naming_symbols.public_static_readonly.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
|
||||
dotnet_naming_symbols.public_static_readonly.required_modifiers = static,readonly
|
||||
dotnet_naming_symbols.public_static_readonly.applicable_kinds = field
|
||||
dotnet_naming_rule.public_static_readonly_all_upper.severity = warning
|
||||
dotnet_naming_rule.public_static_readonly_all_upper.symbols = public_static_readonly
|
||||
dotnet_naming_rule.public_static_readonly_all_upper.style = all_upper
|
||||
|
||||
#Roslyn formating options
|
||||
|
||||
#Formatting - indentation options
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = false
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
#Formatting - new line options
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
#csharp_new_line_before_members_in_anonymous_types = true
|
||||
#csharp_new_line_before_members_in_object_initializers = true # Currently no effect in VS/dotnet format (16.4), and makes Rider confusing
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
#Formatting - organize using options
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
#Formatting - spacing options
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
|
||||
#Formatting - wrapping options
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#Roslyn language styles
|
||||
|
||||
#Style - this. qualification
|
||||
dotnet_style_qualification_for_field = false:warning
|
||||
dotnet_style_qualification_for_property = false:warning
|
||||
dotnet_style_qualification_for_method = false:warning
|
||||
dotnet_style_qualification_for_event = false:warning
|
||||
|
||||
#Style - type names
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
|
||||
dotnet_style_predefined_type_for_member_access = true:warning
|
||||
csharp_style_var_when_type_is_apparent = true:none
|
||||
csharp_style_var_for_built_in_types = true:none
|
||||
csharp_style_var_elsewhere = true:silent
|
||||
|
||||
#Style - modifiers
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,new,abstract,virtual,sealed,override,static,readonly,extern,unsafe,volatile,async:warning
|
||||
|
||||
#Style - parentheses
|
||||
# Skipped because roslyn cannot separate +-*/ with << >>
|
||||
|
||||
#Style - expression bodies
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
csharp_style_expression_bodied_indexers = true:warning
|
||||
csharp_style_expression_bodied_methods = false:silent
|
||||
csharp_style_expression_bodied_operators = true:warning
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
csharp_style_expression_bodied_local_functions = true:silent
|
||||
|
||||
#Style - expression preferences
|
||||
dotnet_style_object_initializer = true:warning
|
||||
dotnet_style_collection_initializer = true:warning
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
|
||||
dotnet_style_prefer_auto_properties = true:warning
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_prefer_compound_assignment = true:warning
|
||||
|
||||
#Style - null/type checks
|
||||
dotnet_style_coalesce_expression = true:warning
|
||||
dotnet_style_null_propagation = true:warning
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:warning
|
||||
csharp_style_throw_expression = true:silent
|
||||
csharp_style_conditional_delegate_call = true:warning
|
||||
|
||||
#Style - unused
|
||||
dotnet_style_readonly_field = true:silent
|
||||
dotnet_code_quality_unused_parameters = non_public:silent
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:warning
|
||||
|
||||
#Style - variable declaration
|
||||
csharp_style_inlined_variable_declaration = true:warning
|
||||
csharp_style_deconstructed_variable_declaration = true:warning
|
||||
|
||||
#Style - other C# 7.x features
|
||||
dotnet_style_prefer_inferred_tuple_names = true:warning
|
||||
csharp_prefer_simple_default_expression = true:warning
|
||||
csharp_style_pattern_local_over_anonymous_function = true:warning
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
||||
|
||||
#Style - C# 8 features
|
||||
csharp_prefer_static_local_function = true:warning
|
||||
csharp_prefer_simple_using_statement = true:silent
|
||||
csharp_style_prefer_index_operator = true:warning
|
||||
csharp_style_prefer_range_operator = true:warning
|
||||
csharp_style_prefer_switch_expression = false:none
|
||||
|
||||
#Supressing roslyn built-in analyzers
|
||||
# Suppress: EC112
|
||||
|
||||
#Private method is unused
|
||||
dotnet_diagnostic.IDE0051.severity = silent
|
||||
#Private member is unused
|
||||
dotnet_diagnostic.IDE0052.severity = silent
|
||||
|
||||
#Rules for disposable
|
||||
dotnet_diagnostic.IDE0067.severity = none
|
||||
dotnet_diagnostic.IDE0068.severity = none
|
||||
dotnet_diagnostic.IDE0069.severity = none
|
||||
dotnet_naming_rule.private_members_camelcase.style = camelcase
|
||||
+19
-25
@@ -1,25 +1,19 @@
|
||||
# Autodetect text files and ensure that we normalise their
|
||||
# line endings to lf internally. When checked out they may
|
||||
# use different line endings.
|
||||
* text=auto
|
||||
|
||||
# Check out with crlf (Windows) line endings
|
||||
*.sln text eol=crlf
|
||||
*.csproj text eol=crlf
|
||||
*.cs text diff=csharp eol=crlf
|
||||
*.resx text eol=crlf
|
||||
*.vsixmanifest text eol=crlf
|
||||
packages.config text eol=crlf
|
||||
App.config text eol=crlf
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.snippet text eol=crlf
|
||||
*.manifest text eol=crlf
|
||||
*.licenseheader text eol=crlf
|
||||
|
||||
# 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
|
||||
# This won't normalise line endings, but it will ensure that merge drivers use CRLF
|
||||
* -text eol=crlf
|
||||
|
||||
# Currently in-use binary file extensions
|
||||
*.blend binary
|
||||
*.bmp binary
|
||||
*.dll binary
|
||||
*.exe binary
|
||||
*.icns binary
|
||||
*.ico binary
|
||||
*.jpg binary
|
||||
*.osz2 binary
|
||||
*.pdn binary
|
||||
*.psd binary
|
||||
*.PSD binary
|
||||
*.tga binary
|
||||
*.ttf binary
|
||||
*.wav binary
|
||||
*.xnb binary
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
custom: https://osu.ppy.sh/home/support
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Issues regarding encountered bugs.
|
||||
---
|
||||
**Describe the bug:**
|
||||
|
||||
**Screenshots or videos showing encountered issue:**
|
||||
|
||||
**osu!lazer version:**
|
||||
|
||||
**Logs:**
|
||||
<!--
|
||||
*please attach logs here, which are located at:*
|
||||
- `%AppData%/osu/logs` *(on Windows),*
|
||||
- `~/.local/share/osu/logs` *(on Linux & macOS).*
|
||||
-->
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
name: Crash Report
|
||||
about: Issues regarding crashes or permanent freezes.
|
||||
---
|
||||
**Describe the crash:**
|
||||
|
||||
**Screenshots or videos showing encountered issue:**
|
||||
|
||||
**osu!lazer version:**
|
||||
|
||||
**Logs:**
|
||||
<!--
|
||||
*please attach logs here, which are located at:*
|
||||
- `%AppData%/osu/logs` *(on Windows),*
|
||||
- `~/.local/share/osu/logs` *(on Linux & macOS).*
|
||||
-->
|
||||
|
||||
**Computer Specifications:**
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Features you would like to see in the game!
|
||||
---
|
||||
**Describe the new feature:**
|
||||
|
||||
**Proposal designs of the feature:**
|
||||
@@ -1,5 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: osu!stable issues
|
||||
url: https://github.com/ppy/osu-stable-issues
|
||||
about: For issues regarding osu!stable (not osu!lazer), open them here.
|
||||
+259
-336
@@ -1,336 +1,259 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# 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
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
Resource.designer.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake #
|
||||
/tools/**
|
||||
/build/tools/**
|
||||
/build/temp/**
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
.idea/modules.xml
|
||||
.idea/*.iml
|
||||
.idea/modules
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
|
||||
# inspectcode
|
||||
inspectcodereport.xml
|
||||
inspectcode
|
||||
|
||||
# BenchmarkDotNet
|
||||
/BenchmarkDotNet.Artifacts
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
bin/[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# 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
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
Staging/
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[submodule "osu-framework"]
|
||||
path = osu-framework
|
||||
url = https://github.com/ppy/osu-framework
|
||||
[submodule "osu-resources"]
|
||||
path = osu-resources
|
||||
url = https://github.com/ppy/osu-resources
|
||||
Generated
Generated
-1
@@ -1 +0,0 @@
|
||||
osu.Desktop
|
||||
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="osu-client-sqlite" uuid="1aa4b9be-cd8d-47ae-8186-30a13cd724a5">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$USER_HOME$/.local/share/osu/client.db</jdbc-url>
|
||||
<driver-properties>
|
||||
<property name="enable_load_extension" value="true" />
|
||||
</driver-properties>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
</project>
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ContentModelUserStore">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
|
||||
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu.Desktop/.idea/.idea.osu.Desktop.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu.Desktop/.idea/.idea.osu.Desktop.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu.Desktop/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu.Desktop/riderModule.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="1" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,20 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Benchmarks" type="DotNetProject" factoryName=".NET Project">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/netcoreapp3.1/osu.Game.Benchmarks.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--filter *" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Benchmarks/bin/Release/netcoreapp3.1" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Benchmarks/osu.Game.Benchmarks.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=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,21 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="CatchRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Catch.Tests/bin/Debug/netcoreapp3.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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,21 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="ManiaRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Mania.Tests/bin/Debug/netcoreapp3.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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,21 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="OsuRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Osu.Tests/bin/Debug/netcoreapp3.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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,21 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="TaikoRuleset (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Ruleset">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Rulesets.Taiko.Tests/bin/Debug/netcoreapp3.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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,20 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tournament" type="DotNetProject" factoryName=".NET Project" folderName="Tournament">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--tournament" />
|
||||
<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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,21 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Tournament (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="Tournament">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Game.Tournament.Tests" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Game.Tournament.Tests/osu.Game.Tournament.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=v3.1" />
|
||||
<browser url="http://localhost:5000" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,20 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu!" type="DotNetProject" factoryName=".NET Project" folderName="osu!">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,20 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! SDL" type="DotNetProject" factoryName=".NET Project" folderName="osu!">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--sdl" />
|
||||
<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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.0" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,20 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! (Tests)" type="DotNetProject" factoryName=".NET Project" folderName="osu!">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Game.Tests/bin/Debug/netcoreapp3.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="RUNTIME_ARGUMENTS" value="" />
|
||||
<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=v3.1" />
|
||||
<method v="2">
|
||||
<option name="Build" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
Generated
-16
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CommitMessageInspectionProfile">
|
||||
<profile version="1.0">
|
||||
<inspection_tool class="SubjectBodySeparation" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="GitSharedSettings">
|
||||
<option name="FORCE_PUSH_PROHIBITED_PATTERNS">
|
||||
<list />
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ContentModelUserStore">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.osu/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.osu/riderModule.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderProjectSettingsUpdater">
|
||||
<option name="vcsConfiguration" value="1" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,2 @@
|
||||
language: csharp
|
||||
solution: osu.sln
|
||||
Vendored
+51
-117
@@ -1,132 +1,66 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "osu! (Debug)",
|
||||
"type": "coreclr",
|
||||
"configurations": [{
|
||||
"name": "osu! VisualTests (Debug)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll"
|
||||
"--tests"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! VisualTests (Release)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
|
||||
"args": [
|
||||
"--tests"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Debug)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Release)",
|
||||
"type": "coreclr",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1/osu!.dll"
|
||||
],
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Tests, Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Debug)",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Tests, Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.1/osu.Game.Tests.dll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tests (Release)",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Tournament (Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1/osu!.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Debug)",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Tournament (Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1/osu!.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build osu! (Release)",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Tournament (Tests, Debug)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tournament tests (Debug)",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Tournament (Tests, Release)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "dotnet",
|
||||
"args": [
|
||||
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1/osu.Game.Tournament.Tests.dll",
|
||||
"--tournament"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build tournament tests (Release)",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Benchmark",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/netcoreapp3.1/osu.Game.Benchmarks.dll",
|
||||
"args": [
|
||||
"--filter",
|
||||
"*"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build benchmarks",
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Cake: Debug Script",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/tools/Cake.CoreCLR/0.30.0/Cake.dll",
|
||||
"args": [
|
||||
"${workspaceRoot}/build/build.cake",
|
||||
"--debug",
|
||||
"--verbosity=diagnostic"
|
||||
],
|
||||
"cwd": "${workspaceRoot}/build",
|
||||
"stopAtEntry": true,
|
||||
"externalConsole": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
}
|
||||
Vendored
+44
-99
@@ -2,125 +2,70 @@
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build osu! (Debug)",
|
||||
"tasks": [{
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Desktop",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/p:DebugType=portable",
|
||||
"/m",
|
||||
"/v:m"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:Configuration=Release",
|
||||
"/p:DebugType=portable",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
"/v:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build osu! (Release)",
|
||||
"label": "Clean (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:DebugType=portable",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/t:Clean",
|
||||
"/v:m"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Clean (Release)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Desktop",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/p:DebugType=portable",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
"/t:Clean",
|
||||
"/v:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build tests (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Tests",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
"label": "Clean All",
|
||||
"dependsOn": [
|
||||
"Clean (Debug)",
|
||||
"Clean (Release)"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build tests (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Tests",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build tournament tests (Debug)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Tournament.Tests",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build tournament tests (Release)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Tournament.Tests",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build benchmarks",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"--no-restore",
|
||||
"osu.Game.Benchmarks",
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/verbosity:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Restore (netcoreapp3.1)",
|
||||
"type": "shell",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"restore",
|
||||
"build/Desktop.proj"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# 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.
|
||||
@@ -1,6 +0,0 @@
|
||||
M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
|
||||
M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
|
||||
M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead.
|
||||
M:System.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead.
|
||||
T:System.IComparable;Don't use non-generic IComparable. Use generic version instead.
|
||||
M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RuleSet Name="osu! Rule Set" Description=" " ToolsVersion="16.0">
|
||||
<Rules AnalyzerId="Microsoft.CodeQuality.Analyzers" RuleNamespace="Microsoft.CodeQuality.Analyzers">
|
||||
<Rule Id="CA1016" Action="None" />
|
||||
<Rule Id="CA1028" Action="None" />
|
||||
<Rule Id="CA1031" Action="None" />
|
||||
<Rule Id="CA1034" Action="None" />
|
||||
<Rule Id="CA1036" Action="None" />
|
||||
<Rule Id="CA1040" Action="None" />
|
||||
<Rule Id="CA1044" Action="None" />
|
||||
<Rule Id="CA1051" Action="None" />
|
||||
<Rule Id="CA1054" Action="None" />
|
||||
<Rule Id="CA1056" Action="None" />
|
||||
<Rule Id="CA1062" Action="None" />
|
||||
<Rule Id="CA1063" Action="None" />
|
||||
<Rule Id="CA1067" Action="None" />
|
||||
<Rule Id="CA1707" Action="None" />
|
||||
<Rule Id="CA1710" Action="None" />
|
||||
<Rule Id="CA1714" Action="None" />
|
||||
<Rule Id="CA1716" Action="None" />
|
||||
<Rule Id="CA1717" Action="None" />
|
||||
<Rule Id="CA1720" Action="None" />
|
||||
<Rule Id="CA1721" Action="None" />
|
||||
<Rule Id="CA1724" Action="None" />
|
||||
<Rule Id="CA1801" Action="None" />
|
||||
<Rule Id="CA1806" Action="None" />
|
||||
<Rule Id="CA1812" Action="None" />
|
||||
<Rule Id="CA1814" Action="None" />
|
||||
<Rule Id="CA1815" Action="None" />
|
||||
<Rule Id="CA1819" Action="None" />
|
||||
<Rule Id="CA1822" Action="None" />
|
||||
<Rule Id="CA1823" Action="None" />
|
||||
<Rule Id="CA2007" Action="None" />
|
||||
<Rule Id="CA2214" Action="None" />
|
||||
<Rule Id="CA2227" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.CodeQuality.CSharp.Analyzers" RuleNamespace="Microsoft.CodeQuality.CSharp.Analyzers">
|
||||
<Rule Id="CA1001" Action="None" />
|
||||
<Rule Id="CA1032" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.NetCore.Analyzers" RuleNamespace="Microsoft.NetCore.Analyzers">
|
||||
<Rule Id="CA1303" Action="None" />
|
||||
<Rule Id="CA1304" Action="None" />
|
||||
<Rule Id="CA1305" Action="None" />
|
||||
<Rule Id="CA1307" Action="None" />
|
||||
<Rule Id="CA1308" Action="None" />
|
||||
<Rule Id="CA1816" Action="None" />
|
||||
<Rule Id="CA1826" Action="None" />
|
||||
<Rule Id="CA2000" Action="None" />
|
||||
<Rule Id="CA2008" Action="None" />
|
||||
<Rule Id="CA2213" Action="None" />
|
||||
<Rule Id="CA2235" Action="None" />
|
||||
</Rules>
|
||||
<Rules AnalyzerId="Microsoft.NetCore.CSharp.Analyzers" RuleNamespace="Microsoft.NetCore.CSharp.Analyzers">
|
||||
<Rule Id="CA1309" Action="Warning" />
|
||||
<Rule Id="CA2201" Action="Warning" />
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
@@ -1,46 +0,0 @@
|
||||
<!-- Contains required properties for osu!framework projects. -->
|
||||
<Project>
|
||||
<PropertyGroup Label="C#">
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>$(MSBuildThisFileDirectory)app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="License">
|
||||
<None Include="$(MSBuildThisFileDirectory)osu.licenseheader">
|
||||
<Link>osu.licenseheader</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Resources">
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Code Analysis">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Code Analysis">
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodeAnalysis\osu.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Documentation">
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<!-- DeepEqual is not netstandard-compatible. This is fine since we run tests with .NET Framework anyway.
|
||||
This is required due to https://github.com/NuGet/Home/issues/5740 -->
|
||||
<NoWarn>$(NoWarn);NU1701</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Nuget">
|
||||
<IsPackable>false</IsPackable>
|
||||
<Authors>ppy Pty Ltd</Authors>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://github.com/ppy/osu</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/ppy/osu</RepositoryUrl>
|
||||
<PackageReleaseNotes>Automated release.</PackageReleaseNotes>
|
||||
<Company>ppy Pty Ltd</Company>
|
||||
<Copyright>Copyright (c) 2020 ppy Pty Ltd</Copyright>
|
||||
<PackageTags>osu game</PackageTags>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,6 +0,0 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "fastlane"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.2)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
atomos (0.1.3)
|
||||
babosa (1.0.3)
|
||||
claide (1.0.3)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
commander-fastlane (4.4.6)
|
||||
highline (~> 1.7.2)
|
||||
declarative (0.0.10)
|
||||
declarative-option (0.1.0)
|
||||
digest-crc (0.4.1)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.7.5)
|
||||
emoji_regex (1.0.1)
|
||||
excon (0.71.1)
|
||||
faraday (0.17.3)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday-cookie_jar (0.0.6)
|
||||
faraday (>= 0.7.4)
|
||||
http-cookie (~> 1.0.0)
|
||||
faraday_middleware (0.13.1)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fastimage (2.1.7)
|
||||
fastlane (2.140.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.3, < 3.0.0)
|
||||
babosa (>= 1.0.2, < 2.0.0)
|
||||
bundler (>= 1.12.0, < 3.0.0)
|
||||
colored
|
||||
commander-fastlane (>= 4.4.6, < 5.0.0)
|
||||
dotenv (>= 2.1.1, < 3.0.0)
|
||||
emoji_regex (>= 0.1, < 2.0)
|
||||
excon (>= 0.71.0, < 1.0.0)
|
||||
faraday (~> 0.17)
|
||||
faraday-cookie_jar (~> 0.0.6)
|
||||
faraday_middleware (~> 0.13.1)
|
||||
fastimage (>= 2.1.0, < 3.0.0)
|
||||
gh_inspector (>= 1.1.2, < 2.0.0)
|
||||
google-api-client (>= 0.29.2, < 0.37.0)
|
||||
google-cloud-storage (>= 1.15.0, < 2.0.0)
|
||||
highline (>= 1.7.2, < 2.0.0)
|
||||
json (< 3.0.0)
|
||||
jwt (~> 2.1.0)
|
||||
mini_magick (>= 4.9.4, < 5.0.0)
|
||||
multi_xml (~> 0.5)
|
||||
multipart-post (~> 2.0.0)
|
||||
plist (>= 3.1.0, < 4.0.0)
|
||||
public_suffix (~> 2.0.0)
|
||||
rubyzip (>= 1.3.0, < 2.0.0)
|
||||
security (= 0.1.3)
|
||||
simctl (~> 1.6.3)
|
||||
slack-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-notifier (>= 2.0.0, < 3.0.0)
|
||||
terminal-table (>= 1.4.5, < 2.0.0)
|
||||
tty-screen (>= 0.6.3, < 1.0.0)
|
||||
tty-spinner (>= 0.8.0, < 1.0.0)
|
||||
word_wrap (~> 1.0.0)
|
||||
xcodeproj (>= 1.13.0, < 2.0.0)
|
||||
xcpretty (~> 0.3.0)
|
||||
xcpretty-travis-formatter (>= 0.0.3)
|
||||
fastlane-plugin-clean_testflight_testers (0.3.0)
|
||||
fastlane-plugin-souyuz (0.9.1)
|
||||
souyuz (= 0.9.1)
|
||||
fastlane-plugin-xamarin (0.6.3)
|
||||
gh_inspector (1.1.3)
|
||||
google-api-client (0.36.4)
|
||||
addressable (~> 2.5, >= 2.5.1)
|
||||
googleauth (~> 0.9)
|
||||
httpclient (>= 2.8.1, < 3.0)
|
||||
mini_mime (~> 1.0)
|
||||
representable (~> 3.0)
|
||||
retriable (>= 2.0, < 4.0)
|
||||
signet (~> 0.12)
|
||||
google-cloud-core (1.5.0)
|
||||
google-cloud-env (~> 1.0)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.3.0)
|
||||
faraday (~> 0.11)
|
||||
google-cloud-errors (1.0.0)
|
||||
google-cloud-storage (1.25.1)
|
||||
addressable (~> 2.5)
|
||||
digest-crc (~> 0.4)
|
||||
google-api-client (~> 0.33)
|
||||
google-cloud-core (~> 1.2)
|
||||
googleauth (~> 0.9)
|
||||
mini_mime (~> 1.0)
|
||||
googleauth (0.10.0)
|
||||
faraday (~> 0.12)
|
||||
jwt (>= 1.4, < 3.0)
|
||||
memoist (~> 0.16)
|
||||
multi_json (~> 1.11)
|
||||
os (>= 0.9, < 2.0)
|
||||
signet (~> 0.12)
|
||||
highline (1.7.10)
|
||||
http-cookie (1.0.3)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
json (2.3.0)
|
||||
jwt (2.1.0)
|
||||
memoist (0.16.2)
|
||||
mini_magick (4.10.1)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
multi_json (1.14.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nanaimo (0.2.6)
|
||||
naturally (2.2.0)
|
||||
nokogiri (1.10.7)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
os (1.0.1)
|
||||
plist (3.5.0)
|
||||
public_suffix (2.0.5)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rouge (2.0.7)
|
||||
rubyzip (1.3.0)
|
||||
security (0.1.3)
|
||||
signet (0.12.0)
|
||||
addressable (~> 2.3)
|
||||
faraday (~> 0.9)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simctl (1.6.7)
|
||||
CFPropertyList
|
||||
naturally
|
||||
slack-notifier (2.3.2)
|
||||
souyuz (0.9.1)
|
||||
fastlane (>= 1.103.0)
|
||||
highline (~> 1.7)
|
||||
nokogiri (~> 1.7)
|
||||
terminal-notifier (2.0.0)
|
||||
terminal-table (1.8.0)
|
||||
unicode-display_width (~> 1.1, >= 1.1.1)
|
||||
tty-cursor (0.7.0)
|
||||
tty-screen (0.7.0)
|
||||
tty-spinner (0.9.2)
|
||||
tty-cursor (~> 0.7)
|
||||
uber (0.1.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.6)
|
||||
unicode-display_width (1.6.1)
|
||||
word_wrap (1.0.0)
|
||||
xcodeproj (1.14.0)
|
||||
CFPropertyList (>= 2.3.3, < 4.0)
|
||||
atomos (~> 0.1.3)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.2.6)
|
||||
xcpretty (0.3.0)
|
||||
rouge (~> 2.0.7)
|
||||
xcpretty-travis-formatter (1.0.0)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
fastlane-plugin-clean_testflight_testers
|
||||
fastlane-plugin-souyuz
|
||||
fastlane-plugin-xamarin
|
||||
|
||||
BUNDLED WITH
|
||||
2.0.1
|
||||
@@ -0,0 +1,11 @@
|
||||
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
|
||||
|
||||
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,27 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
[string]$Target,
|
||||
[string]$Configuration,
|
||||
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
|
||||
[string]$Verbosity,
|
||||
[switch]$ShowDescription,
|
||||
[Alias("WhatIf", "Noop")]
|
||||
[switch]$DryRun,
|
||||
[Parameter(Position = 0, Mandatory = $false, ValueFromRemainingArguments = $true)]
|
||||
[string[]]$ScriptArgs
|
||||
)
|
||||
|
||||
# Build Cake arguments
|
||||
$cakeArguments = "";
|
||||
if ($Target) { $cakeArguments += "-target=$Target" }
|
||||
if ($Configuration) { $cakeArguments += "-configuration=$Configuration" }
|
||||
if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" }
|
||||
if ($ShowDescription) { $cakeArguments += "-showdescription" }
|
||||
if ($DryRun) { $cakeArguments += "-dryrun" }
|
||||
if ($Experimental) { $cakeArguments += "-experimental" }
|
||||
$cakeArguments += $ScriptArgs
|
||||
|
||||
dotnet tool restore
|
||||
dotnet cake ./build/InspectCode.cake --bootstrap
|
||||
dotnet cake ./build/InspectCode.cake $cakeArguments
|
||||
exit $LASTEXITCODE
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2020 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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,109 +1,32 @@
|
||||
<p align="center">
|
||||
<img width="500px" src="assets/lazer.png">
|
||||
</p>
|
||||
# osu! [](https://ci.appveyor.com/project/peppy/osu) [](https://www.codefactor.io/repository/github/ppy/osu) [](https://discord.gg/ppy)
|
||||
|
||||
# osu!
|
||||
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era!
|
||||
|
||||
[](https://ci.appveyor.com/project/peppy/osu)
|
||||
[]()
|
||||
[](https://www.codefactor.io/repository/github/ppy/osu)
|
||||
[](https://discord.gg/ppy)
|
||||
# Status
|
||||
|
||||
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Commonly known by the codename *osu!lazer*. Pew pew.
|
||||
This is still heavily under development and is not intended for end-user use. This repository is intended for developer collaboration. You're welcome to try and use it but please do not submit bug reports without a patch. Please do not ask for help building or using this software.
|
||||
|
||||
## Status
|
||||
# Requirements
|
||||
|
||||
This project is under heavy development, but is in a stable state. Users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve to the point of eventually replacing the existing stable client as an update.
|
||||
- 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.
|
||||
|
||||
We are accepting bug reports (please report with as much detail as possible and follow the existing issue templates). Feature requests are also welcome, but understand that our focus is on completing the game to feature parity before adding new features. A few resources are available as starting points to getting involved and understanding the project:
|
||||
# Getting Started
|
||||
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
|
||||
- Build in your IDE of choice (recommended IDEs automatically restore nuget packages; if you are using an alternative make sure to `nuget restore`)
|
||||
|
||||
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
|
||||
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
|
||||
- Read peppy's [latest blog post](https://blog.ppy.sh/a-definitive-lazer-faq/) exploring where lazer is currently and the roadmap going forward.
|
||||
# Contributing
|
||||
|
||||
## Running osu!
|
||||
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
|
||||
|
||||
If you are looking to install or test osu! without setting up a development environment, you can consume our [binary releases](https://github.com/ppy/osu/releases). Handy links below will download the latest version for your operating system of choice:
|
||||
Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
|
||||
|
||||
**Latest build:**
|
||||
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues).
|
||||
|
||||
| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
|
||||
| ------------- | ------------- | ------------- | ------------- | ------------- |
|
||||
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible.
|
||||
|
||||
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
|
||||
# Licence
|
||||
|
||||
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
|
||||
|
||||
## Developing or debugging
|
||||
|
||||
Please make sure you have the following prerequisites:
|
||||
|
||||
- A desktop platform with the [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) or higher installed.
|
||||
- When developing with mobile, [Xamarin](https://docs.microsoft.com/en-us/xamarin/) is required, which is shipped together with Visual Studio or [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/).
|
||||
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as [Visual Studio 2019+](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- When running on Linux, please have a system-wide FFmpeg installation available to support video decoding.
|
||||
|
||||
### Downloading the source code
|
||||
|
||||
Clone the repository:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/ppy/osu
|
||||
cd osu
|
||||
```
|
||||
|
||||
To update the source code to the latest commit, run the following command inside the `osu` directory:
|
||||
|
||||
```shell
|
||||
git pull
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this is provided [below](#contributing).
|
||||
|
||||
- Visual Studio / Rider users should load the project via one of the platform-specific `.slnf` files, rather than the main `.sln.` This will allow access to template run configurations.
|
||||
- Visual Studio Code users must run the `Restore` task before any build attempt.
|
||||
|
||||
You can also build and run *osu!* from the command-line with a single command:
|
||||
|
||||
```shell
|
||||
dotnet run --project osu.Desktop
|
||||
```
|
||||
|
||||
If you are not interested in debugging *osu!*, you can add `-c Release` to gain performance. In this case, you must replace `Debug` with `Release` in any commands mentioned in this document.
|
||||
|
||||
If the build fails, try to restore NuGet packages with `dotnet restore`.
|
||||
|
||||
_Due to a historical feature gap between .NET Core and Xamarin, running `dotnet` CLI from the root directory will not work for most commands. This can be resolved by specifying a target `.csproj` or the helper project at `build/Desktop.proj`. Configurations have been provided to work around this issue for all supported IDEs mentioned above._
|
||||
|
||||
### Testing with resource/framework modifications
|
||||
|
||||
Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be achieved by running some commands as documented on the [osu-resources](https://github.com/ppy/osu-resources/wiki/Testing-local-resources-checkout-with-other-projects) and [osu-framework](https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects) wiki pages.
|
||||
|
||||
### Code analysis
|
||||
|
||||
Before committing your code, please run a code formatter. This can be achieved by running `dotnet format` in the command line, or using the `Format code` command in your IDE.
|
||||
|
||||
We have adopted some cross-platform, compiler integrated analyzers. They can provide warnings when you are editing, building inside IDE or from command line, as-if they are provided by the compiler itself.
|
||||
|
||||
JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it from PowerShell with `.\InspectCode.ps1`, which is [only supported on Windows](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention of having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time to ensure no effort is wasted.
|
||||
|
||||
If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues) (especially those with the ["good first issue"](https://github.com/ppy/osu/issues?q=is%3Aopen+label%3Agood-first-issue+sort%3Aupdated-desc) label).
|
||||
|
||||
Before starting, please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
|
||||
|
||||
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured, with any libraries we are using, or with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as painless as possible.
|
||||
|
||||
For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via PayPal or osu!supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
|
||||
|
||||
## Licence
|
||||
|
||||
*osu!*'s code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source.
|
||||
The osu! client code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source.
|
||||
|
||||
Please note that this *does not cover* the usage of the "osu!" or "ppy" branding in any software, resources, advertising or promotion, as this is protected by trademark law.
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK;
|
||||
using Symcol.Core.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.GameObjects
|
||||
{
|
||||
public class SymcolHitbox : SymcolContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// whether we want to do hit detection
|
||||
/// </summary>
|
||||
public int Team { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// whether we want to do hit detection
|
||||
/// </summary>
|
||||
public bool HitDetection { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// the shape of this object (used for hit detection)
|
||||
/// </summary>
|
||||
public Shape Shape { get; }
|
||||
|
||||
public SymcolHitbox(Vector2 size, Shape shape = Shape.Circle)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Shape = shape;
|
||||
Size = size;
|
||||
|
||||
if (Shape == Shape.Circle)
|
||||
Child = new SymcolContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CornerRadius = Width / 2
|
||||
};
|
||||
else if (Shape == Shape.Rectangle)
|
||||
Child = new SymcolContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
}
|
||||
|
||||
public bool HitDetect(SymcolHitbox hitbox1, SymcolHitbox hitbox2)
|
||||
{
|
||||
if (hitbox1.HitDetection && hitbox2.HitDetection && hitbox1.Team != hitbox2.Team)
|
||||
{
|
||||
if (hitbox1.Shape == Shape.Circle && hitbox2.Shape == Shape.Circle)
|
||||
{
|
||||
if (hitbox1.ScreenSpaceDrawQuad.AABB.IntersectsWith(hitbox2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
else if (hitbox1.Shape == Shape.Circle && hitbox2.Shape == Shape.Rectangle || hitbox1.Shape == Shape.Rectangle && hitbox2.Shape == Shape.Circle)
|
||||
{
|
||||
if (hitbox1.ScreenSpaceDrawQuad.AABB.IntersectsWith(hitbox2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
else if (hitbox1.Shape == Shape.Rectangle && hitbox2.Shape == Shape.Rectangle)
|
||||
{
|
||||
if (hitbox1.ScreenSpaceDrawQuad.AABB.IntersectsWith(hitbox2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
else if (hitbox1.Shape == Shape.Complex || hitbox2.Shape == Shape.Complex)
|
||||
foreach (SymcolContainer child1 in hitbox1.Children)
|
||||
foreach (SymcolContainer child2 in hitbox2.Children)
|
||||
if (child1.ScreenSpaceDrawQuad.AABB.IntersectsWith(child2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Shape
|
||||
{
|
||||
Circle,
|
||||
Rectangle,
|
||||
Complex
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// Will support base eden game functions (if we come up with any)
|
||||
/// </summary>
|
||||
public class SymcolClickableContainer : ClickableContainer
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// Will support base eden game functions (if we come up with any)
|
||||
/// </summary>
|
||||
public class SymcolContainer : Container
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
public class SymcolDialContainer : CircularContainer
|
||||
{
|
||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
private Vector2 mousePosition;
|
||||
|
||||
private float lastAngle;
|
||||
private float currentRotation;
|
||||
public float RotationAbsolute;
|
||||
|
||||
private int completeTick;
|
||||
|
||||
private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360));
|
||||
|
||||
private bool rotationTransferred;
|
||||
|
||||
protected override bool OnMouseMove(InputState state)
|
||||
{
|
||||
mousePosition = Parent.ToLocalSpace(state.Mouse.NativeState.Position);
|
||||
return base.OnMouseMove(state);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
|
||||
|
||||
|
||||
if (!rotationTransferred)
|
||||
{
|
||||
currentRotation = Rotation * 2;
|
||||
rotationTransferred = true;
|
||||
}
|
||||
|
||||
if (thisAngle - lastAngle > 180)
|
||||
lastAngle += 360;
|
||||
else if (lastAngle - thisAngle > 180)
|
||||
lastAngle -= 360;
|
||||
|
||||
currentRotation += thisAngle - lastAngle;
|
||||
RotationAbsolute += Math.Abs(thisAngle - lastAngle);
|
||||
|
||||
lastAngle = thisAngle;
|
||||
|
||||
foreach(Drawable drawable in Children)
|
||||
drawable.RotateTo(currentRotation / 2, 200, Easing.OutExpo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
public class SymcolDragContainer : SymcolContainer
|
||||
{
|
||||
protected override bool OnDragStart(InputState state) => true;
|
||||
|
||||
public bool AllowLeftClickDrag { get; set; } = true;
|
||||
|
||||
private bool drag;
|
||||
|
||||
private Vector2 startPosition;
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
startPosition = Position;
|
||||
|
||||
if (args.Button == MouseButton.Left && AllowLeftClickDrag || args.Button == MouseButton.Right)
|
||||
drag = true;
|
||||
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (drag)
|
||||
Position = startPosition + state.Mouse.Position - state.Mouse.PositionMouseDown.GetValueOrDefault();
|
||||
|
||||
return base.OnDrag(state);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButton.Left && AllowLeftClickDrag || args.Button == MouseButton.Right)
|
||||
drag = false;
|
||||
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using Symcol.Core.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.UserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// just a Button with a sprite
|
||||
/// </summary>
|
||||
public class SpriteButton : SymcolClickableContainer
|
||||
{
|
||||
private readonly string textureName;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get { return spriteText?.Text; }
|
||||
set
|
||||
{
|
||||
if (spriteText != null)
|
||||
spriteText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Sprite sprite;
|
||||
private readonly SpriteText spriteText;
|
||||
|
||||
public SpriteButton(string textureName)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
this.textureName = textureName;
|
||||
Masking = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sprite = new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill
|
||||
},
|
||||
spriteText = new SpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
sprite.Texture = textures.Get(textureName);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
if (Enabled.Value)
|
||||
{
|
||||
var flash = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
};
|
||||
|
||||
Add(flash);
|
||||
|
||||
flash.Blending = BlendingMode.Additive;
|
||||
flash.FadeOut(200);
|
||||
flash.Expire();
|
||||
}
|
||||
|
||||
return base.OnClick(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using Symcol.Core.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.UserInterface
|
||||
{
|
||||
public class SymcolWindow : SymcolContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Put all your stuff in this
|
||||
/// </summary>
|
||||
public SymcolContainer WindowContent { get; set; }
|
||||
public SpriteText WindowTitle;
|
||||
|
||||
private readonly SymcolContainer topBar;
|
||||
private readonly SymcolClickableContainer minimize;
|
||||
|
||||
public SymcolWindow(Vector2 size)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
CornerRadius = 6;
|
||||
Masking = true;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
topBar = new SymcolContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Height = 20,
|
||||
Width = size.X,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
},
|
||||
WindowTitle = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
TextSize = 18
|
||||
},
|
||||
new SymcolClickableContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 30,
|
||||
Action = Close,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.Red,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
}
|
||||
},
|
||||
minimize = new SymcolClickableContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 30,
|
||||
Position = new Vector2(-30, 0),
|
||||
Action = Minimize,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
WindowContent = new SymcolContainer
|
||||
{
|
||||
Size = size,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
}
|
||||
};
|
||||
|
||||
WindowContent.Position = new Vector2(0, topBar.Height);
|
||||
}
|
||||
|
||||
protected void Close()
|
||||
{
|
||||
this.FadeOut(200);
|
||||
}
|
||||
|
||||
protected void Open()
|
||||
{
|
||||
this.FadeIn(200);
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
if (Alpha > 0)
|
||||
this.FadeOut(200);
|
||||
else
|
||||
this.FadeIn(200);
|
||||
}
|
||||
|
||||
protected override bool OnDragStart(InputState state) => true;
|
||||
|
||||
private bool drag;
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButton.Left)
|
||||
drag = true;
|
||||
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (drag)
|
||||
Position += state.Mouse.Delta;
|
||||
|
||||
return base.OnDrag(state);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButton.Left)
|
||||
drag = false;
|
||||
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
|
||||
public void Maximize()
|
||||
{
|
||||
WindowContent.FadeIn(200);
|
||||
WindowContent.ScaleTo(Vector2.One, 200);
|
||||
minimize.Action = Minimize;
|
||||
}
|
||||
|
||||
public void Minimize()
|
||||
{
|
||||
WindowContent.FadeOut(200);
|
||||
WindowContent.ScaleTo(new Vector2(1, 0), 200);
|
||||
minimize.Action = Maximize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class BasicPacket : Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// Ask host if we can connect
|
||||
/// </summary>
|
||||
public bool Connect;
|
||||
|
||||
/// <summary>
|
||||
/// Tell the host we are breaking up
|
||||
/// </summary>
|
||||
public bool Disconnect;
|
||||
|
||||
/// <summary>
|
||||
/// Testing Connection
|
||||
/// </summary>
|
||||
public bool Test;
|
||||
|
||||
/// <summary>
|
||||
/// Send a force exit to others
|
||||
/// </summary>
|
||||
public bool Abort;
|
||||
|
||||
/// <summary>
|
||||
/// PreLoad the game
|
||||
/// </summary>
|
||||
public bool LoadGame;
|
||||
|
||||
/// <summary>
|
||||
/// Request a list of all players from Host
|
||||
/// </summary>
|
||||
public bool RequestPlayerList;
|
||||
|
||||
/// <summary>
|
||||
/// List of players in this match that we should account for
|
||||
/// </summary>
|
||||
public List<ClientInfo> PlayerList = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Tell Host we are PreLoaded
|
||||
/// </summary>
|
||||
public bool Loaded;
|
||||
|
||||
/// <summary>
|
||||
/// Start the game already!
|
||||
/// </summary>
|
||||
public bool StartGame;
|
||||
|
||||
/// <summary>
|
||||
/// Send to host when game started
|
||||
/// </summary>
|
||||
public bool GameStarted;
|
||||
|
||||
public BasicPacket(ClientInfo clientInfo) : base(clientInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a client signature basically
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ClientInfo
|
||||
{
|
||||
public string IP;
|
||||
|
||||
public int Port;
|
||||
|
||||
public int Ping;
|
||||
|
||||
public int ConncetionTryCount;
|
||||
|
||||
public double LastConnectionTime;
|
||||
|
||||
public double StartedTestConnectionTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
public class NetworkingClient
|
||||
{
|
||||
public UdpClient UdpClient;
|
||||
|
||||
public IPEndPoint EndPoint;
|
||||
|
||||
/// <summary>
|
||||
/// if false we only receive
|
||||
/// </summary>
|
||||
public readonly bool Send;
|
||||
|
||||
public readonly int Port;
|
||||
|
||||
public readonly string IP;
|
||||
|
||||
public NetworkingClient(bool send, string ip, int port = 25570)
|
||||
{
|
||||
Port = port;
|
||||
IP = ip;
|
||||
|
||||
if (send)
|
||||
initializeSend();
|
||||
else
|
||||
initializeReceive();
|
||||
}
|
||||
|
||||
private void initializeSend()
|
||||
{
|
||||
UdpClient = new UdpClient(IP, Port);
|
||||
}
|
||||
|
||||
private void initializeReceive()
|
||||
{
|
||||
UdpClient = new UdpClient(Port);
|
||||
EndPoint = new IPEndPoint(IPAddress.Any, Port);
|
||||
}
|
||||
|
||||
private void sendByte(byte[] data)
|
||||
{
|
||||
UdpClient.Send(data, data.Length);
|
||||
}
|
||||
|
||||
private byte[] receiveByte()
|
||||
{
|
||||
return UdpClient.Receive(ref EndPoint);
|
||||
}
|
||||
|
||||
public static int SENTPACKETCOUNT;
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet somewhere
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendPacket(Packet packet)
|
||||
{
|
||||
SENTPACKETCOUNT++;
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
formatter.Serialize(stream, packet);
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
int i = packet.PacketSize;
|
||||
retry:
|
||||
byte[] data = new byte[i];
|
||||
|
||||
try
|
||||
{
|
||||
stream.Read(data, 0, (int)stream.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
i *= 2;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
sendByte(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Receive a Packet from somewhere
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Packet ReceivePacket(bool force = false)
|
||||
{
|
||||
if (UdpClient.Available > 0 || force)
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
byte[] data = receiveByte();
|
||||
stream.Write(data, 0, data.Length);
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
Packet packet = (Packet)formatter.Deserialize(stream);
|
||||
packet.ClientInfo.IP = EndPoint.Address.ToString();
|
||||
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (UdpClient != null)
|
||||
UdpClient.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,646 @@
|
||||
#define SoloTesting
|
||||
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
//TODO: This NEEDS its own clock to avoid fuckery later on with DoubleTime and HalfTime
|
||||
public class NetworkingClientHandler : Container
|
||||
{
|
||||
//30 Seconds by default
|
||||
protected virtual double TimeOutTime => 30000;
|
||||
|
||||
protected readonly NetworkingClient ReceiveClient;
|
||||
|
||||
protected readonly NetworkingClient SendClient;
|
||||
|
||||
/// <summary>
|
||||
/// Just a client signature basically
|
||||
/// </summary>
|
||||
public ClientInfo ClientInfo;
|
||||
|
||||
/// <summary>
|
||||
/// All Connecting clients
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> ConnectingClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// All Connected clients
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> ConncetedClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Clients waiting in our match
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> InMatchClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Clients loaded and ready to start
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> LoadedClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Clients ingame playing
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> InGameClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets hit when we get a Packet
|
||||
/// </summary>
|
||||
public Action<Packet> OnPacketReceive;
|
||||
|
||||
/// <summary>
|
||||
/// (Peer) Call this when we connect to a Host (Includes list of connected peers + Host)
|
||||
/// </summary>
|
||||
public Action<List<ClientInfo>> OnConnectedToHost;
|
||||
|
||||
/// <summary>
|
||||
/// (Host) Whenever a new client Connects
|
||||
/// </summary>
|
||||
public Action<ClientInfo> OnClientConnect;
|
||||
|
||||
/// <summary>
|
||||
/// (Host) Whenever a new client Disconnects
|
||||
/// </summary>
|
||||
public Action<ClientInfo> OnClientDisconnect;
|
||||
|
||||
/// <summary>
|
||||
/// (Host/Peer) When a new Client joins the game
|
||||
/// </summary>
|
||||
public Action<ClientInfo> OnClientJoin;
|
||||
|
||||
/// <summary>
|
||||
/// Receive a full player list
|
||||
/// </summary>
|
||||
public Action<List<ClientInfo>> OnReceivePlayerList;
|
||||
|
||||
/// <summary>
|
||||
/// if we are connected and in a match
|
||||
/// </summary>
|
||||
public bool InMatch;
|
||||
|
||||
/// <summary>
|
||||
/// Are we in a game
|
||||
/// </summary>
|
||||
public bool InGame;
|
||||
|
||||
/// <summary>
|
||||
/// Are we loaded and ready to start?
|
||||
/// </summary>
|
||||
public bool Loaded;
|
||||
|
||||
/// <summary>
|
||||
/// Called to leave an in-progress game
|
||||
/// </summary>
|
||||
public Action OnAbort;
|
||||
|
||||
/// <summary>
|
||||
/// Called to load the game (Includes Host)
|
||||
/// </summary>
|
||||
public Action<List<ClientInfo>> OnLoadGame;
|
||||
|
||||
/// <summary>
|
||||
/// Called to start the game once loaded
|
||||
/// </summary>
|
||||
public Action StartGame;
|
||||
|
||||
public readonly ClientType ClientType;
|
||||
|
||||
public NetworkingClientHandler(ClientType type, string ip, int port = 25570, string thisLocalIp = "0.0.0.0")
|
||||
{
|
||||
AlwaysPresent = true;
|
||||
|
||||
ClientType = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ClientType.Host:
|
||||
ReceiveClient = new NetworkingClient(false, ip, port);
|
||||
break;
|
||||
case ClientType.Peer:
|
||||
ReceiveClient = new NetworkingClient(false, thisLocalIp, port);
|
||||
SendClient = new NetworkingClient(true, ip, port);
|
||||
break;
|
||||
case ClientType.Server:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Logger.Log("Created a RulesetNetworkingClientHandler", LoggingTarget.Network, LogLevel.Verbose);
|
||||
|
||||
if (ClientInfo == null)
|
||||
ClientInfo = new ClientInfo
|
||||
{
|
||||
Port = port
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (ClientType == ClientType.Peer)
|
||||
ConnectToHost();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
PacketRestart:
|
||||
Packet p = null;
|
||||
|
||||
if (ReceiveClient.UdpClient.Available > 0)
|
||||
p = ReceiveClient.ReceivePacket();
|
||||
|
||||
if (p is BasicPacket packet)
|
||||
{
|
||||
//Hosts
|
||||
if (SendClient == null)
|
||||
{
|
||||
if (packet.Disconnect)
|
||||
{
|
||||
OnClientDisconnect?.Invoke(packet.ClientInfo);
|
||||
foreach (ClientInfo client in ConnectingClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
ConnectingClients.Remove(client);
|
||||
Logger.Log("A Connecting Client has Disconnected", LoggingTarget.Network, LogLevel.Verbose);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in ConncetedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
ConncetedClients.Remove(client);
|
||||
Logger.Log("A Client has Disconnected", LoggingTarget.Network, LogLevel.Verbose);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in InMatchClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
InMatchClients.Remove(client);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in LoadedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
LoadedClients.Remove(client);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in InGameClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
InGameClients.Remove(client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.Connect)
|
||||
{
|
||||
packet.ClientInfo.StartedTestConnectionTime = Time.Current;
|
||||
ConnectingClients.Add(packet.ClientInfo);
|
||||
|
||||
NetworkingClient client = new NetworkingClient(true, packet.ClientInfo.IP, packet.ClientInfo.Port);
|
||||
|
||||
List<ClientInfo> playerList = new List<ClientInfo>
|
||||
{
|
||||
ClientInfo
|
||||
};
|
||||
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
playerList.Add(clientInfo);
|
||||
|
||||
client.SendPacket(new BasicPacket(ClientInfo)
|
||||
{
|
||||
PlayerList = playerList,
|
||||
Connect = true
|
||||
});
|
||||
|
||||
Logger.Log("A Client is Connecting. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.RequestPlayerList)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, packet.ClientInfo.IP, packet.ClientInfo.Port);
|
||||
|
||||
List<ClientInfo> playerList = new List<ClientInfo>
|
||||
{
|
||||
ClientInfo
|
||||
};
|
||||
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
playerList.Add(clientInfo);
|
||||
|
||||
client.SendPacket(new BasicPacket(ClientInfo)
|
||||
{
|
||||
PlayerList = playerList,
|
||||
RequestPlayerList = true
|
||||
});
|
||||
|
||||
Logger.Log("A Client is Connecting. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.Loaded)
|
||||
foreach (ClientInfo client in InMatchClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
Logger.Log("A Client has Loaded and is ready to start", LoggingTarget.Network, LogLevel.Verbose);
|
||||
InMatchClients.Remove(client);
|
||||
LoadedClients.Add(client);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet.GameStarted)
|
||||
foreach (ClientInfo client in LoadedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
Logger.Log("A Client has started!", LoggingTarget.Network, LogLevel.Verbose);
|
||||
LoadedClients.Remove(client);
|
||||
InGameClients.Add(client);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet.Test)
|
||||
{
|
||||
foreach (ClientInfo client in ConnectingClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
client.Ping = (int)Time.Current - (int)client.StartedTestConnectionTime;
|
||||
ConnectingClients.Remove(client);
|
||||
ConncetedClients.Add(client);
|
||||
InMatchClients.Add(client);
|
||||
OnClientJoin?.Invoke(client);
|
||||
client.LastConnectionTime = Time.Current;
|
||||
client.ConncetionTryCount = 0;
|
||||
Logger.Log("Successfully connected to a Client! Ping: " + client.Ping, LoggingTarget.Network, LogLevel.Verbose);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in ConncetedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
client.Ping = (int)Time.Current - (int)client.StartedTestConnectionTime;
|
||||
client.LastConnectionTime = Time.Current;
|
||||
client.ConncetionTryCount = 0;
|
||||
Logger.Log("Successfully maintained connection to a Client! Ping: " + client.Ping, LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !SoloTesting
|
||||
if (InMatchClients.Count == 0 && LoadedClients.Count > 0 && Loaded && !InGame)
|
||||
SendStartGame();
|
||||
#endif
|
||||
|
||||
//Peers
|
||||
else if (SendClient != null)
|
||||
{
|
||||
if (packet.Connect)
|
||||
{
|
||||
if (!InGame && !InMatch)
|
||||
{
|
||||
InMatch = true;
|
||||
OnConnectedToHost?.Invoke(packet.PlayerList);
|
||||
}
|
||||
Logger.Log("Connected to Host!", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.Test)
|
||||
{
|
||||
SendToHost(new BasicPacket(ClientInfo) { Test = true });
|
||||
Logger.Log("Received connection test info from host, returning. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.RequestPlayerList)
|
||||
OnReceivePlayerList?.Invoke(packet.PlayerList);
|
||||
|
||||
if (packet.StartGame)
|
||||
{
|
||||
StartGame?.Invoke();
|
||||
SendToHost(new BasicPacket(ClientInfo) { GameStarted = true });
|
||||
InGame = true;
|
||||
}
|
||||
|
||||
if (packet.Abort)
|
||||
{
|
||||
OnAbort?.Invoke();
|
||||
InGame = false;
|
||||
Loaded = false;
|
||||
}
|
||||
|
||||
if (packet.LoadGame)
|
||||
{
|
||||
Logger.Log("Received instructions to LoadGame for " + packet.PlayerList.Count + " players", LoggingTarget.Network, LogLevel.Verbose);
|
||||
OnLoadGame?.Invoke(packet.PlayerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SoloTesting
|
||||
if (Loaded && !InGame)
|
||||
SendStartGame();
|
||||
#endif
|
||||
|
||||
if (p != null)
|
||||
OnPacketReceive?.Invoke(p);
|
||||
|
||||
if (ReceiveClient.UdpClient.Available > 0)
|
||||
goto PacketRestart;
|
||||
|
||||
foreach (ClientInfo client in ConnectingClients)
|
||||
{
|
||||
if (client.LastConnectionTime + TimeOutTime / 10 <= Time.Current && client.ConncetionTryCount == 0)
|
||||
{
|
||||
client.StartedTestConnectionTime = Time.Current;
|
||||
TestConnection(client);
|
||||
}
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 6 <= Time.Current && client.ConncetionTryCount == 1)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 3 <= Time.Current && client.ConncetionTryCount == 2)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.StartedTestConnectionTime + TimeOutTime <= Time.Current)
|
||||
{
|
||||
ConnectingClients.Remove(client);
|
||||
Logger.Log("Connection to a connecting client lost! - " + client.IP + ":" + client.Port, LoggingTarget.Network, LogLevel.Error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ClientInfo client in ConncetedClients)
|
||||
{
|
||||
if (client.LastConnectionTime + TimeOutTime / 6 <= Time.Current && client.ConncetionTryCount == 0)
|
||||
{
|
||||
client.StartedTestConnectionTime = Time.Current;
|
||||
TestConnection(client);
|
||||
}
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 3 <= Time.Current && client.ConncetionTryCount == 1)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 2 <= Time.Current && client.ConncetionTryCount == 2)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.StartedTestConnectionTime + TimeOutTime <= Time.Current)
|
||||
{
|
||||
ConncetedClients.Remove(client);
|
||||
InGameClients.Remove(client);
|
||||
LoadedClients.Remove(client);
|
||||
InGameClients.Remove(client);
|
||||
Logger.Log("Connection to a connected client lost! - " + client.IP + ":" + client.Port, LoggingTarget.Network, LogLevel.Error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Poke!
|
||||
/// </summary>
|
||||
/// <param name="clientInfo"></param>
|
||||
protected void TestConnection(ClientInfo clientInfo)
|
||||
{
|
||||
clientInfo.ConncetionTryCount++;
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(new BasicPacket(ClientInfo) { Test = true });
|
||||
Logger.Log("Testing a client's connection - " + clientInfo.IP + ":" + clientInfo.Port, LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
public void RequestPlayerList()
|
||||
{
|
||||
BasicPacket packet = new BasicPacket(ClientInfo) { RequestPlayerList = true };
|
||||
SendToHost(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell peers to start loading game
|
||||
/// </summary>
|
||||
public virtual void StartLoadingGame()
|
||||
{
|
||||
if (SendClient == null)
|
||||
{
|
||||
BasicPacket packet = new BasicPacket(ClientInfo) { LoadGame = true };
|
||||
|
||||
foreach (ClientInfo client in InMatchClients)
|
||||
packet.PlayerList.Add(client);
|
||||
packet.PlayerList.Add(ClientInfo);
|
||||
|
||||
SendToInMatchClients(packet);
|
||||
|
||||
OnLoadGame?.Invoke(packet.PlayerList);
|
||||
}
|
||||
else
|
||||
Logger.Log("Called StartLoadingGame - We are not the Host!", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this when the game is Loaded and ready to be started
|
||||
/// </summary>
|
||||
public virtual void GameLoaded()
|
||||
{
|
||||
Loaded = true;
|
||||
SendToHost(new BasicPacket(ClientInfo) { Loaded = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the Host
|
||||
/// </summary>
|
||||
public virtual void ConnectToHost()
|
||||
{
|
||||
SendToHost(new BasicPacket(ClientInfo) { Connect = true });
|
||||
Logger.Log("Attempting conection to Host. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell peers to start and starts ours
|
||||
/// </summary>
|
||||
public virtual void SendStartGame()
|
||||
{
|
||||
if (SendClient == null)
|
||||
{
|
||||
SendToLoadedClients(new BasicPacket(ClientInfo) { StartGame = true });
|
||||
InGame = true;
|
||||
Logger.Log("Sending Start Game", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
StartGame?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to the Host
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToHost(Packet packet)
|
||||
{
|
||||
if (SendClient != null)
|
||||
SendClient.SendPacket(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all Connecting clients
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToConnectingClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in ConnectingClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients Connected and waiting
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToConnectedClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients In this Match
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToInMatchClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in InMatchClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients Loaded
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToLoadedClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in LoadedClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients InGame
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToInGameClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in InGameClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to ALL clients we know
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToAllClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
{
|
||||
SendToConnectingClients(packet);
|
||||
SendToConnectedClients(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send to all but the one that sent it
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
/// <param name="playerID"></param>
|
||||
public void ShareWithOtherPeers(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
if (packet.ClientInfo.IP != clientInfo.IP)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AbortGame()
|
||||
{
|
||||
SendToLoadedClients(new BasicPacket(ClientInfo) { Abort = true });
|
||||
SendToInGameClients(new BasicPacket(ClientInfo) { Abort = true });
|
||||
|
||||
restart:
|
||||
foreach (ClientInfo client in LoadedClients)
|
||||
{
|
||||
LoadedClients.Remove(client);
|
||||
InMatchClients.Add(client);
|
||||
goto restart;
|
||||
}
|
||||
foreach (ClientInfo client in InGameClients)
|
||||
{
|
||||
InGameClients.Remove(client);
|
||||
InMatchClients.Add(client);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
InGame = false;
|
||||
Loaded = false;
|
||||
|
||||
OnAbort?.Invoke();
|
||||
}
|
||||
|
||||
public virtual void Disconnect()
|
||||
{
|
||||
Packet packet = new BasicPacket(ClientInfo) { Disconnect = true };
|
||||
|
||||
OnAbort?.Invoke();
|
||||
InMatch = false;
|
||||
InGame = false;
|
||||
Loaded = false;
|
||||
|
||||
if (SendClient == null)
|
||||
{
|
||||
SendToConnectingClients(packet);
|
||||
SendToConnectedClients(packet);
|
||||
}
|
||||
else
|
||||
SendToHost(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Die
|
||||
/// </summary>
|
||||
/// <param name="isDisposing"></param>
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
ReceiveClient?.Clear();
|
||||
|
||||
if (SendClient != null)
|
||||
{
|
||||
SendToHost(new BasicPacket(ClientInfo) { Disconnect = true });
|
||||
SendClient.Clear();
|
||||
}
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ClientType
|
||||
{
|
||||
Host,
|
||||
Peer,
|
||||
Server
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a Signature
|
||||
/// </summary>
|
||||
public readonly ClientInfo ClientInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Specify starting size of packet for efficiency
|
||||
/// </summary>
|
||||
public virtual int PacketSize => 1024;
|
||||
|
||||
public Packet(ClientInfo clientInfo)
|
||||
{
|
||||
ClientInfo = clientInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
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("symcol.Toys")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("symcol.Toys")]
|
||||
[assembly: AssemblyCopyright("Copyright © 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("f34ac16c-e590-4d70-a069-a748326852bf")]
|
||||
|
||||
// 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")]
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{F34AC16C-E590-4D70-A069-A748326852BF}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Symcol.Core</RootNamespace>
|
||||
<AssemblyName>Symcol.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<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' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Cyotek.Drawing.BitmapFont, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Cyotek.Drawing.BitmapFont.1.3.4-beta1\lib\net46\Cyotek.Drawing.BitmapFont.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ManagedBass, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ManagedBass.2.0.3\lib\net45\ManagedBass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<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="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Generic, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Win32, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLiteNetExtensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="GameObjects\SymcolHitbox.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolClickableContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolDialContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolDragContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolContainer.cs" />
|
||||
<Compile Include="Graphics\UserInterface\SpriteButton.cs" />
|
||||
<Compile Include="Graphics\UserInterface\SymcolWindow.cs" />
|
||||
<Compile Include="Networking\BasicPacket.cs" />
|
||||
<Compile Include="Networking\ClientInfo.cs" />
|
||||
<Compile Include="Networking\NetworkingClient.cs" />
|
||||
<Compile Include="Networking\Packet.cs" />
|
||||
<Compile Include="Networking\NetworkingClientHandler.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</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" />
|
||||
</Project>
|
||||
@@ -0,0 +1,43 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Containers
|
||||
{
|
||||
public class LinkText : OsuSpriteText, IHasTooltip
|
||||
{
|
||||
public string TooltipText => Tooltip;
|
||||
|
||||
public virtual string Tooltip => "";
|
||||
|
||||
private readonly OsuHoverContainer content;
|
||||
|
||||
public override bool HandleKeyboardInput => content.Action != null;
|
||||
public override bool HandleMouseInput => content.Action != null;
|
||||
|
||||
protected override Container<Drawable> Content => content ?? (Container<Drawable>)this;
|
||||
|
||||
public override IEnumerable<Drawable> FlowingChildren => Children;
|
||||
|
||||
public string Url
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
content.Action = () => Process.Start(value);
|
||||
}
|
||||
}
|
||||
|
||||
public LinkText()
|
||||
{
|
||||
AddInternal(content = new OsuHoverContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO: make this more generic
|
||||
/// </summary>
|
||||
public class ProfileLink : LinkText
|
||||
{
|
||||
public override string Tooltip => "View profile in browser";
|
||||
|
||||
public ProfileLink(User user, bool maintainer = false)
|
||||
{
|
||||
if (!maintainer)
|
||||
Text = "Ruleset Creator: " + user.Username;
|
||||
else
|
||||
Text = "Ruleset Maintainer: " + user.Username;
|
||||
|
||||
Url = $@"https://osu.ppy.sh/users/{user.Id}";
|
||||
Font = @"Exo2.0-RegularItalic";
|
||||
TextSize = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.HitObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Mostly stuff copied from Container
|
||||
/// </summary>
|
||||
/// <typeparam name="TObject"></typeparam>
|
||||
public abstract class DrawableSymcolHitObject<TObject> : DrawableHitObject<TObject>
|
||||
where TObject : HitObject
|
||||
{
|
||||
//Future prep?
|
||||
//public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { }
|
||||
//public override void ApplyTransformsAt(double time, bool propagateChildren = false) { }
|
||||
|
||||
protected virtual Container<Drawable> Content => new Container();
|
||||
|
||||
public IReadOnlyList<Drawable> Children
|
||||
{
|
||||
get
|
||||
{
|
||||
return InternalChildren;
|
||||
}
|
||||
set
|
||||
{
|
||||
ChildrenEnumerable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Drawable> ChildrenEnumerable
|
||||
{
|
||||
set
|
||||
{
|
||||
Clear();
|
||||
AddRange(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRange(IEnumerable<Drawable> range)
|
||||
{
|
||||
foreach (Drawable d in range)
|
||||
Add(d);
|
||||
}
|
||||
|
||||
public Drawable Child
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Children.Count != 1)
|
||||
throw new InvalidOperationException($"{nameof(Child)} is only available when there's only 1 in {nameof(Children)}!");
|
||||
|
||||
return Children[0];
|
||||
}
|
||||
set
|
||||
{
|
||||
Clear();
|
||||
Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() => Clear(true);
|
||||
|
||||
public virtual void Clear(bool disposeChildren)
|
||||
{
|
||||
if (Content != null)
|
||||
Content.Clear(disposeChildren);
|
||||
else
|
||||
ClearInternal(disposeChildren);
|
||||
}
|
||||
|
||||
protected DrawableSymcolHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(Drawable drawable)
|
||||
{
|
||||
AddInternal(drawable);
|
||||
}
|
||||
|
||||
public void Remove(Drawable drawable)
|
||||
{
|
||||
RemoveInternal(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class ChatPacket : Packet
|
||||
{
|
||||
public override int PacketSize => 4096;
|
||||
|
||||
public string Author;
|
||||
|
||||
public string AuthorColor;
|
||||
|
||||
public string Message;
|
||||
|
||||
public ChatPacket(ClientInfo clientInfo) : base(clientInfo)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a client signature basically
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RulesetClientInfo : ClientInfo
|
||||
{
|
||||
public string Username = "";
|
||||
|
||||
public int UserID = -1;
|
||||
|
||||
public string UserPic;
|
||||
|
||||
public string UserBackground;
|
||||
|
||||
public string UserCountry;
|
||||
|
||||
public string CountryFlagName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
//TODO: This NEEDS its own clock to avoid fuckery later on with DoubleTime and HalfTime
|
||||
public class RulesetNetworkingClientHandler : NetworkingClientHandler, IOnlineComponent
|
||||
{
|
||||
public RulesetClientInfo RulesetClientInfo;
|
||||
|
||||
public Action<WorkingBeatmap> OnMapChange;
|
||||
|
||||
private OsuGame osu;
|
||||
|
||||
public RulesetNetworkingClientHandler(ClientType type, string ip, int port = 25570, string thisLocalIp = "0.0.0.0") : base(type, ip, port, thisLocalIp)
|
||||
{
|
||||
if (RulesetClientInfo == null)
|
||||
{
|
||||
RulesetClientInfo = new RulesetClientInfo
|
||||
{
|
||||
Port = port
|
||||
};
|
||||
|
||||
ClientInfo = RulesetClientInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send Map to Peers
|
||||
/// </summary>
|
||||
/// <param name="map"></param>
|
||||
public void SetMap(WorkingBeatmap map)
|
||||
{
|
||||
RulesetPacket packet;
|
||||
try
|
||||
{
|
||||
packet = new RulesetPacket(RulesetClientInfo)
|
||||
{
|
||||
OnlineBeatmapSetID = (int)map.BeatmapSetInfo.OnlineBeatmapSetID,
|
||||
OnlineBeatmapID = (int)map.BeatmapInfo.OnlineBeatmapID
|
||||
};
|
||||
SendToInMatchClients(packet);
|
||||
OnMapChange?.Invoke(osu.Beatmap.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
packet = new RulesetPacket(RulesetClientInfo);
|
||||
SendToInMatchClients(packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api, OsuGame osu)
|
||||
{
|
||||
api.Register(this);
|
||||
this.osu = osu;
|
||||
}
|
||||
|
||||
public void APIStateChanged(APIAccess api, APIState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
default:
|
||||
RulesetClientInfo.Username = "";
|
||||
RulesetClientInfo.UserID = -1;
|
||||
break;
|
||||
case APIState.Online:
|
||||
RulesetClientInfo.Username = api.LocalUser.Value.Username;
|
||||
RulesetClientInfo.UserID = (int)api.LocalUser.Value.Id;
|
||||
RulesetClientInfo.UserCountry = api.LocalUser.Value.Country.FullName;
|
||||
RulesetClientInfo.CountryFlagName = api.LocalUser.Value.Country.FlagName;
|
||||
RulesetClientInfo.UserPic = api.LocalUser.Value.AvatarUrl;
|
||||
RulesetClientInfo.UserBackground = api.LocalUser.Value.CoverUrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class RulesetPacket : Packet
|
||||
{
|
||||
public new readonly RulesetClientInfo ClientInfo;
|
||||
|
||||
public override int PacketSize => 4096;
|
||||
|
||||
public int OnlineBeatmapSetID = -1;
|
||||
|
||||
public int OnlineBeatmapID = -1;
|
||||
|
||||
public bool HaveMap;
|
||||
|
||||
public string ChatContent;
|
||||
|
||||
//public string RulesetName = "";
|
||||
|
||||
public RulesetPacket(RulesetClientInfo rulesetClientInfo) : base(rulesetClientInfo)
|
||||
{
|
||||
ClientInfo = rulesetClientInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class ScorePacket : Packet
|
||||
{
|
||||
public override int PacketSize => 2048;
|
||||
|
||||
public int Score;
|
||||
|
||||
public ScorePacket(ClientInfo clientInfo, int score) : base(clientInfo)
|
||||
{
|
||||
Score = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Options
|
||||
{
|
||||
public class MultiplayerDropdownEnumOption<T> : MultiplayerOption
|
||||
where T : struct
|
||||
{
|
||||
public readonly Bindable<T> BindableEnum;
|
||||
|
||||
public MultiplayerDropdownEnumOption(Bindable<T> bindable, string name, int quadrant, bool sync = true) : base(name, quadrant, sync)
|
||||
{
|
||||
BindableEnum = bindable;
|
||||
|
||||
OptionContainer.Child = new BetterSettingsEnumDropdown<T>
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Bindable = bindable,
|
||||
};
|
||||
}
|
||||
|
||||
private class BetterSettingsEnumDropdown<T> : SettingsEnumDropdown<T>
|
||||
{
|
||||
protected override Drawable CreateControl() => new BetterOsuEnumDropdown<T>
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
};
|
||||
|
||||
private class BetterOsuEnumDropdown<T> : OsuEnumDropdown<T>
|
||||
{
|
||||
public BetterOsuEnumDropdown()
|
||||
{
|
||||
Menu.MaxHeight = 160;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Options
|
||||
{
|
||||
public abstract class MultiplayerOption : Container
|
||||
{
|
||||
protected readonly SpriteText Title;
|
||||
|
||||
protected readonly Container OptionContainer;
|
||||
|
||||
public MultiplayerOption(string name, int quadrant, bool sync = true)
|
||||
{
|
||||
if (quadrant == 1 | quadrant == 3 | quadrant == 5 | quadrant == 7)
|
||||
{
|
||||
switch (quadrant)
|
||||
{
|
||||
case 1:
|
||||
quadrant = 0;
|
||||
break;
|
||||
case 3:
|
||||
quadrant = 1;
|
||||
break;
|
||||
case 5:
|
||||
quadrant = 2;
|
||||
break;
|
||||
case 7:
|
||||
quadrant = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
Position = new Vector2(16, 4 + (64 * quadrant));
|
||||
}
|
||||
else if (quadrant == 2 | quadrant == 4 | quadrant == 6 | quadrant == 8)
|
||||
{
|
||||
switch (quadrant)
|
||||
{
|
||||
case 2:
|
||||
quadrant = 0;
|
||||
break;
|
||||
case 4:
|
||||
quadrant = 1;
|
||||
break;
|
||||
case 6:
|
||||
quadrant = 2;
|
||||
break;
|
||||
case 8:
|
||||
quadrant = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopLeft;
|
||||
Position = new Vector2(22, 4 + (64 * quadrant));
|
||||
}
|
||||
else
|
||||
throw new Exception("Globglogabgalab");
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Width = 0.49f;
|
||||
Height = 80;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Title = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
TextSize = 20,
|
||||
Text = name
|
||||
},
|
||||
OptionContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(-16, 18),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Options
|
||||
{
|
||||
public class MultiplayerToggleOption : MultiplayerOption
|
||||
{
|
||||
public readonly Bindable<bool> BindableBool;
|
||||
|
||||
public MultiplayerToggleOption(Bindable<bool> bindable, string name, int quadrant, bool sync = true) : base(name, quadrant, sync)
|
||||
{
|
||||
BindableBool = bindable;
|
||||
|
||||
Child = new SettingsCheckbox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Bindable = bindable,
|
||||
LabelText = " " + name,
|
||||
Position = new Vector2(-16, 18),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Users;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class Chat : Container, IOnlineComponent
|
||||
{
|
||||
private readonly RulesetNetworkingClientHandler rulesetNetworkingClientHandler;
|
||||
|
||||
private string playerColorHex = SymcolSettingsSubsection.SymcolConfigManager.GetBindable<string>(SymcolSetting.PlayerColor);
|
||||
|
||||
private User user;
|
||||
|
||||
private readonly FillFlowContainer<ChatMessage> messageContainer;
|
||||
private readonly OsuTextBox textBox;
|
||||
|
||||
public Chat(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
this.rulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
|
||||
rulesetNetworkingClientHandler.OnPacketReceive += (packet) =>
|
||||
{
|
||||
if (packet is ChatPacket chatPacket)
|
||||
Add(chatPacket);
|
||||
if (rulesetNetworkingClientHandler.ClientType == ClientType.Host)
|
||||
rulesetNetworkingClientHandler.ShareWithOtherPeers(packet);
|
||||
};
|
||||
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Origin = Anchor.BottomCentre;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Height = 0.46f;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.8f
|
||||
},
|
||||
new OsuScrollContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.9f,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
messageContainer = new FillFlowContainer<ChatMessage>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
}
|
||||
}
|
||||
},
|
||||
textBox = new OsuTextBox
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.98f,
|
||||
Height = 36,
|
||||
Position = new Vector2(0, -12),
|
||||
Colour = Color4.White,
|
||||
Text = "Type here!"
|
||||
}
|
||||
};
|
||||
|
||||
textBox.OnCommit += (s, r) =>
|
||||
{
|
||||
AddMessage(textBox.Text);
|
||||
textBox.Text = "";
|
||||
};
|
||||
}
|
||||
|
||||
public void Add(ChatPacket packet)
|
||||
{
|
||||
ChatMessage message = new ChatMessage(packet);
|
||||
messageContainer.Add(message);
|
||||
}
|
||||
|
||||
public void AddMessage(string message)
|
||||
{
|
||||
if (message == "" | message == " ")
|
||||
return;
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
OsuColour.FromHex(playerColorHex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
playerColorHex = "#ffffff";
|
||||
}
|
||||
|
||||
ChatPacket packet = new ChatPacket(rulesetNetworkingClientHandler.ClientInfo)
|
||||
{
|
||||
Author = user.Username,
|
||||
AuthorColor = playerColorHex,
|
||||
Message = message,
|
||||
};
|
||||
|
||||
rulesetNetworkingClientHandler.SendToHost(packet);
|
||||
rulesetNetworkingClientHandler.SendToInMatchClients(packet);
|
||||
Add(packet);
|
||||
}
|
||||
else
|
||||
Logger.Log("You must be logged in to message!", LoggingTarget.Network, LogLevel.Error);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api)
|
||||
{
|
||||
api.Register(this);
|
||||
}
|
||||
|
||||
public void APIStateChanged(APIAccess api, APIState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
default:
|
||||
user = null;
|
||||
break;
|
||||
case APIState.Online:
|
||||
user = api.LocalUser.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class ChatMessage : Container
|
||||
{
|
||||
public ChatMessage(ChatPacket packet)
|
||||
{
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = OsuColour.FromHex(packet.AuthorColor),
|
||||
TextSize = 24,
|
||||
Text = packet.Author + ":"
|
||||
},
|
||||
new OsuTextFlowContainer(t => { t.TextSize = 24; })
|
||||
{
|
||||
Position = new OpenTK.Vector2(140, 0),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = packet.Message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Users;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MatchPlayer : ClickableContainer, IHasContextMenu
|
||||
{
|
||||
public readonly RulesetClientInfo ClientInfo;
|
||||
|
||||
private readonly Box dim;
|
||||
|
||||
private readonly DrawableFlag countryFlag;
|
||||
private readonly UserCoverBackground profileBackground;
|
||||
private readonly UpdateableAvatar profilePicture;
|
||||
|
||||
public MatchPlayer(RulesetClientInfo clientInfo)
|
||||
{
|
||||
ClientInfo = clientInfo;
|
||||
|
||||
Alpha = 0;
|
||||
Masking = true;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 40f;
|
||||
CornerRadius = 10;
|
||||
|
||||
Country country = new Country
|
||||
{
|
||||
FullName = ClientInfo.UserCountry,
|
||||
FlagName = ClientInfo.CountryFlagName,
|
||||
};
|
||||
|
||||
User user = new User
|
||||
{
|
||||
Username = ClientInfo.Username,
|
||||
Id = ClientInfo.UserID,
|
||||
Country = country,
|
||||
AvatarUrl = ClientInfo.UserPic,
|
||||
CoverUrl = ClientInfo.UserBackground,
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
profileBackground = new UserCoverBackground(user)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
FillMode = FillMode.Fill,
|
||||
OnLoadComplete = d => d.FadeInFromZero(200),
|
||||
},
|
||||
dim = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.8f
|
||||
},
|
||||
profilePicture = new UpdateableAvatar
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(Height * 0.8f),
|
||||
Position = new Vector2(6, 0),
|
||||
User = user,
|
||||
Masking = true,
|
||||
CornerRadius = 6,
|
||||
},
|
||||
countryFlag = new DrawableFlag(country)
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Size = new Vector2(Height * 0.9f, (Height * 0.9f) * 0.66f),
|
||||
Position = new Vector2(-10, 0)
|
||||
},
|
||||
new SpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Position = new Vector2(Height * 1.1f, 0),
|
||||
TextSize = Height * 0.9f,
|
||||
Text = user.Username
|
||||
}
|
||||
};
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
Process.Start("https://osu.ppy.sh/users/" + user.Id);
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
dim.FadeTo(0.6f, 200);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
base.OnHoverLost(state);
|
||||
|
||||
dim.FadeTo(0.8f, 200);
|
||||
}
|
||||
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuMenuItem("View Profile", MenuItemType.Standard, () => { }),
|
||||
new OsuMenuItem("Promote to Host", MenuItemType.Highlighted, () => { }),
|
||||
new OsuMenuItem("Kick", MenuItemType.Destructive, () => { }),
|
||||
new OsuMenuItem("Ban", MenuItemType.Destructive, () => { }),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MatchPlayerList : Container
|
||||
{
|
||||
private readonly RulesetNetworkingClientHandler rulesetNetworkingClientHandler;
|
||||
|
||||
public readonly List<MatchPlayer> MatchPlayers = new List<MatchPlayer>();
|
||||
|
||||
public readonly FillFlowContainer MatchPlayersContianer;
|
||||
|
||||
public MatchPlayerList(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
this.rulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 16;
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Width = 0.49f;
|
||||
Height = 0.45f;
|
||||
Position = new Vector2(10);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.8f)
|
||||
},
|
||||
MatchPlayersContianer = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.98f,
|
||||
Height = 0.96f
|
||||
}
|
||||
};
|
||||
|
||||
rulesetNetworkingClientHandler.OnReceivePlayerList += (players) =>
|
||||
{
|
||||
restart:
|
||||
foreach (MatchPlayer matchPlayer in MatchPlayers)
|
||||
foreach (ClientInfo clientInfo in players)
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
if (rulesetClientInfo.IP + rulesetClientInfo.Port != matchPlayer.ClientInfo.IP + matchPlayer.ClientInfo.Port)
|
||||
{
|
||||
Add(rulesetClientInfo);
|
||||
players.Remove(clientInfo);
|
||||
goto restart;
|
||||
}
|
||||
};
|
||||
rulesetNetworkingClientHandler.RequestPlayerList();
|
||||
|
||||
rulesetNetworkingClientHandler.OnClientJoin += (clientInfo) =>
|
||||
{
|
||||
foreach (MatchPlayer matchPlayer in MatchPlayers)
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
if (rulesetClientInfo.IP + rulesetClientInfo.Port != matchPlayer.ClientInfo.IP + matchPlayer.ClientInfo.Port)
|
||||
{
|
||||
Add(rulesetClientInfo);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
rulesetNetworkingClientHandler.OnClientDisconnect += (clientInfo) =>
|
||||
{
|
||||
foreach (MatchPlayer matchPlayer in MatchPlayers)
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
if (rulesetClientInfo.IP + rulesetClientInfo.Port == matchPlayer.ClientInfo.IP + matchPlayer.ClientInfo.Port)
|
||||
{
|
||||
Remove(matchPlayer);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void Add(RulesetClientInfo clientInfo)
|
||||
{
|
||||
MatchPlayer matchPlayer = new MatchPlayer(clientInfo);
|
||||
|
||||
Add(matchPlayer);
|
||||
}
|
||||
|
||||
public void Add(MatchPlayer matchPlayer)
|
||||
{
|
||||
MatchPlayers.Add(matchPlayer);
|
||||
MatchPlayersContianer.Add(matchPlayer);
|
||||
matchPlayer.FadeInFromZero(200);
|
||||
}
|
||||
|
||||
public void Remove(MatchPlayer matchPlayer)
|
||||
{
|
||||
MatchPlayers.Remove(matchPlayer);
|
||||
matchPlayer.FadeOutFromOne(200)
|
||||
.Expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Screens.Symcol.Pieces;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Options;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MatchTools : Container
|
||||
{
|
||||
public readonly Bindable<MatchScreenMode> Mode = new Bindable<MatchScreenMode>() { Default = MatchScreenMode.MapDetails };
|
||||
|
||||
public readonly Bindable<MatchGamemode> GameMode = new Bindable<MatchGamemode>() { Default = MatchGamemode.HeadToHead };
|
||||
|
||||
public readonly OsuTabControl<MatchScreenMode> TabControl;
|
||||
|
||||
public readonly Container SelectedContent;
|
||||
|
||||
public readonly Container MapDetails;
|
||||
|
||||
public Container RulesetSettings;
|
||||
|
||||
public readonly Container SoundBoard;
|
||||
|
||||
private WorkingBeatmap selectedBeatmap;
|
||||
|
||||
private int selectedBeatmapSetID;
|
||||
|
||||
public MatchTools()
|
||||
{
|
||||
Masking = true;
|
||||
CornerRadius = 16;
|
||||
Anchor = Anchor.TopRight;
|
||||
Origin = Anchor.TopRight;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Width = 0.49f;
|
||||
Height = 0.45f;
|
||||
Position = new Vector2(-10, 10);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.8f)
|
||||
},
|
||||
TabControl = new OsuTabControl<MatchScreenMode>
|
||||
{
|
||||
Position = new Vector2(72, 0),
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.08f,
|
||||
Width = 0.8f
|
||||
},
|
||||
SelectedContent = new Container
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.92f
|
||||
}
|
||||
};
|
||||
TabControl.Current.Value = MatchScreenMode.MapDetails;
|
||||
|
||||
Mode.ValueChanged += (value) =>
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case MatchScreenMode.MapDetails:
|
||||
if (selectedBeatmap != null)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmap);
|
||||
else if (selectedBeatmapSetID != 0)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmapSetID);
|
||||
else
|
||||
SelectedContent.Child = new MapDetailsSection(true);
|
||||
break;
|
||||
case MatchScreenMode.MatchSettings:
|
||||
SelectedContent.Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new MultiplayerDropdownEnumOption<MatchGamemode>(GameMode, "Match Gamemode", 1)
|
||||
}
|
||||
};
|
||||
break;
|
||||
case MatchScreenMode.SoundBoard:
|
||||
SelectedContent.Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new HitSoundBoard
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ButtonSize = 80
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
};
|
||||
Mode.BindTo(TabControl.Current);
|
||||
}
|
||||
|
||||
public void MapChange(WorkingBeatmap workingBeatmap)
|
||||
{
|
||||
if (workingBeatmap == null)
|
||||
{
|
||||
MapChange(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedBeatmap = workingBeatmap;
|
||||
selectedBeatmapSetID = (int)workingBeatmap.BeatmapSetInfo.OnlineBeatmapSetID;
|
||||
|
||||
if (Mode.Value == MatchScreenMode.MapDetails)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmap);
|
||||
}
|
||||
|
||||
public void MapChange(int onlineBeatmapSetID)
|
||||
{
|
||||
selectedBeatmap = null;
|
||||
selectedBeatmapSetID = onlineBeatmapSetID;
|
||||
|
||||
if (Mode.Value == MatchScreenMode.MapDetails)
|
||||
{
|
||||
if (selectedBeatmapSetID != 0 && selectedBeatmapSetID != -1)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmapSetID);
|
||||
else
|
||||
SelectedContent.Child = new MapDetailsSection(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MapDetailsSection : ClickableContainer
|
||||
{
|
||||
private Sprite beatmapBG;
|
||||
private SpriteText name;
|
||||
private SpriteText artist;
|
||||
private SpriteText difficulty;
|
||||
private SpriteText time;
|
||||
|
||||
private Box dim;
|
||||
|
||||
public MapDetailsSection(WorkingBeatmap workingBeatmap)
|
||||
{
|
||||
draw();
|
||||
|
||||
HitObject lastObject = workingBeatmap.Beatmap.HitObjects.LastOrDefault();
|
||||
double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0;
|
||||
|
||||
beatmapBG.Texture = workingBeatmap.Background;
|
||||
name.Text = workingBeatmap.BeatmapSetInfo.Metadata.Title;
|
||||
artist.Text = "By: " + workingBeatmap.BeatmapSetInfo.Metadata.Artist;
|
||||
difficulty.Text = workingBeatmap.BeatmapInfo.Version + " (" + Math.Round(workingBeatmap.BeatmapInfo.StarDifficulty, 2) + " stars) mapped by " + workingBeatmap.BeatmapInfo.Metadata.AuthorString;
|
||||
time.Text = getBPMRange(workingBeatmap.Beatmap) + " bpm for " + TimeSpan.FromMilliseconds(endTime - workingBeatmap.Beatmap.HitObjects.First().StartTime).ToString(@"m\:ss");
|
||||
|
||||
BorderColour = getColour(workingBeatmap.BeatmapInfo);
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Radius = 16,
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = getColour(workingBeatmap.BeatmapInfo).Opacity(0.2f)
|
||||
};
|
||||
Action = () => Process.Start("https://osu.ppy.sh/beatmapsets/" + workingBeatmap.BeatmapSetInfo.OnlineBeatmapSetID);
|
||||
}
|
||||
|
||||
public MapDetailsSection(int onlineBeatmapSetID)
|
||||
{
|
||||
draw();
|
||||
name.Text = "Missing Map!";
|
||||
artist.Text = "Click to open in Browser";
|
||||
Action = () => Process.Start("https://osu.ppy.sh/beatmapsets/" + onlineBeatmapSetID);
|
||||
}
|
||||
|
||||
public MapDetailsSection(bool invalid)
|
||||
{
|
||||
draw();
|
||||
name.Text = "Invalid / No Map Selected!";
|
||||
artist.Text = "Don't hit start, weird things might happen";
|
||||
Action = () => Process.Start("https://osu.ppy.sh/home");
|
||||
}
|
||||
|
||||
private void draw()
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Width = 0.95f;
|
||||
Height = 0.9f;
|
||||
|
||||
Masking = true;
|
||||
BorderColour = Color4.LightBlue;
|
||||
BorderThickness = 4;
|
||||
CornerRadius = 10;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Radius = 16,
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.LightBlue.Opacity(0.2f)
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
beatmapBG = new Sprite
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
},
|
||||
dim = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.6f
|
||||
},
|
||||
name = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 0),
|
||||
Font = @"Exo2.0-SemiBoldItalic",
|
||||
TextSize = 40
|
||||
},
|
||||
artist = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 38),
|
||||
Font = @"Exo2.0-MediumItalic",
|
||||
TextSize = 24
|
||||
},
|
||||
difficulty = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 64),
|
||||
Font = "Exo2.0-Bold",
|
||||
TextSize = 16
|
||||
},
|
||||
time = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 84),
|
||||
TextSize = 16
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
dim.FadeTo(0.4f, 200);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
base.OnHoverLost(state);
|
||||
|
||||
dim.FadeTo(0.6f, 200);
|
||||
}
|
||||
|
||||
//"Borrowed" stuff
|
||||
private string getBPMRange(Beatmap beatmap)
|
||||
{
|
||||
double bpmMax = beatmap.ControlPointInfo.BPMMaximum;
|
||||
double bpmMin = beatmap.ControlPointInfo.BPMMinimum;
|
||||
|
||||
if (Precision.AlmostEquals(bpmMin, bpmMax))
|
||||
return $"{bpmMin:0}";
|
||||
|
||||
return $"{bpmMin:0}-{bpmMax:0} (mostly {beatmap.ControlPointInfo.BPMMode:0})";
|
||||
}
|
||||
|
||||
private enum DifficultyRating
|
||||
{
|
||||
Easy,
|
||||
Normal,
|
||||
Hard,
|
||||
Insane,
|
||||
Expert,
|
||||
ExpertPlus
|
||||
}
|
||||
|
||||
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
var rating = beatmap.StarDifficulty;
|
||||
|
||||
if (rating < 1.5) return DifficultyRating.Easy;
|
||||
if (rating < 2.25) return DifficultyRating.Normal;
|
||||
if (rating < 3.75) return DifficultyRating.Hard;
|
||||
if (rating < 5.25) return DifficultyRating.Insane;
|
||||
if (rating < 6.75) return DifficultyRating.Expert;
|
||||
return DifficultyRating.ExpertPlus;
|
||||
}
|
||||
|
||||
private Color4 getColour(BeatmapInfo beatmap)
|
||||
{
|
||||
OsuColour palette = new OsuColour();
|
||||
switch (getDifficultyRating(beatmap))
|
||||
{
|
||||
case DifficultyRating.Easy:
|
||||
return palette.Green;
|
||||
default:
|
||||
case DifficultyRating.Normal:
|
||||
return palette.Blue;
|
||||
case DifficultyRating.Hard:
|
||||
return palette.Yellow;
|
||||
case DifficultyRating.Insane:
|
||||
return palette.Pink;
|
||||
case DifficultyRating.Expert:
|
||||
return palette.Purple;
|
||||
case DifficultyRating.ExpertPlus:
|
||||
return palette.Gray0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MatchGamemode
|
||||
{
|
||||
[System.ComponentModel.Description("Head to Head")]
|
||||
HeadToHead,
|
||||
[System.ComponentModel.Description("Head to Head with Live Spectator")]
|
||||
HeadToHeadSpectator,
|
||||
[System.ComponentModel.Description("Team Versus")]
|
||||
TeamVS,
|
||||
[System.ComponentModel.Description("TAG4")]
|
||||
TAG4,
|
||||
[System.ComponentModel.Description("Team TAG4")]
|
||||
TeamTAG4,
|
||||
[System.ComponentModel.Description("Tourny Mode")]
|
||||
Tournement,
|
||||
}
|
||||
|
||||
public enum MatchScreenMode
|
||||
{
|
||||
[System.ComponentModel.Description("Map Details")]
|
||||
MapDetails,
|
||||
[System.ComponentModel.Description("Match Settings")]
|
||||
MatchSettings,
|
||||
[System.ComponentModel.Description("Ruleset Settings")]
|
||||
RulesetSettings,
|
||||
[System.ComponentModel.Description("Sound Board")]
|
||||
SoundBoard
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MultiplayerScoreboard : Container
|
||||
{
|
||||
public readonly Container<MultiplayerScoreboardItem> ScoreboardItems;
|
||||
|
||||
private readonly RulesetNetworkingClientHandler rulesetNetworkingClientHandler;
|
||||
|
||||
private readonly ScoreProcessor scoreProcessor;
|
||||
|
||||
private double updateScoreTime = 0;
|
||||
|
||||
public MultiplayerScoreboard(RulesetNetworkingClientHandler rulesetNetworkingClientHandler, List<ClientInfo> playerList, ScoreProcessor scoreProcessor)
|
||||
{
|
||||
this.rulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
this.scoreProcessor = scoreProcessor;
|
||||
|
||||
AlwaysPresent = true;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Width = 120;
|
||||
|
||||
Position = new Vector2(0, -200);
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
|
||||
Child = ScoreboardItems = new Container<MultiplayerScoreboardItem>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
};
|
||||
|
||||
int i = 1;
|
||||
foreach (ClientInfo clientInfo in playerList)
|
||||
{
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
{
|
||||
ScoreboardItems.Add(new MultiplayerScoreboardItem(rulesetClientInfo, i) { });
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
rulesetNetworkingClientHandler.OnPacketReceive += (Packet packet) =>
|
||||
{
|
||||
if (packet is ScorePacket scorePacket)
|
||||
{
|
||||
rulesetNetworkingClientHandler.ShareWithOtherPeers(scorePacket);
|
||||
foreach (MultiplayerScoreboardItem item in ScoreboardItems)
|
||||
if (scorePacket.ClientInfo == item.ClientInfo)
|
||||
item.Score = scorePacket.Score;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (Time.Current >= updateScoreTime)
|
||||
{
|
||||
updateScoreTime = Time.Current + 500;
|
||||
foreach (MultiplayerScoreboardItem item in ScoreboardItems)
|
||||
if (rulesetNetworkingClientHandler.ClientInfo == item.ClientInfo)
|
||||
item.Score = (int)scoreProcessor.TotalScore.Value;
|
||||
|
||||
rulesetNetworkingClientHandler.SendToHost(new ScorePacket(rulesetNetworkingClientHandler.ClientInfo, (int)scoreProcessor.TotalScore.Value));
|
||||
rulesetNetworkingClientHandler.SendToInGameClients(new ScorePacket(rulesetNetworkingClientHandler.ClientInfo, (int)scoreProcessor.TotalScore.Value));
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Key == Key.Tab)
|
||||
{
|
||||
if (Alpha > 0)
|
||||
this.FadeOut(100);
|
||||
else
|
||||
this.FadeIn(100);
|
||||
}
|
||||
|
||||
return base.OnKeyDown(state, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MultiplayerScoreboardItem : Container
|
||||
{
|
||||
public int Score
|
||||
{
|
||||
get { return score; }
|
||||
set
|
||||
{
|
||||
if (value != score)
|
||||
{
|
||||
score = value;
|
||||
scoreText.Text = value.ToString();
|
||||
|
||||
foreach(MultiplayerScoreboardItem item in itemList)
|
||||
if (value > item.Score && Place > item.Place)
|
||||
{
|
||||
Place = item.Place;
|
||||
foreach (MultiplayerScoreboardItem i in itemList)
|
||||
if (i.Place < Place)
|
||||
i.Place -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Place
|
||||
{
|
||||
get { return place; }
|
||||
set
|
||||
{
|
||||
if (Place != place)
|
||||
{
|
||||
place = value;
|
||||
this.MoveTo(new Vector2(0, (-height - 8) * (value - 1)), 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int place = 0;
|
||||
|
||||
private int score = 0;
|
||||
|
||||
private const int height = 60;
|
||||
|
||||
public readonly RulesetClientInfo ClientInfo;
|
||||
|
||||
private readonly SpriteText scoreText;
|
||||
|
||||
private static List<MultiplayerScoreboardItem> itemList = new List<MultiplayerScoreboardItem>();
|
||||
|
||||
public MultiplayerScoreboardItem(RulesetClientInfo clientInfo, int place)
|
||||
{
|
||||
ClientInfo = clientInfo;
|
||||
this.place = place;
|
||||
|
||||
itemList.Add(this);
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 8;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.8f,
|
||||
},
|
||||
new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(4),
|
||||
Text = clientInfo.Username
|
||||
},
|
||||
scoreText = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Position = new Vector2(-4),
|
||||
Text = Score.ToString()
|
||||
}
|
||||
};
|
||||
|
||||
this.MoveTo(new Vector2(0, (-height - 8) * (Place - 1)), 200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
itemList.Remove(this);
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Select;
|
||||
using System;
|
||||
using osu.Game.Screens;
|
||||
using osu.Framework.Screens;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public class MatchSongSelect : SongSelect
|
||||
{
|
||||
public WorkingBeatmap SelectedMap;
|
||||
|
||||
private bool exiting;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => null;
|
||||
|
||||
public Action Action;
|
||||
|
||||
public readonly RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
public MatchSongSelect(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
RulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
base.OnEntering(last);
|
||||
}
|
||||
|
||||
protected override bool OnSelectionFinalised()
|
||||
{
|
||||
if (!exiting)
|
||||
{
|
||||
RulesetNetworkingClientHandler.OnMapChange?.Invoke(null);
|
||||
SelectedMap = Beatmap.Value;
|
||||
Action();
|
||||
exiting = true;
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
Exit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using OpenTK;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using OpenTK.Input;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Pieces;
|
||||
using System.Collections.Generic;
|
||||
using Symcol.Core.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public class MultiPlayer : ScreenWithBeatmapBackground, IProvideCursor
|
||||
{
|
||||
public readonly RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap);
|
||||
|
||||
protected override float BackgroundParallaxAmount => 0.1f;
|
||||
|
||||
public override bool ShowOverlaysOnEnter => false;
|
||||
|
||||
public Action RestartRequested;
|
||||
|
||||
public override bool AllowBeatmapRulesetChange => false;
|
||||
|
||||
public bool HasFailed { get; private set; }
|
||||
|
||||
public bool AllowPause { get; set; } = false;
|
||||
public bool AllowLeadIn { get; set; } = true;
|
||||
public bool AllowResults { get; set; } = true;
|
||||
|
||||
public int RestartCount;
|
||||
|
||||
public CursorContainer Cursor => RulesetContainer.Cursor;
|
||||
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value;
|
||||
|
||||
private IAdjustableClock sourceClock;
|
||||
private DecoupleableInterpolatingFramedClock adjustableClock;
|
||||
|
||||
private RulesetInfo ruleset;
|
||||
|
||||
private APIAccess api;
|
||||
|
||||
private ScoreProcessor scoreProcessor;
|
||||
protected RulesetContainer RulesetContainer;
|
||||
|
||||
#region User Settings
|
||||
|
||||
private Bindable<double> dimLevel;
|
||||
private Bindable<double> blurLevel;
|
||||
private Bindable<bool> showStoryboard;
|
||||
private Bindable<bool> mouseWheelDisabled;
|
||||
private Bindable<double> userAudioOffset;
|
||||
|
||||
private SampleChannel sampleRestart;
|
||||
|
||||
#endregion
|
||||
|
||||
private Container storyboardContainer;
|
||||
private DrawableStoryboard storyboard;
|
||||
|
||||
private HUDOverlay hudOverlay;
|
||||
|
||||
private MultiplayerScoreboard scoreboard;
|
||||
|
||||
private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true;
|
||||
|
||||
private readonly List<ClientInfo> playerList;
|
||||
|
||||
public MultiPlayer(RulesetNetworkingClientHandler rulesetNetworkingClientHandler, List<ClientInfo> playerList)//, WorkingBeatmap beatmap = null)
|
||||
{
|
||||
RulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
RulesetNetworkingClientHandler.OnAbort = () => Exit();
|
||||
RulesetNetworkingClientHandler.StartGame = () => start();
|
||||
this.playerList = playerList;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, APIAccess api, OsuConfigManager config)
|
||||
{
|
||||
this.api = api;
|
||||
|
||||
dimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||
blurLevel = config.GetBindable<double>(OsuSetting.BlurLevel);
|
||||
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
|
||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||
|
||||
sampleRestart = audio.Sample.Get(@"Gameplay/restart");
|
||||
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
|
||||
|
||||
WorkingBeatmap working = Beatmap.Value;
|
||||
Beatmap beatmap;
|
||||
|
||||
try
|
||||
{
|
||||
beatmap = working.Beatmap;
|
||||
|
||||
if (beatmap == null)
|
||||
throw new InvalidOperationException("Beatmap was not loaded");
|
||||
|
||||
ruleset = Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset;
|
||||
var rulesetInstance = ruleset.CreateInstance();
|
||||
|
||||
try
|
||||
{
|
||||
RulesetContainer = rulesetInstance.CreateRulesetContainerWith(working, ruleset.ID == beatmap.BeatmapInfo.Ruleset.ID);
|
||||
}
|
||||
catch (BeatmapInvalidForRulesetException)
|
||||
{
|
||||
// we may fail to create a RulesetContainer if the beatmap cannot be loaded with the user's preferred ruleset
|
||||
// let's try again forcing the beatmap's ruleset.
|
||||
ruleset = beatmap.BeatmapInfo.Ruleset;
|
||||
rulesetInstance = ruleset.CreateInstance();
|
||||
RulesetContainer = rulesetInstance.CreateRulesetContainerWith(Beatmap, true);
|
||||
}
|
||||
|
||||
if (!RulesetContainer.Objects.Any())
|
||||
throw new InvalidOperationException("Beatmap contains no hit objects!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Could not load beatmap sucessfully!");
|
||||
|
||||
//couldn't load, hard abort!
|
||||
Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
sourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock();
|
||||
adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
||||
|
||||
var firstObjectTime = RulesetContainer.Objects.First().StartTime;
|
||||
adjustableClock.Seek(AllowLeadIn
|
||||
? Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn))
|
||||
: firstObjectTime);
|
||||
|
||||
adjustableClock.ProcessFrame();
|
||||
|
||||
// the final usable gameplay clock with user-set offsets applied.
|
||||
var offsetClock = new FramedOffsetClock(adjustableClock);
|
||||
|
||||
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
||||
userAudioOffset.TriggerChange();
|
||||
|
||||
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = offsetClock,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
storyboardContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
},
|
||||
RulesetContainer,
|
||||
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
|
||||
{
|
||||
Clock = Clock, // hud overlay doesn't want to use the audio clock directly
|
||||
ProcessCustomClock = false,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
},
|
||||
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ProcessCustomClock = false,
|
||||
Breaks = beatmap.Breaks
|
||||
},
|
||||
scoreboard = new MultiplayerScoreboard(RulesetNetworkingClientHandler, playerList, scoreProcessor)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (showStoryboard)
|
||||
initializeStoryboard(false);
|
||||
|
||||
// Bind ScoreProcessor to ourselves
|
||||
scoreProcessor.AllJudged += onCompletion;
|
||||
scoreProcessor.Failed += onFail;
|
||||
|
||||
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||
mod.ApplyToScoreProcessor(scoreProcessor);
|
||||
}
|
||||
|
||||
private void applyRateFromMods()
|
||||
{
|
||||
if (sourceClock == null) return;
|
||||
|
||||
sourceClock.Rate = 1;
|
||||
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
|
||||
mod.ApplyToClock(sourceClock);
|
||||
}
|
||||
|
||||
private void initializeStoryboard(bool asyncLoad)
|
||||
{
|
||||
if (storyboardContainer == null)
|
||||
return;
|
||||
|
||||
var beatmap = Beatmap.Value;
|
||||
|
||||
storyboard = beatmap.Storyboard.CreateDrawable();
|
||||
storyboard.Masking = true;
|
||||
|
||||
if (asyncLoad)
|
||||
LoadComponentAsync(storyboard, storyboardContainer.Add);
|
||||
else
|
||||
storyboardContainer.Add(storyboard);
|
||||
}
|
||||
|
||||
private ScheduledDelegate onCompletionEvent;
|
||||
|
||||
private void onCompletion()
|
||||
{
|
||||
// Only show the completion screen if the player hasn't failed
|
||||
if (scoreProcessor.HasFailed || onCompletionEvent != null)
|
||||
return;
|
||||
|
||||
ValidForResume = false;
|
||||
|
||||
if (!AllowResults) return;
|
||||
|
||||
using (BeginDelayedSequence(1000))
|
||||
{
|
||||
onCompletionEvent = Schedule(delegate
|
||||
{
|
||||
if (!IsCurrentScreen) return;
|
||||
|
||||
var score = new Score
|
||||
{
|
||||
Beatmap = Beatmap.Value.BeatmapInfo,
|
||||
Ruleset = ruleset
|
||||
};
|
||||
scoreProcessor.PopulateScore(score);
|
||||
score.User = RulesetContainer.Replay?.User ?? api.LocalUser.Value;
|
||||
Push(new Results(score));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private bool onFail()
|
||||
{
|
||||
if (Beatmap.Value.Mods.Value.OfType<IApplicableFailOverride>().Any(m => !m.AllowFail))
|
||||
return false;
|
||||
|
||||
HasFailed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
|
||||
if (!loadedSuccessfully)
|
||||
return;
|
||||
|
||||
Content.Alpha = 0;
|
||||
Content
|
||||
.ScaleTo(0.7f)
|
||||
.ScaleTo(1, 750, Easing.OutQuint)
|
||||
.Delay(250)
|
||||
.FadeIn(250);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
sourceClock.Reset();
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
adjustableClock.ChangeSource(sourceClock);
|
||||
applyRateFromMods();
|
||||
|
||||
this.Delay(750).Schedule(() =>
|
||||
{
|
||||
Logger.Log("Client finnished loading", LoggingTarget.Network, LogLevel.Verbose);
|
||||
RulesetNetworkingClientHandler.GameLoaded();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void start()
|
||||
{
|
||||
adjustableClock.Start();
|
||||
}
|
||||
|
||||
protected override void OnSuspending(Screen next)
|
||||
{
|
||||
fadeOut();
|
||||
base.OnSuspending(next);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
fadeOut();
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
protected override void UpdateBackgroundElements()
|
||||
{
|
||||
if (!IsCurrentScreen) return;
|
||||
|
||||
base.UpdateBackgroundElements();
|
||||
|
||||
if (ShowStoryboard && storyboard == null)
|
||||
initializeStoryboard(true);
|
||||
|
||||
var beatmap = Beatmap.Value;
|
||||
var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable;
|
||||
|
||||
storyboardContainer?
|
||||
.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint)
|
||||
.FadeTo(storyboardVisible && BackgroundOpacity > 0 ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||
|
||||
if (storyboardVisible && beatmap.Storyboard.ReplacesBackground)
|
||||
Background?.FadeTo(0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void fadeOut()
|
||||
{
|
||||
const float fade_out_duration = 250;
|
||||
|
||||
RulesetContainer?.FadeOut(fade_out_duration);
|
||||
Content.FadeOut(fade_out_duration);
|
||||
|
||||
hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In);
|
||||
|
||||
Background?.FadeTo(1f, fade_out_duration);
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Key == Key.Escape)
|
||||
BackOut();
|
||||
|
||||
return base.OnKeyDown(state, args);
|
||||
}
|
||||
|
||||
public void BackOut()
|
||||
{
|
||||
RulesetNetworkingClientHandler.AbortGame();
|
||||
RulesetNetworkingClientHandler.OnAbort();
|
||||
}
|
||||
|
||||
protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Screens;
|
||||
using System;
|
||||
using osu.Framework.Screens;
|
||||
using System.Collections.Generic;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public abstract class RulesetLobbyScreen : OsuScreen
|
||||
{
|
||||
public abstract string RulesetName { get; }
|
||||
|
||||
public abstract RulesetMatchScreen MatchScreen { get; }
|
||||
|
||||
public RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
public readonly SettingsButton HostGameButton;
|
||||
public readonly SettingsButton DirectConnectButton;
|
||||
public readonly SettingsButton JoinGameButton;
|
||||
|
||||
public readonly Container NewGame;
|
||||
protected readonly TextBox HostIP;
|
||||
protected readonly TextBox HostPort;
|
||||
//protected readonly TextBox PublicIp;
|
||||
protected readonly TextBox LocalIp;
|
||||
|
||||
public readonly Container JoinIP;
|
||||
|
||||
public RulesetLobbyScreen()
|
||||
{
|
||||
AlwaysPresent = true;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
HostGameButton = new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Host Game",
|
||||
Action = HostGame
|
||||
},
|
||||
DirectConnectButton = new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Direct Connect",
|
||||
Action = DirectConnect
|
||||
},
|
||||
JoinGameButton = new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Join Game"
|
||||
},
|
||||
NewGame = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
Size = new Vector2(400, 300),
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Blue,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
HostIP = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "Host IP Address"
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
HostPort = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "25570"
|
||||
},
|
||||
/*
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 22),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
PublicIp = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 22),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "You're Public IP Address"
|
||||
},
|
||||
*/
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 44),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
LocalIp = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 44),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "You're Local IP Address"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
protected override void OnResuming(Screen last)
|
||||
{
|
||||
base.OnResuming(last);
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
}
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
protected virtual void HostGame()
|
||||
{
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
}
|
||||
Add(RulesetNetworkingClientHandler = new RulesetNetworkingClientHandler(ClientType.Host, LocalIp.Text, Int32.Parse(HostPort.Text)));
|
||||
|
||||
List<ClientInfo> list = new List<ClientInfo>();
|
||||
list.Add(RulesetNetworkingClientHandler.RulesetClientInfo);
|
||||
|
||||
JoinMatch(list);
|
||||
}
|
||||
|
||||
protected virtual void DirectConnect()
|
||||
{
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
}
|
||||
Add(RulesetNetworkingClientHandler = new RulesetNetworkingClientHandler(ClientType.Peer, HostIP.Text, Int32.Parse(HostPort.Text), LocalIp.Text));
|
||||
|
||||
RulesetNetworkingClientHandler.OnConnectedToHost += (p) => JoinMatch(p);
|
||||
}
|
||||
|
||||
protected virtual void JoinMatch(List<ClientInfo> clientInfos)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
MakeCurrent();
|
||||
Push(MatchScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Screens;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Pieces;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public abstract class RulesetMatchScreen : OsuScreen
|
||||
{
|
||||
public readonly RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
private readonly MatchPlayerList playerList;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
protected MatchTools MatchTools;
|
||||
|
||||
private readonly Chat chat;
|
||||
|
||||
public RulesetMatchScreen(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
RulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.35f,
|
||||
Text = "Leave",
|
||||
Action = () => Exit()
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Open Song Select",
|
||||
Action = () => openSongSelect()
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.35f,
|
||||
Text = "Start Match",
|
||||
Action = () => RulesetNetworkingClientHandler.StartLoadingGame()
|
||||
},
|
||||
playerList = new MatchPlayerList(RulesetNetworkingClientHandler),
|
||||
MatchTools = new MatchTools(),
|
||||
chat = new Chat(RulesetNetworkingClientHandler)
|
||||
};
|
||||
|
||||
RulesetNetworkingClientHandler.OnPacketReceive += (Packet packet) =>
|
||||
{
|
||||
if (packet is RulesetPacket rulesetPacket && rulesetPacket.OnlineBeatmapID != -1)
|
||||
foreach (BeatmapSetInfo beatmapSet in beatmaps.GetAllUsableBeatmapSets())
|
||||
if (beatmapSet.OnlineBeatmapSetID == rulesetPacket.OnlineBeatmapSetID)
|
||||
{
|
||||
foreach (BeatmapInfo beatmap in beatmapSet.Beatmaps)
|
||||
if (beatmap.OnlineBeatmapID == rulesetPacket.OnlineBeatmapID)
|
||||
{
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
||||
Beatmap.Value.Track.Start();
|
||||
MatchTools.MapChange(Beatmap);
|
||||
RulesetNetworkingClientHandler.OnMapChange?.Invoke(Beatmap);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
MatchTools.MapChange(rulesetPacket.OnlineBeatmapSetID);
|
||||
};
|
||||
|
||||
RulesetNetworkingClientHandler.OnMapChange += (beatmap) => MatchTools.MapChange(beatmap);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
playerList.Add(RulesetNetworkingClientHandler.RulesetClientInfo);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapManager beatmaps)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
MakeCurrent();
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.OnLoadGame = (i) => Load(i);
|
||||
}
|
||||
|
||||
protected override void OnResuming(Screen last)
|
||||
{
|
||||
base.OnResuming(last);
|
||||
MakeCurrent();
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
}
|
||||
|
||||
protected override void OnSuspending(Screen next)
|
||||
{
|
||||
base.OnSuspending(next);
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
RulesetNetworkingClientHandler.Disconnect();
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
protected virtual void Load(List<ClientInfo> playerList)
|
||||
{
|
||||
MakeCurrent();
|
||||
Push(new MultiPlayer(RulesetNetworkingClientHandler, playerList));
|
||||
}
|
||||
|
||||
private void openSongSelect()
|
||||
{
|
||||
MatchSongSelect songSelect = new MatchSongSelect(RulesetNetworkingClientHandler);
|
||||
MakeCurrent();
|
||||
Push(songSelect);
|
||||
songSelect.Action = () => RulesetNetworkingClientHandler.SetMap(songSelect.SelectedMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
//osu.Game.Screens.Symcol.SymcolMenu
|
||||
//Symcol.Rulesets.Core.SymcolSettingsSubsection
|
||||
#define SymcolMods
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Symcol;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public class RulesetMultiplayerSelection : OsuScreen
|
||||
{
|
||||
public static readonly FillFlowContainer<RulesetLobbyItem> LobbyItems = new FillFlowContainer<RulesetLobbyItem>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.85f,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
};
|
||||
|
||||
public RulesetMultiplayerSelection()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Add(LobbyItems);
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
foreach (RulesetLobbyItem item in LobbyItems)
|
||||
item.Action = () => Push(item.RulesetLobbyScreen);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
Remove(LobbyItems);
|
||||
|
||||
#if SymcolMods
|
||||
SymcolSettingsSubsection.RulesetMultiplayerSelection = new RulesetMultiplayerSelection();
|
||||
|
||||
SymcolMenu.RulesetMultiplayerScreen = SymcolSettingsSubsection.RulesetMultiplayerSelection;
|
||||
#endif
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class RulesetLobbyItem : ClickableContainer
|
||||
{
|
||||
public abstract Texture Icon { get; }
|
||||
|
||||
public abstract string RulesetName { get; }
|
||||
|
||||
public virtual Texture Background { get; }
|
||||
|
||||
public abstract RulesetLobbyScreen RulesetLobbyScreen { get; }
|
||||
|
||||
public RulesetLobbyItem()
|
||||
{
|
||||
CornerRadius = 20;
|
||||
Masking = true;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 100;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Texture = Background
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Size = new Vector2(Height),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Texture = Icon
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Text = RulesetName,
|
||||
TextSize = 60,
|
||||
Position = new Vector2(-20, 0)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
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("Symcol.Rulesets.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Symcol.Rulesets.Core")]
|
||||
[assembly: AssemblyCopyright("Copyright © Shawdooow 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("552b5940-c647-4060-aa4d-61baac415c72")]
|
||||
|
||||
// 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")]
|
||||
@@ -0,0 +1,97 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Skinning
|
||||
{
|
||||
public abstract class SkinElement : Container
|
||||
{
|
||||
private static string loadedSkin;
|
||||
|
||||
private static ResourceStore<byte[]> skinResources;
|
||||
private static TextureStore skinTextures;
|
||||
|
||||
/// <summary>
|
||||
/// Will attempt to get a skin element fron the skin, if no element is found return the default element
|
||||
/// </summary>
|
||||
/// <param name="stockTextures"></param>
|
||||
/// <param name="skin"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="storage"></param>
|
||||
/// <returns></returns>
|
||||
public static Texture GetSkinElement(TextureStore stockTextures, Bindable<string> skin, string fileName, Storage storage)
|
||||
{
|
||||
Texture texture = null;
|
||||
|
||||
string fileNameHd = fileName + "@2x";
|
||||
|
||||
Storage skinStorage = storage.GetStorageForDirectory("Skins\\" + skin);
|
||||
|
||||
if (skin.Value == "default")
|
||||
{
|
||||
texture = stockTextures.Get(fileName + ".png");
|
||||
|
||||
if (texture == null)
|
||||
texture = stockTextures.Get(fileNameHd + ".png");
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
if (loadedSkin != skin.ToString())
|
||||
{
|
||||
loadedSkin = skin.ToString();
|
||||
skinResources = new ResourceStore<byte[]>(new StorageBackedResourceStore(skinStorage));
|
||||
skinTextures = new TextureStore(new RawTextureLoaderStore(skinResources));
|
||||
}
|
||||
|
||||
if (skinStorage.Exists(fileNameHd + ".png"))
|
||||
texture = skinTextures.Get(fileNameHd + ".png");
|
||||
else if (skinStorage.Exists(fileName + ".png"))
|
||||
{
|
||||
texture = skinTextures.Get(fileName + ".png");
|
||||
texture.ScaleAdjust = 1f;
|
||||
}
|
||||
else
|
||||
texture = stockTextures.Get(fileNameHd + ".png");
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will attempt to get a skin element from the skin, if no element is found return null
|
||||
/// </summary>
|
||||
/// <param name="skin"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="storage"></param>
|
||||
/// <returns></returns>
|
||||
public static Texture GetElement(Bindable<string> skin, string fileName, Storage storage)
|
||||
{
|
||||
Texture texture = null;
|
||||
|
||||
string fileNameHd = fileName + "@2x";
|
||||
|
||||
Storage skinStorage = storage.GetStorageForDirectory("Skins\\" + skin);
|
||||
|
||||
if (loadedSkin != skin.ToString())
|
||||
{
|
||||
loadedSkin = skin.ToString();
|
||||
skinResources = new ResourceStore<byte[]>(new StorageBackedResourceStore(skinStorage));
|
||||
skinTextures = new TextureStore(new RawTextureLoaderStore(skinResources));
|
||||
}
|
||||
|
||||
if (skinStorage.Exists(fileNameHd + ".png"))
|
||||
texture = skinTextures.Get(fileNameHd + ".png");
|
||||
else if (skinStorage.Exists(fileName + ".png"))
|
||||
{
|
||||
texture = skinTextures.Get(fileName + ".png");
|
||||
texture.ScaleAdjust = 1f;
|
||||
}
|
||||
else
|
||||
texture = null;
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Skinning
|
||||
{
|
||||
public class SkinConfigReader<T> : IniConfigManager<T>
|
||||
where T : struct
|
||||
{
|
||||
protected override string Filename => @"skin.ini";
|
||||
|
||||
public SkinConfigReader(Storage storage) : base(storage) { }
|
||||
|
||||
protected override bool PerformSave() { return false; }
|
||||
}
|
||||
|
||||
//wildly incomplete
|
||||
public enum ClassicIniParameters
|
||||
{
|
||||
Name,
|
||||
Author,
|
||||
CursorRotate,
|
||||
CursorExpand,
|
||||
CursorCentre
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{552B5940-C647-4060-AA4D-61BAAC415C72}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Symcol.Rulesets.Core</RootNamespace>
|
||||
<AssemblyName>Symcol.Rulesets.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<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' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4" />
|
||||
<Reference Include="System" />
|
||||
<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="Containers\LinkText.cs" />
|
||||
<Compile Include="Containers\ProfileLink.cs" />
|
||||
<Compile Include="HitObjects\DrawableSymcolHitObject.cs" />
|
||||
<Compile Include="Multiplayer\Networking\ScorePacket.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\Chat.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\ChatMessage.cs" />
|
||||
<Compile Include="Multiplayer\Networking\ChatPacket.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MatchTools.cs" />
|
||||
<Compile Include="Multiplayer\Networking\RulesetClientInfo.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MatchPlayer.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MatchPlayerList.cs" />
|
||||
<Compile Include="Multiplayer\Options\MultiplayerDropdownEnumOption.cs" />
|
||||
<Compile Include="Multiplayer\Options\MultiplayerOption.cs" />
|
||||
<Compile Include="Multiplayer\Options\MultiplayerToggleOption.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MultiplayerScoreboard.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MultiplayerScoreboardItem.cs" />
|
||||
<Compile Include="Multiplayer\Screens\MatchSongSelect.cs" />
|
||||
<Compile Include="Multiplayer\Screens\MultiPlayer.cs" />
|
||||
<Compile Include="Multiplayer\Screens\RulesetLobbyScreen.cs" />
|
||||
<Compile Include="Multiplayer\Screens\RulesetMatchScreen.cs" />
|
||||
<Compile Include="Multiplayer\Screens\RulesetMultiplayerSelection.cs" />
|
||||
<Compile Include="Multiplayer\Networking\RulesetNetworkingClientHandler.cs" />
|
||||
<Compile Include="Multiplayer\Networking\RulesetPacket.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Skinning\SkinElement.cs" />
|
||||
<Compile Include="Skinning\SkinIniReader.cs" />
|
||||
<Compile Include="SymcolConfigManager.cs" />
|
||||
<Compile Include="SymcolPlayfield.cs" />
|
||||
<Compile Include="SymcolSettingsSubsection.cs" />
|
||||
<Compile Include="SymcolInputManager.cs" />
|
||||
<Compile Include="VectorVideos\VectorVideo.cs" />
|
||||
<Compile Include="Wiki\WikiOptionEnumExplanation.cs" />
|
||||
<Compile Include="Wiki\WikiParagraph.cs" />
|
||||
<Compile Include="Wiki\WikiSubSectionHeader.cs" />
|
||||
<Compile Include="Wiki\WikiOverlay.cs" />
|
||||
<Compile Include="Wiki\WikiHeader.cs" />
|
||||
<Compile Include="Wiki\WikiSection.cs" />
|
||||
<Compile Include="Wiki\WikiSubSectionLinkHeader.cs" />
|
||||
</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\osu.Game.csproj">
|
||||
<Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
|
||||
<Name>osu.Game</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Symcol.Core\Symcol.Core.csproj">
|
||||
<Project>{F34AC16C-E590-4D70-A069-A748326852BF}</Project>
|
||||
<Name>Symcol.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,22 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public class SymcolConfigManager : IniConfigManager<SymcolSetting>
|
||||
{
|
||||
protected override string Filename => "symcol.ini";
|
||||
|
||||
public SymcolConfigManager(Storage storage) : base(storage) { }
|
||||
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
Set(SymcolSetting.PlayerColor, "#ffffff");
|
||||
}
|
||||
}
|
||||
|
||||
public enum SymcolSetting
|
||||
{
|
||||
PlayerColor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using Symcol.Rulesets.Core.VectorVideos;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public class SymcolInputManager<T> : RulesetInputManager<T>
|
||||
where T : struct
|
||||
{
|
||||
protected virtual bool VectorVideo => false;
|
||||
|
||||
public SymcolInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique)
|
||||
{
|
||||
Child = new VectorVideo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public class SymcolPlayfield : Playfield
|
||||
{
|
||||
public static RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
public SymcolPlayfield(Vector2 size) : base(size.X)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//osu.Game.Screens.Symcol.SymcolMenu
|
||||
//Symcol.Rulesets.Core.Multiplayer.Screens.RulesetMultiplayerSelection
|
||||
#define SymcolMods
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using Symcol.Rulesets.Core.Wiki;
|
||||
using osu.Game.Screens.Symcol;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Screens;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Logging;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public abstract class SymcolSettingsSubsection : SettingsSubsection
|
||||
{
|
||||
public virtual WikiOverlay Wiki => null;
|
||||
|
||||
public virtual RulesetLobbyItem RulesetLobbyItem => null;
|
||||
|
||||
#if SymcolMods
|
||||
public static RulesetMultiplayerSelection RulesetMultiplayerSelection;
|
||||
#endif
|
||||
|
||||
public static SymcolConfigManager SymcolConfigManager;
|
||||
|
||||
private OsuGame osu;
|
||||
|
||||
public SymcolSettingsSubsection()
|
||||
{
|
||||
|
||||
#if SymcolMods
|
||||
if (RulesetLobbyItem != null)
|
||||
RulesetMultiplayerSelection.LobbyItems.Add(RulesetLobbyItem);
|
||||
|
||||
if (RulesetMultiplayerSelection == null)
|
||||
RulesetMultiplayerSelection = new RulesetMultiplayerSelection();
|
||||
|
||||
SymcolMenu.RulesetMultiplayerScreen = RulesetMultiplayerSelection;
|
||||
#endif
|
||||
#if !SymcolMods
|
||||
Logger.Log("osu.Game mods not installed! Online Multiplayer will not be avalible without them. . .", LoggingTarget.Information, LogLevel.Important);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGame osu, Storage storage)
|
||||
{
|
||||
this.osu = osu;
|
||||
|
||||
if (SymcolConfigManager == null)
|
||||
SymcolConfigManager = new SymcolConfigManager(storage);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (Wiki != null)
|
||||
osu.Add(Wiki);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.VectorVideos
|
||||
{
|
||||
public class VectorVideo : BeatSyncedContainer
|
||||
{
|
||||
public const string FILE_NAME = "VectorVideo.symcol";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(Storage storage)
|
||||
{
|
||||
}
|
||||
|
||||
protected void LoadContent(string args)
|
||||
{
|
||||
string[] parameters = args.Split(',');
|
||||
|
||||
ObjectType objectType = ObjectType.LogoVisualizer;
|
||||
Anchor anchor = Anchor.Centre;
|
||||
Anchor origin = Anchor.Centre;
|
||||
|
||||
bool checkingType = false;
|
||||
|
||||
foreach (string parameter in parameters)
|
||||
{
|
||||
string[] subParameters = parameter.Split('=');
|
||||
|
||||
foreach (string subParameter in subParameters)
|
||||
{
|
||||
if (subParameter == "Type")
|
||||
checkingType = true;
|
||||
|
||||
if (checkingType)
|
||||
switch (subParameter)
|
||||
{
|
||||
case "LogoVisualizer":
|
||||
objectType = ObjectType.LogoVisualizer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLogoVisualizer()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public enum ObjectType
|
||||
{
|
||||
LogoVisualizer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using OpenTK.Graphics;
|
||||
using Symcol.Rulesets.Core.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public abstract class WikiHeader : Container
|
||||
{
|
||||
protected abstract Texture RulesetIcon { get; }
|
||||
|
||||
protected abstract string RulesetName { get; }
|
||||
|
||||
protected abstract string RulesetDescription { get; }
|
||||
|
||||
protected virtual string RulesetUrl => $@"https://osu.ppy.sh/home";
|
||||
|
||||
protected virtual User Creator => null;
|
||||
|
||||
protected virtual User Maintainer => null;
|
||||
|
||||
protected virtual string DiscordInvite => $@"https://discord.gg/ppy";
|
||||
|
||||
protected virtual Texture HeaderBackground => null;
|
||||
|
||||
private const float description_height = 150;
|
||||
private const float description_width = 220;
|
||||
private const float icon_size = 200;
|
||||
private const float header_margin = 50;
|
||||
private const float rulesetname_height = 60;
|
||||
|
||||
public WikiHeader()
|
||||
{
|
||||
Masking = true;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = header_margin + icon_size + rulesetname_height;
|
||||
|
||||
|
||||
var user = Creator;
|
||||
bool maintainer = false;
|
||||
string userTitle = "Creator";
|
||||
if (Creator == null)
|
||||
{
|
||||
user = Maintainer;
|
||||
maintainer = true;
|
||||
userTitle = "Maintainer";
|
||||
}
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Texture = HeaderBackground
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Size = new Vector2(icon_size),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Texture = RulesetIcon
|
||||
},
|
||||
new LinkText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, icon_size),
|
||||
Text = RulesetName,
|
||||
Url = RulesetUrl,
|
||||
Font = @"Exo2.0-RegularItalic",
|
||||
TextSize = rulesetname_height
|
||||
},
|
||||
new ProfileLink(user, maintainer)
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, icon_size + rulesetname_height),
|
||||
},
|
||||
new LinkText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, icon_size + rulesetname_height + 20),
|
||||
Text = userTitle + "'s Discord server",
|
||||
Url = DiscordInvite,
|
||||
Font = @"Exo2.0-RegularItalic",
|
||||
TextSize = 16
|
||||
},
|
||||
new OsuTextFlowContainer(t => { t.TextSize = 20; })
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Size = new Vector2(description_width, description_height),
|
||||
Text = RulesetDescription
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiOptionEnumExplanation<T> : Container
|
||||
where T : struct
|
||||
{
|
||||
public OsuTextFlowContainer Description;
|
||||
|
||||
public WikiOptionEnumExplanation(Bindable<T> bindable)
|
||||
{
|
||||
OsuColour osu = new OsuColour();
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Masking = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = osu.Yellow,
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Size = new Vector2(10, 0.98f),
|
||||
CornerRadius = 5,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Position = new Vector2(-10, 0),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.45f,
|
||||
|
||||
Child = new SettingsEnumDropdown<T>
|
||||
{
|
||||
Bindable = bindable
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.45f,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
AutoSizeDuration = 100,
|
||||
AutoSizeEasing = Easing.OutQuint,
|
||||
|
||||
Child = Description = new OsuTextFlowContainer(t => { t.TextSize = 20; })
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using System.Linq;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public abstract class WikiOverlay : WaveOverlayContainer
|
||||
{
|
||||
protected abstract WikiHeader Header { get; }
|
||||
protected abstract WikiSection[] Sections { get; }
|
||||
|
||||
private WikiSection lastSection;
|
||||
private SectionsContainer<WikiSection> sectionsContainer;
|
||||
private WikiTabControl tabs;
|
||||
|
||||
public const float CONTENT_X_MARGIN = 100;
|
||||
|
||||
public WikiOverlay()
|
||||
{
|
||||
FirstWaveColour = OsuColour.Gray(0.4f);
|
||||
SecondWaveColour = OsuColour.Gray(0.3f);
|
||||
ThirdWaveColour = OsuColour.Gray(0.2f);
|
||||
FourthWaveColour = OsuColour.Gray(0.1f);
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativePositionAxes = Axes.Both;
|
||||
Width = 0.85f;
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
Masking = true;
|
||||
AlwaysPresent = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 10
|
||||
};
|
||||
|
||||
tabs = new WikiTabControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Height = 30
|
||||
};
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(0.2f)
|
||||
});
|
||||
|
||||
Add(sectionsContainer = new SectionsContainer<WikiSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ExpandableHeader = Header,
|
||||
FixedHeader = tabs,
|
||||
HeaderBackground = new Box
|
||||
{
|
||||
Colour = OsuColour.Gray(34),
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
});
|
||||
|
||||
sectionsContainer.SelectedSection.ValueChanged += s =>
|
||||
{
|
||||
if (lastSection != s)
|
||||
{
|
||||
lastSection = s;
|
||||
tabs.Current.Value = lastSection;
|
||||
}
|
||||
};
|
||||
|
||||
tabs.Current.ValueChanged += s =>
|
||||
{
|
||||
if (lastSection == null)
|
||||
{
|
||||
lastSection = sectionsContainer.Children.FirstOrDefault();
|
||||
if (lastSection != null)
|
||||
tabs.Current.Value = lastSection;
|
||||
return;
|
||||
}
|
||||
if (lastSection != s)
|
||||
{
|
||||
lastSection = s;
|
||||
sectionsContainer.ScrollTo(lastSection);
|
||||
}
|
||||
};
|
||||
|
||||
foreach (WikiSection sec in Sections)
|
||||
{
|
||||
if (sec != null)
|
||||
{
|
||||
sectionsContainer.Add(sec);
|
||||
tabs.AddItem(sec);
|
||||
}
|
||||
}
|
||||
|
||||
sectionsContainer.ScrollToTop();
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
base.PopIn();
|
||||
FadeEdgeEffectTo(0.5f, APPEAR_DURATION, Easing.In);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out);
|
||||
}
|
||||
|
||||
private class WikiTabControl : PageTabControl<WikiSection>
|
||||
{
|
||||
public WikiTabControl()
|
||||
{
|
||||
TabContainer.RelativeSizeAxes &= ~Axes.X;
|
||||
TabContainer.AutoSizeAxes |= Axes.X;
|
||||
TabContainer.Anchor |= Anchor.x1;
|
||||
TabContainer.Origin |= Anchor.x1;
|
||||
}
|
||||
|
||||
protected override TabItem<WikiSection> CreateTabItem(WikiSection value) => new WikiTabItem(value);
|
||||
|
||||
protected override Dropdown<WikiSection> CreateDropdown() => null;
|
||||
|
||||
private class WikiTabItem : PageTabItem
|
||||
{
|
||||
public WikiTabItem(WikiSection value) : base(value)
|
||||
{
|
||||
Text.Text = value.Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiParagraph : Container
|
||||
{
|
||||
public WikiParagraph(string text, float textsize = 20)
|
||||
{
|
||||
paragraphNoMarkdown(text, textsize);
|
||||
}
|
||||
|
||||
public WikiParagraph(string text, bool markdown)
|
||||
{
|
||||
if (!markdown)
|
||||
paragraphNoMarkdown(text, 20);
|
||||
else
|
||||
paragraphMarkdown(text, 20);
|
||||
}
|
||||
public WikiParagraph(string text, float textsize, bool markdown)
|
||||
{
|
||||
if (!markdown)
|
||||
paragraphNoMarkdown(text, textsize);
|
||||
else
|
||||
paragraphMarkdown(text, textsize);
|
||||
}
|
||||
|
||||
private void paragraphNoMarkdown(string text, float textsize)
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Child = new OsuTextFlowContainer(t => { t.TextSize = textsize; })
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = text
|
||||
};
|
||||
}
|
||||
|
||||
private void paragraphMarkdown(string text, float textsize)
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Child = new OsuTextFlowContainer(t => { t.TextSize = textsize; })
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = text
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public abstract class WikiSection : FillFlowContainer
|
||||
{
|
||||
public abstract string Title { get; }
|
||||
|
||||
private readonly FillFlowContainer content;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected WikiSection()
|
||||
{
|
||||
OsuColour osu = new OsuColour();
|
||||
Direction = FillDirection.Vertical;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Colour = osu.Yellow,
|
||||
Text = Title,
|
||||
TextSize = 32,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Horizontal = WikiOverlay.CONTENT_X_MARGIN,
|
||||
Vertical = 12
|
||||
}
|
||||
},
|
||||
content = new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Horizontal = WikiOverlay.CONTENT_X_MARGIN,
|
||||
Bottom = 20
|
||||
}
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1,
|
||||
Colour = OsuColour.Gray(34),
|
||||
EdgeSmoothness = new Vector2(1)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiSubSectionHeader : OsuSpriteText
|
||||
{
|
||||
public WikiSubSectionHeader(string text)
|
||||
{
|
||||
OsuColour osu = new OsuColour();
|
||||
Colour = osu.Pink;
|
||||
Text = text;
|
||||
TextSize = 24;
|
||||
Font = @"Exo2.0-BoldItalic";
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Vertical = 10
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user